blob: 44eca776122d48120eb0d5ff72c85cf7fc292938 [file] [log] [blame]
The Android Open Source Project10e23ee2009-03-03 19:30:30 -08001/*
2 * Copyright 2008, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Binary implementation of the original opcontrol script due to missing tools
19 * like awk, test, etc.
20 */
21
22#include <unistd.h>
23#include <getopt.h>
24#include <stdio.h>
25#include <stdlib.h>
Jean-Baptiste Querud850f372010-05-03 15:16:06 -070026#include <string.h>
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080027#include <errno.h>
28#include <fcntl.h>
29#include <signal.h>
Jeff Brown87866d92011-02-02 13:27:17 -080030#include <dirent.h>
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080031#include <sys/stat.h>
Jeff Brown87866d92011-02-02 13:27:17 -080032#include <sys/types.h>
33#include <sys/wait.h>
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080034
35#include "op_config.h"
36
Bruce Beare751a4432010-03-04 10:30:51 -080037#define verbose(fmt...) if (verbose_print) printf(fmt)
The Android Open Source Project10e23ee2009-03-03 19:30:30 -080038
Paul Lind73f45fe2013-03-04 17:10:49 -080039struct event_info {
40 int id;
41 int counters;
42 int um;
43 const char *name;
44 const char *explanation;
45};
46
47#define CTR(n) (1<<(n))
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070048
Bruce Beare751a4432010-03-04 10:30:51 -080049#if defined(__i386__) || defined(__x86_64__)
Paul Lind73f45fe2013-03-04 17:10:49 -080050struct event_info event_info_arch_perfmon[] = {
51 #include "../events/i386/arch_perfmon/events.h"
52};
53
Bruce Beare751a4432010-03-04 10:30:51 -080054#define MAX_EVENTS 2
55int min_count[MAX_EVENTS] = {60000, 100000};
Paul Lind73f45fe2013-03-04 17:10:49 -080056
57const char *default_event = "CPU_CLK_UNHALTED";
58#endif
59
60#if defined(__arm__)
61#if !defined(WITH_ARM_V7_A)
62struct event_info event_info_armv6[] = {
63 #include "../events/arm/armv6/events.h"
64};
65
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070066#define MAX_EVENTS 3
Ben Cheng14345072009-09-16 11:31:39 -070067int min_count[MAX_EVENTS] = {150000, 200000, 250000};
Paul Lind73f45fe2013-03-04 17:10:49 -080068
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070069#else
Paul Lind73f45fe2013-03-04 17:10:49 -080070struct event_info event_info_armv7[] = {
71 #include "../events/arm/armv7/events.h"
72};
73
Ben Cheng14345072009-09-16 11:31:39 -070074#define MAX_EVENTS 5
Ben Chengafec5b92010-02-22 15:33:08 -080075int min_count[MAX_EVENTS] = {150000, 20000, 25000, 30000, 35000};
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070076#endif
77
Paul Lind73f45fe2013-03-04 17:10:49 -080078const char *default_event = "CPU_CYCLES";
79#endif
80
81#if defined(__mips__)
82struct event_info event_info_24K[] = {
83 #include "../events/mips/24K/events.h"
84};
85struct event_info event_info_34K[] = {
86 #include "../events/mips/34K/events.h"
87};
88struct event_info event_info_74K[] = {
89 #include "../events/mips/74K/events.h"
90};
91struct event_info event_info_1004K[] = {
92 #include "../events/mips/1004K/events.h"
93};
94
95#define MAX_EVENTS 4
96int min_count[MAX_EVENTS] = {150000, 20000, 25000, 30000};
97
98const char *default_event = "CYCLES";
99#endif /* defined(__mips__) */
100
101#define ARRAYSZ(x) (sizeof(x)/sizeof((x)[0]))
102
103struct cpuevents {
104 const char *cpu;
105 struct event_info *event_info;
106 unsigned int nevents;
107} cpuevents[] = {
108#if defined(__i386__) || defined(__x86_64__)
109 {"i386/arch_perfmon", event_info_arch_perfmon, ARRAYSZ(event_info_arch_perfmon)},
110#endif /* defined(__i386__) || defined(__x86_64__) */
111#if defined(__arm__)
112#if !defined(WITH_ARM_V7_A)
113 {"arm/armv6", event_info_armv6, ARRAYSZ(event_info_armv6)},
114#else
115 {"arm/armv7", event_info_armv7, ARRAYSZ(event_info_armv7)},
116#endif
117#endif /* defined(__arm__) */
118#if defined(__mips__)
119 {"mips/24K", event_info_24K, ARRAYSZ(event_info_24K)},
120 {"mips/34K", event_info_34K, ARRAYSZ(event_info_34K)},
121 {"mips/74K", event_info_74K, ARRAYSZ(event_info_74K)},
122 {"mips/1004K", event_info_1004K, ARRAYSZ(event_info_1004K)},
123#endif /* defined(__mips__) */
124};
125
126struct cpuevents *cpuevent;
127#define event_info cpuevent->event_info
128#define NEVENTS cpuevent->nevents
129
Bruce Beare751a4432010-03-04 10:30:51 -0800130int verbose_print;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800131int list_events;
132int show_usage;
133int setup;
134int quick;
Ben Chenga9404b82010-09-03 16:46:45 -0700135int timer;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800136int num_events;
137int start;
138int stop;
139int reset;
140
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700141int selected_events[MAX_EVENTS];
142int selected_counts[MAX_EVENTS];
Paul Lind73f45fe2013-03-04 17:10:49 -0800143int max_events;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800144
Bruce Beare751a4432010-03-04 10:30:51 -0800145char callgraph[8];
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800146char kernel_range[512];
147char vmlinux[512];
148
149struct option long_options[] = {
150 {"help", 0, &show_usage, 1},
151 {"list-events", 0, &list_events, 1},
152 {"reset", 0, &reset, 1},
153 {"setup", 0, &setup, 1},
154 {"quick", 0, &quick, 1},
Ben Chenga9404b82010-09-03 16:46:45 -0700155 {"timer", 0, &timer, 1},
Bruce Beare751a4432010-03-04 10:30:51 -0800156 {"callgraph", 1, 0, 'c'},
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800157 {"event", 1, 0, 'e'},
158 {"vmlinux", 1, 0, 'v'},
159 {"kernel-range", 1, 0, 'r'},
160 {"start", 0, &start, 1},
161 {"stop", 0, &stop, 1},
Bruce Beare751a4432010-03-04 10:30:51 -0800162 {"dump", 0, 0, 'd'},
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800163 {"shutdown", 0, 0, 'h'},
164 {"status", 0, 0, 't'},
Bruce Beare751a4432010-03-04 10:30:51 -0800165 {"verbose", 0, 0, 'V'},
Jeff Brown87866d92011-02-02 13:27:17 -0800166 {"verbose-log", 1, 0, 'l'},
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800167 {0, 0, 0, 0},
168};
169
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800170
Ben Cheng14345072009-09-16 11:31:39 -0700171void usage()
172{
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800173 printf("\nopcontrol: usage:\n"
174 " --list-events list event types\n"
175 " --help this message\n"
Bruce Beare751a4432010-03-04 10:30:51 -0800176 " --verbose show extra status\n"
Jeff Brown87866d92011-02-02 13:27:17 -0800177 " --verbose-log=lvl set daemon logging verbosity during setup\n"
178 " levels are: all,sfile,arcs,samples,module,misc\n"
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800179 " --setup setup directories\n"
Bruce Beare751a4432010-03-04 10:30:51 -0800180#if defined(__i386__) || defined(__x86_64__)
181 " --quick setup and select CPU_CLK_UNHALTED:60000\n"
Paul Lind73f45fe2013-03-04 17:10:49 -0800182#elif defined(__arm__)
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800183 " --quick setup and select CPU_CYCLES:150000\n"
Paul Lind73f45fe2013-03-04 17:10:49 -0800184#elif defined(__mips__)
185 " --quick setup and select CYCLES:150000\n"
Bruce Beare751a4432010-03-04 10:30:51 -0800186#endif
Ben Chenga9404b82010-09-03 16:46:45 -0700187 " --timer timer-based profiling\n"
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800188 " --status show configuration\n"
189 " --start start data collection\n"
190 " --stop stop data collection\n"
191 " --reset clears out data from current session\n"
Paul Lind73f45fe2013-03-04 17:10:49 -0800192 " --shutdown kill the oprofile daemon\n"
Bruce Beare751a4432010-03-04 10:30:51 -0800193 " --callgraph=depth callgraph depth\n"
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800194 " --event=eventspec\n"
195 " Choose an event. May be specified multiple times.\n"
196 " eventspec is in the form of name[:count], where :\n"
197 " name: event name, see \"opcontrol --list-events\"\n"
198 " count: reset counter value\n"
199 " --vmlinux=file vmlinux kernel image\n"
200 " --kernel-range=start,end\n"
201 " kernel range vma address in hexadecimal\n"
202 );
203}
204
Paul Lind73f45fe2013-03-04 17:10:49 -0800205int setup_device(void)
206{
207 if (mkdir(OP_DRIVER_BASE, 0755)) {
208 if (errno != EEXIST) {
209 fprintf(stderr, "Cannot create directory "OP_DRIVER_BASE": %s\n",
210 strerror(errno));
211 return -1;
212 }
213 }
214
215 if (access(OP_DRIVER_BASE"/stats", F_OK)) {
216 if (system("mount -t oprofilefs nodev "OP_DRIVER_BASE)) {
217 return -1;
218 }
219 }
220
221 /* Selecting the event information by cpu_type has only been tested on MIPS */
222#if defined(__mips__)
223 /* Use cpu_type to select the events */
224 int fd = open(OP_DRIVER_BASE "/cpu_type", O_RDONLY);
225 if (fd < 0) {
226 fprintf(stderr, OP_DRIVER_BASE "/cpu_type: %s\n",
227 strerror(errno));
228 return -1;
229 }
230
231 char buf[512];
232 int n = read(fd, buf, sizeof(buf)-1);
233 close(fd);
234 if (n < 0) {
235 fprintf(stderr, OP_DRIVER_BASE "/cpu_type: %s\n",
236 strerror(errno));
237 return -1;
238 }
239 buf[n] = '\0';
240 for (unsigned int i = 0; i < ARRAYSZ(cpuevents); i++) {
241 if (strcmp(buf, cpuevents[i].cpu) == 0) {
242 cpuevent = &cpuevents[i];
243 }
244 }
245 if (cpuevent == NULL) {
246 fprintf(stderr, "Unrecognised CPU type %s\n", buf);
247 return -1;
248 }
249 for (max_events = 0; max_events < MAX_EVENTS; max_events++) {
250 snprintf(buf, sizeof(buf), OP_DRIVER_BASE"/%d", max_events);
251 if (access(buf, F_OK) < 0)
252 break;
253 }
254#else
255 max_events = MAX_EVENTS;
256 cpuevent = &cpuevents[0];
257#endif
258 return 0;
259}
260
Ben Cheng14345072009-09-16 11:31:39 -0700261void setup_session_dir()
262{
Paul Lind73f45fe2013-03-04 17:10:49 -0800263 if (access(OP_DATA_DIR, F_OK) == 0)
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800264 system("rm -r "OP_DATA_DIR);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800265
Mike Playled0950102010-07-09 17:02:22 +0100266 if (mkdir(OP_DATA_DIR, 0755)) {
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800267 fprintf(stderr, "Cannot create directory \"%s\": %s\n",
268 OP_DATA_DIR, strerror(errno));
269 }
Mike Playled0950102010-07-09 17:02:22 +0100270 if (mkdir(OP_DATA_DIR"/samples", 0755)) {
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800271 fprintf(stderr, "Cannot create directory \"%s\": %s\n",
272 OP_DATA_DIR"/samples", strerror(errno));
273 }
274}
275
Ben Cheng529d8682012-01-04 14:35:36 -0800276int read_num(const char* file)
277{
278 char buffer[256];
279 int fd = open(file, O_RDONLY);
280 if (fd<0) return -1;
281 int rd = read(fd, buffer, sizeof(buffer)-1);
282 buffer[rd] = 0;
283 close(fd);
284 return atoi(buffer);
285}
286
Ben Cheng14345072009-09-16 11:31:39 -0700287int do_setup()
288{
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800289 char dir[1024];
290
Ben Cheng529d8682012-01-04 14:35:36 -0800291 /*
292 * Kill the old daemon so that setup can be done more than once to achieve
293 * the same effect as reset.
294 */
295 int num = read_num(OP_DATA_DIR"/lock");
296 if (num >= 0) {
297 printf("Terminating the old daemon...\n");
298 kill(num, SIGTERM);
299 sleep(5);
300 }
301
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800302 setup_session_dir();
303
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800304 return 0;
305}
306
Paul Lind73f45fe2013-03-04 17:10:49 -0800307void stringify_counters(char *ctr_string, int ctr_mask)
308{
309 int i, n, len;
310 char *p = ctr_string;
311
312 *p = '\0';
313 for (i=0; i<32; ++i) {
314 if (ctr_mask & (1<<i)) {
315 p += sprintf(p, "%d,", i);
316 }
317 }
318 if (p != ctr_string) {
319 *(p-1) = '\0'; /* erase the final comma */
320 }
321}
322
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800323void do_list_events()
324{
325 unsigned int i;
Paul Lind73f45fe2013-03-04 17:10:49 -0800326 char ctrs[32*3+1];
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800327
Paul Lind73f45fe2013-03-04 17:10:49 -0800328 printf("%-12s | %-30s: %s\n", "counter", "name", "meaning");
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800329 printf("----------------------------------------"
330 "--------------------------------------\n");
Paul Lind73f45fe2013-03-04 17:10:49 -0800331 for (i = 0; i < NEVENTS; i++) {
332 stringify_counters(ctrs, event_info[i].counters);
333 printf("%-12s | %-30s: %s\n", ctrs, event_info[i].name, event_info[i].explanation);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800334 }
335}
336
Ben Cheng14345072009-09-16 11:31:39 -0700337int find_event_idx_from_name(const char *name)
338{
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800339 unsigned int i;
340
Paul Lind73f45fe2013-03-04 17:10:49 -0800341 for (i = 0; i < NEVENTS; i++) {
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800342 if (!strcmp(name, event_info[i].name)) {
343 return i;
344 }
345 }
346 return -1;
347}
348
Paul Lind73f45fe2013-03-04 17:10:49 -0800349const char * find_event_name_from_id(int id, int mask)
Ben Cheng14345072009-09-16 11:31:39 -0700350{
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800351 unsigned int i;
352
Paul Lind73f45fe2013-03-04 17:10:49 -0800353 for (i = 0; i < NEVENTS; i++) {
354 if (event_info[i].id == id && (event_info[i].counters == 0 || (event_info[i].counters & mask))) {
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800355 return event_info[i].name;
356 }
357 }
Paul Lind73f45fe2013-03-04 17:10:49 -0800358 return "Undefined Event";
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800359}
360
Ben Cheng14345072009-09-16 11:31:39 -0700361int process_event(const char *event_spec)
362{
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800363 char event_name[512];
364 char count_name[512];
365 unsigned int i;
Ben Cheng14345072009-09-16 11:31:39 -0700366 int event_idx;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800367 int count_val;
368
369 strncpy(event_name, event_spec, 512);
370 count_name[0] = 0;
371
372 /* First, check if the name is followed by ":" */
373 for (i = 0; i < strlen(event_name); i++) {
374 if (event_name[i] == 0) {
375 break;
376 }
377 if (event_name[i] == ':') {
378 strncpy(count_name, event_name+i+1, 512);
379 event_name[i] = 0;
380 break;
381 }
382 }
Ben Cheng14345072009-09-16 11:31:39 -0700383 event_idx = find_event_idx_from_name(event_name);
384 if (event_idx == -1) {
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800385 fprintf(stderr, "Unknown event name: %s\n", event_name);
386 return -1;
387 }
388
Paul Lind73f45fe2013-03-04 17:10:49 -0800389 /*
390 * check that the named event is valid for this event counter
391 * 'num_events' represents the cpu internal counter number
392 */
393 verbose("idx: %d, name: %s, mask: %02x, ctr#: %d\n",
394 event_idx, event_info[event_idx].name,
395 event_info[event_idx].counters, num_events);
396 if (event_info[event_idx].counters != 0 &&
397 (event_info[event_idx].counters & CTR(num_events)) == 0) {
398 fprintf(stderr, "Bad event name: %s for counter %d, see --list\n",
399 event_name, num_events);
400 return -1;
401 }
402
Jeff Brown87866d92011-02-02 13:27:17 -0800403 /* Use default count */
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800404 if (count_name[0] == 0) {
405 count_val = min_count[0];
406 } else {
407 count_val = atoi(count_name);
408 }
409
Ben Cheng14345072009-09-16 11:31:39 -0700410 selected_events[num_events] = event_idx;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800411 selected_counts[num_events++] = count_val;
Ben Cheng14345072009-09-16 11:31:39 -0700412 verbose("event_id is %d\n", event_info[event_idx].id);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800413 verbose("count_val is %d\n", count_val);
414 return 0;
415}
416
417int echo_dev(const char* str, int val, const char* file, int counter)
418{
419 char fullname[512];
420 char content[128];
421 int fd;
422
423 if (counter >= 0) {
424 snprintf(fullname, 512, OP_DRIVER_BASE"/%d/%s", counter, file);
425 }
426 else {
427 snprintf(fullname, 512, OP_DRIVER_BASE"/%s", file);
428 }
429 fd = open(fullname, O_WRONLY);
430 if (fd<0) {
431 fprintf(stderr, "Cannot open %s: %s\n", fullname, strerror(errno));
432 return fd;
433 }
434 if (str == 0) {
435 sprintf(content, "%d", val);
436 }
437 else {
438 strncpy(content, str, 128);
439 }
440 verbose("Configure %s (%s)\n", fullname, content);
441 write(fd, content, strlen(content));
442 close(fd);
443 return 0;
444}
445
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800446void do_status()
447{
448 int num;
449 char fullname[512];
450 int i;
451
452 printf("Driver directory: %s\n", OP_DRIVER_BASE);
453 printf("Session directory: %s\n", OP_DATA_DIR);
Paul Lind73f45fe2013-03-04 17:10:49 -0800454 for (i = 0; i < max_events; i++) {
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800455 sprintf(fullname, OP_DRIVER_BASE"/%d/enabled", i);
456 num = read_num(fullname);
457 if (num > 0) {
458 printf("Counter %d:\n", i);
459
460 /* event name */
461 sprintf(fullname, OP_DRIVER_BASE"/%d/event", i);
462 num = read_num(fullname);
Paul Lind73f45fe2013-03-04 17:10:49 -0800463 printf(" name: %s\n", find_event_name_from_id(num, CTR(i)));
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800464
465 /* profile interval */
466 sprintf(fullname, OP_DRIVER_BASE"/%d/count", i);
467 num = read_num(fullname);
468 printf(" count: %d\n", num);
469 }
470 else {
471 printf("Counter %d disabled\n", i);
472 }
473 }
474
475 num = read_num(OP_DATA_DIR"/lock");
476 if (num >= 0) {
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800477 /* Still needs to check if this lock is left-over */
478 sprintf(fullname, "/proc/%d", num);
Paul Lind73f45fe2013-03-04 17:10:49 -0800479 if (access(fullname, R_OK) != 0) {
Ben Cheng529d8682012-01-04 14:35:36 -0800480 printf("OProfile daemon exited prematurely - redo setup"
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800481 " before you continue\n");
482 return;
483 }
484 else {
Jeff Brown87866d92011-02-02 13:27:17 -0800485
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800486 printf("oprofiled pid: %d\n", num);
487 num = read_num(OP_DRIVER_BASE"/enable");
Jeff Brown87866d92011-02-02 13:27:17 -0800488
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800489 printf("profiler is%s running\n", num == 0 ? " not" : "");
Jeff Brown87866d92011-02-02 13:27:17 -0800490
491 DIR* dir = opendir(OP_DRIVER_BASE"/stats");
492 if (dir) {
493 for (struct dirent* dirent; !!(dirent = readdir(dir));) {
494 if (strlen(dirent->d_name) >= 4 && memcmp(dirent->d_name, "cpu", 3) == 0) {
495 char cpupath[256];
496 strcpy(cpupath, OP_DRIVER_BASE"/stats/");
497 strcat(cpupath, dirent->d_name);
498
499 strcpy(fullname, cpupath);
500 strcat(fullname, "/sample_received");
501 num = read_num(fullname);
502 printf(" %s %9u samples received\n", dirent->d_name, num);
503
504 strcpy(fullname, cpupath);
505 strcat(fullname, "/sample_lost_overflow");
506 num = read_num(fullname);
507 printf(" %s %9u samples lost overflow\n", dirent->d_name, num);
508
509 strcpy(fullname, cpupath);
510 strcat(fullname, "/sample_invalid_eip");
511 num = read_num(fullname);
512 printf(" %s %9u samples invalid eip\n", dirent->d_name, num);
513
514 strcpy(fullname, cpupath);
515 strcat(fullname, "/backtrace_aborted");
516 num = read_num(fullname);
517 printf(" %s %9u backtrace aborted\n", dirent->d_name, num);
518 }
519 }
520 closedir(dir);
521 }
Bruce Beare751a4432010-03-04 10:30:51 -0800522
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800523 num = read_num(OP_DRIVER_BASE"/backtrace_depth");
Ben Cheng529d8682012-01-04 14:35:36 -0800524 printf("backtrace_depth: %u\n", num);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800525 }
526 }
527 else {
528 printf("oprofiled is not running\n");
529 }
530}
531
532void do_reset()
533{
Ben Cheng529d8682012-01-04 14:35:36 -0800534 /*
535 * Sending SIGHUP will result in the following crash in oprofiled when
536 * profiling subsequent runs:
537 * Stack Trace:
538 * RELADDR FUNCTION FILE:LINE
539 * 00008cd8 add_node+12 oprofilelibdb/db_insert.c:32
540 * 00008d69 odb_update_node_with_offset+60 oprofilelibdb/db_insert.c:102
541 *
542 * However without sending SIGHUP oprofile cannot be restarted successfully.
543 * As a temporary workaround, change do_reset into a no-op for now and kill
544 * the old daemon in do_setup to start all over again as a heavy-weight
545 * reset.
546 */
547#if 0
Paul Lind73f45fe2013-03-04 17:10:49 -0800548 int pid = read_num(OP_DATA_DIR"/lock");
549 if (pid >= 0)
550 kill(pid, SIGHUP); /* HUP makes oprofiled close its sample files */
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800551
Paul Lind73f45fe2013-03-04 17:10:49 -0800552 if (access(OP_DATA_DIR"/samples/current", R_OK) == 0)
553 system("rm -r "OP_DATA_DIR"/samples/current");
Ben Cheng529d8682012-01-04 14:35:36 -0800554#endif
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800555}
556
557int main(int argc, char * const argv[])
558{
559 int option_index;
Jeff Brown87866d92011-02-02 13:27:17 -0800560 bool show_status = false;
561 char* verbose_log = NULL;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800562
563 /* Initialize default strings */
564 strcpy(vmlinux, "--no-vmlinux");
565 strcpy(kernel_range, "");
566
Paul Lind73f45fe2013-03-04 17:10:49 -0800567 setup_device();
568
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800569 while (1) {
Jeff Brown87866d92011-02-02 13:27:17 -0800570 int c = getopt_long(argc, argv, "c:e:v:r:dhVtl:", long_options, &option_index);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800571 if (c == -1) {
572 break;
573 }
574 switch (c) {
575 case 0:
576 break;
Bruce Beare751a4432010-03-04 10:30:51 -0800577 /* --callgraph */
578 case 'c':
Jeff Brown87866d92011-02-02 13:27:17 -0800579 strncpy(callgraph, optarg, sizeof(callgraph));
Bruce Beare751a4432010-03-04 10:30:51 -0800580 break;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800581 /* --event */
582 case 'e':
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700583 if (num_events == MAX_EVENTS) {
584 fprintf(stderr, "More than %d events specified\n",
585 MAX_EVENTS);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800586 exit(1);
587 }
588 if (process_event(optarg)) {
589 exit(1);
590 }
591 break;
592 /* --vmlinux */
593 case 'v':
594 sprintf(vmlinux, "-k %s", optarg);
595 break;
596 /* --kernel-range */
597 case 'r':
598 sprintf(kernel_range, "-r %s", optarg);
599 break;
Bruce Beare751a4432010-03-04 10:30:51 -0800600 case 'd':
601 /* --dump */ {
602 int pid = read_num(OP_DATA_DIR"/lock");
603 echo_dev("1", 0, "dump", -1);
Bruce Beare751a4432010-03-04 10:30:51 -0800604 break;
605 }
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800606 /* --shutdown */
607 case 'h': {
608 int pid = read_num(OP_DATA_DIR"/lock");
609 if (pid >= 0) {
Bruce Beare751a4432010-03-04 10:30:51 -0800610 kill(pid, SIGHUP); /* Politely ask the daemon to close files */
611 sleep(1);
612 kill(pid, SIGTERM);/* Politely ask the daemon to die */
613 sleep(1);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800614 kill(pid, SIGKILL);
Jeff Brown87866d92011-02-02 13:27:17 -0800615 }
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800616 setup_session_dir();
617 break;
618 }
Bruce Beare751a4432010-03-04 10:30:51 -0800619 /* --verbose */
620 case 'V':
621 verbose_print++;
622 break;
Jeff Brown87866d92011-02-02 13:27:17 -0800623 /* --verbose-log */
624 case 'l':
625 verbose_log = strdup(optarg);
626 break;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800627 /* --status */
628 case 't':
Jeff Brown87866d92011-02-02 13:27:17 -0800629 show_status = true;
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800630 break;
631 default:
632 usage();
633 exit(1);
634 }
635 }
636 verbose("list_events = %d\n", list_events);
637 verbose("setup = %d\n", setup);
638
639 if (list_events) {
640 do_list_events();
641 }
642
643 if (quick) {
Paul Lind73f45fe2013-03-04 17:10:49 -0800644 process_event(default_event);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800645 setup = 1;
646 }
647
Ben Chenga9404b82010-09-03 16:46:45 -0700648 if (timer) {
649 setup = 1;
650 }
651
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800652 if (reset) {
653 do_reset();
654 }
655
656 if (show_usage) {
657 usage();
658 }
659
660 if (setup) {
661 if (do_setup()) {
662 fprintf(stderr, "do_setup failed");
663 exit(1);
664 }
665 }
666
Bruce Beare751a4432010-03-04 10:30:51 -0800667 if (strlen(callgraph)) {
668 echo_dev(callgraph, 0, "backtrace_depth", -1);
669 }
670
Ben Chenga9404b82010-09-03 16:46:45 -0700671 if (num_events != 0 || timer != 0) {
Jeff Brown87866d92011-02-02 13:27:17 -0800672 char command[1024];
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800673 int i;
674
Jeff Brown87866d92011-02-02 13:27:17 -0800675 strcpy(command, argv[0]);
676 char* slash = strrchr(command, '/');
677 strcpy(slash ? slash + 1 : command, "oprofiled --session-dir="OP_DATA_DIR);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800678
Paul Lind73f45fe2013-03-04 17:10:49 -0800679#if defined(__arm__) && !defined(WITH_ARM_V7_A)
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800680 /* Since counter #3 can only handle CPU_CYCLES, check and shuffle the
681 * order a bit so that the maximal number of events can be profiled
682 * simultaneously
683 */
684 if (num_events == 3) {
685 for (i = 0; i < num_events; i++) {
686 int event_idx = selected_events[i];
687
688 if (event_info[event_idx].id == 0xff) {
689 break;
690 }
691 }
692
693 /* No CPU_CYCLES is found */
694 if (i == 3) {
695 fprintf(stderr, "You can only specify three events if one of "
696 "them is CPU_CYCLES\n");
697 exit(1);
698 }
699 /* Swap CPU_CYCLES to counter #2 (starting from #0)*/
700 else if (i != 2) {
701 int temp;
702
703 temp = selected_events[2];
704 selected_events[2] = selected_events[i];
705 selected_events[i] = temp;
706
707 temp = selected_counts[2];
708 selected_counts[2] = selected_counts[i];
709 selected_counts[i] = temp;
710 }
711 }
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700712#endif
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800713
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800714 /* Configure the counters and enable them */
715 for (i = 0; i < num_events; i++) {
716 int event_idx = selected_events[i];
717 int setup_result = 0;
718
719 if (i == 0) {
Jeff Brown87866d92011-02-02 13:27:17 -0800720 snprintf(command + strlen(command), sizeof(command) - strlen(command),
721 " --events=");
722 } else {
723 snprintf(command + strlen(command), sizeof(command) - strlen(command), ",");
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800724 }
725 /* Compose name:id:count:unit_mask:kernel:user, something like
726 * --events=CYCLES_DATA_STALL:2:0:200000:0:1:1,....
727 */
Jeff Brown87866d92011-02-02 13:27:17 -0800728 snprintf(command + strlen(command), sizeof(command) - strlen(command),
Bruce Beare751a4432010-03-04 10:30:51 -0800729 "%s:%d:%d:%d:%d:1:1",
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800730 event_info[event_idx].name,
731 event_info[event_idx].id,
732 i,
Bruce Beare751a4432010-03-04 10:30:51 -0800733 selected_counts[i],
734 event_info[event_idx].um);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800735
736 setup_result |= echo_dev("1", 0, "user", i);
737 setup_result |= echo_dev("1", 0, "kernel", i);
Bruce Beare751a4432010-03-04 10:30:51 -0800738 setup_result |= echo_dev(NULL, event_info[event_idx].um, "unit_mask", i);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800739 setup_result |= echo_dev("1", 0, "enabled", i);
740 setup_result |= echo_dev(NULL, selected_counts[i], "count", i);
741 setup_result |= echo_dev(NULL, event_info[event_idx].id,
742 "event", i);
743 if (setup_result) {
744 fprintf(stderr, "Counter configuration failed for %s\n",
745 event_info[event_idx].name);
746 fprintf(stderr, "Did you do \"opcontrol --setup\" first?\n");
747 exit(1);
748 }
749 }
750
Ben Chenga9404b82010-09-03 16:46:45 -0700751 if (timer == 0) {
752 /* If not in timer mode, disable unused counters */
Paul Lind73f45fe2013-03-04 17:10:49 -0800753 for (i = num_events; i < max_events; i++) {
Ben Chenga9404b82010-09-03 16:46:45 -0700754 echo_dev("0", 0, "enabled", i);
755 }
756 } else {
757 /* Timer mode uses empty event list */
Jeff Brown87866d92011-02-02 13:27:17 -0800758 snprintf(command + strlen(command), sizeof(command) - strlen(command),
759 " --events=");
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800760 }
761
Jeff Brown87866d92011-02-02 13:27:17 -0800762 snprintf(command + strlen(command), sizeof(command) - strlen(command),
763 " %s", vmlinux);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800764 if (kernel_range[0]) {
Jeff Brown87866d92011-02-02 13:27:17 -0800765 snprintf(command + strlen(command), sizeof(command) - strlen(command),
766 " %s", kernel_range);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800767 }
Jeff Brown87866d92011-02-02 13:27:17 -0800768
769 if (verbose_log) {
770 snprintf(command + strlen(command), sizeof(command) - strlen(command),
771 " --verbose=%s", verbose_log);
772 }
773
774 printf("Starting oprofiled...\n");
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800775 verbose("command: %s\n", command);
Jeff Brown87866d92011-02-02 13:27:17 -0800776
777 int rc = system(command);
778 if (rc) {
779 fprintf(stderr, "Failed, oprofile returned exit code: %d\n", rc);
780 } else {
781 sleep(2);
782 printf("Ready\n");
783 }
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800784 }
785
786 if (start) {
787 echo_dev("1", 0, "enable", -1);
Ben Cheng529d8682012-01-04 14:35:36 -0800788 int num = read_num(OP_DATA_DIR"/lock");
789
790 if (num >= 0) {
791 kill(num, SIGUSR1);
792 }
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800793 }
794
795 if (stop) {
Ben Chengafec5b92010-02-22 15:33:08 -0800796 echo_dev("1", 0, "dump", -1);
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800797 echo_dev("0", 0, "enable", -1);
798 }
Jeff Brown87866d92011-02-02 13:27:17 -0800799
800 if (show_status) {
801 do_status();
802 }
The Android Open Source Project10e23ee2009-03-03 19:30:30 -0800803}