1 /*
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>
26 #include <string.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <dirent.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34
35 #include "op_config.h"
36
37 #define verbose(fmt...) if (verbose_print) printf(fmt)
38
39 /* Experiments found that using a small interval may hang the device, and the
40 * more events tracked simultaneously, the longer the interval has to be.
41 */
42
43 #if defined(__i386__) || defined(__x86_64__)
44 #define MAX_EVENTS 2
45 int min_count[MAX_EVENTS] = {60000, 100000};
46 #elif !defined(WITH_ARM_V7_A)
47 #define MAX_EVENTS 3
48 int min_count[MAX_EVENTS] = {150000, 200000, 250000};
49 #else
50 #define MAX_EVENTS 5
51 int min_count[MAX_EVENTS] = {150000, 20000, 25000, 30000, 35000};
52 #endif
53
54 int verbose_print;
55 int list_events;
56 int show_usage;
57 int setup;
58 int quick;
59 int timer;
60 int num_events;
61 int start;
62 int stop;
63 int reset;
64
65 int selected_events[MAX_EVENTS];
66 int selected_counts[MAX_EVENTS];
67
68 char callgraph[8];
69 char kernel_range[512];
70 char vmlinux[512];
71
72 struct option long_options[] = {
73 {"help", 0, &show_usage, 1},
74 {"list-events", 0, &list_events, 1},
75 {"reset", 0, &reset, 1},
76 {"setup", 0, &setup, 1},
77 {"quick", 0, &quick, 1},
78 {"timer", 0, &timer, 1},
79 {"callgraph", 1, 0, 'c'},
80 {"event", 1, 0, 'e'},
81 {"vmlinux", 1, 0, 'v'},
82 {"kernel-range", 1, 0, 'r'},
83 {"start", 0, &start, 1},
84 {"stop", 0, &stop, 1},
85 {"dump", 0, 0, 'd'},
86 {"shutdown", 0, 0, 'h'},
87 {"status", 0, 0, 't'},
88 {"verbose", 0, 0, 'V'},
89 {"verbose-log", 1, 0, 'l'},
90 {0, 0, 0, 0},
91 };
92
93 struct event_info {
94 int id;
95 int um;
96 const char *name;
97 const char *explanation;
98 } event_info[] = {
99 #if defined(__i386__) || defined(__x86_64__)
100 /* INTEL_ARCH_PERFMON events */
101
102 /* 0x3c counters:cpuid um:zero minimum:6000 filter:0 name:CPU_CLK_UNHALTED :
103 * Clock cycles when not halted
104 */
105 {0x3c, 0, "CPU_CLK_UNHALTED",
106 "Clock cycles when not halted" },
107
108 /* event:0x3c counters:cpuid um:one minimum:6000 filter:2 name:UNHALTED_REFERENCE_CYCLES :
109 * Unhalted reference cycles
110 */
111 {0x3c, 1, "UNHALTED_REFERENCE_CYCLES",
112 "Unhalted reference cycles" },
113
114 /* event:0xc0 counters:cpuid um:zero minimum:6000 filter:1 name:INST_RETIRED :
115 * number of instructions retired
116 */
117 {0xc0, 0, "INST_RETIRED",
118 "number of instructions retired"},
119
120 /* event:0x2e counters:cpuid um:x41 minimum:6000 filter:5 name:LLC_MISSES :
121 * Last level cache demand requests from this core that missed the LLC
122 */
123 {0x2e, 0x41, "LLC_MISSES",
124 "Last level cache demand requests from this core that missed the LLC"},
125
126 /* event:0x2e counters:cpuid um:x4f minimum:6000 filter:4 name:LLC_REFS :
127 * Last level cache demand requests from this core
128 */
129 {0x2e, 0x4f, "LLC_REFS",
130 "Last level cache demand requests from this core"},
131
132 /* event:0xc4 counters:cpuid um:zero minimum:500 filter:6 name:BR_INST_RETIRED :
133 * number of branch instructions retired
134 */
135 {0xc4, 0, "BR_INST_RETIRED",
136 "number of branch instructions retired"},
137
138 /* event:0xc5 counters:cpuid um:zero minimum:500 filter:7 name:BR_MISS_PRED_RETIRED :
139 * number of mispredicted branches retired (precise)
140 */
141 {0xc5, 0, "BR_MISS_PRED_RETIRED",
142 "number of mispredicted branches retired (precise)"},
143
144 #elif !defined(WITH_ARM_V7_A)
145 /* ARM V6 events */
146 {0x00, 0, "IFU_IFETCH_MISS",
147 "number of instruction fetch misses"},
148 {0x01, 0, "CYCLES_IFU_MEM_STALL",
149 "cycles instruction fetch pipe is stalled"},
150 {0x02, 0, "CYCLES_DATA_STALL",
151 "cycles stall occurs for due to data dependency"},
152 {0x03, 0, "ITLB_MISS",
153 "number of Instruction MicroTLB misses"},
154 {0x04, 0, "DTLB_MISS",
155 "number of Data MicroTLB misses"},
156 {0x05, 0, "BR_INST_EXECUTED",
157 "branch instruction executed w/ or w/o program flow change"},
158 {0x06, 0, "BR_INST_MISS_PRED",
159 "branch mispredicted"},
160 {0x07, 0, "INSN_EXECUTED",
161 "instructions executed"},
162 {0x09, 0, "DCACHE_ACCESS",
163 "data cache access, cacheable locations"},
164 {0x0a, 0, "DCACHE_ACCESS_ALL",
165 "data cache access, all locations"},
166 {0x0b, 0, "DCACHE_MISS",
167 "data cache miss"},
168 {0x0c, 0, "DCACHE_WB",
169 "data cache writeback, 1 event for every half cacheline"},
170 {0x0d, 0, "PC_CHANGE",
171 "number of times the program counter was changed without a mode switch"},
172 {0x0f, 0, "TLB_MISS",
173 "Main TLB miss"},
174 {0x10, 0, "EXP_EXTERNAL",
175 "Explicit external data access"},
176 {0x11, 0, "LSU_STALL",
177 "cycles stalled because Load Store request queue is full"},
178 {0x12, 0, "WRITE_DRAIN",
179 "Times write buffer was drained"},
180 {0xff, 0, "CPU_CYCLES",
181 "clock cycles counter"},
182 #else
183 /* ARM V7 events */
184 {0x00, 0, "PMNC_SW_INCR",
185 "Software increment of PMNC registers"},
186 {0x01, 0, "IFETCH_MISS",
187 "Instruction fetch misses from cache or normal cacheable memory"},
188 {0x02, 0, "ITLB_MISS",
189 "Instruction fetch misses from TLB"},
190 {0x03, 0, "DCACHE_REFILL",
191 "Data R/W operation that causes a refill from cache or normal cacheable"
192 "memory"},
193 {0x04, 0, "DCACHE_ACCESS",
194 "Data R/W from cache"},
195 {0x05, 0, "DTLB_REFILL",
196 "Data R/W that causes a TLB refill"},
197 {0x06, 0, "DREAD",
198 "Data read architecturally executed (note: architecturally executed = for"
199 "instructions that are unconditional or that pass the condition code)"},
200 {0x07, 0, "DWRITE",
201 "Data write architecturally executed"},
202 {0x08, 0, "INSTR_EXECUTED",
203 "All executed instructions"},
204 {0x09, 0, "EXC_TAKEN",
205 "Exception taken"},
206 {0x0A, 0, "EXC_EXECUTED",
207 "Exception return architecturally executed"},
208 {0x0B, 0, "CID_WRITE",
209 "Instruction that writes to the Context ID Register architecturally"
210 "executed"},
211 {0x0C, 0, "PC_WRITE",
212 "SW change of PC, architecturally executed (not by exceptions)"},
213 {0x0D, 0, "PC_IMM_BRANCH",
214 "Immediate branch instruction executed (taken or not)"},
215 {0x0E, 0, "PC_PROC_RETURN",
216 "Procedure return architecturally executed (not by exceptions)"},
217 {0x0F, 0, "UNALIGNED_ACCESS",
218 "Unaligned access architecturally executed"},
219 {0x10, 0, "PC_BRANCH_MIS_PRED",
220 "Branch mispredicted or not predicted. Counts pipeline flushes because of"
221 "misprediction"},
222 {0x12, 0, "PC_BRANCH_MIS_USED",
223 "Branch or change in program flow that could have been predicted"},
224 {0x40, 0, "WRITE_BUFFER_FULL",
225 "Any write buffer full cycle"},
226 {0x41, 0, "L2_STORE_MERGED",
227 "Any store that is merged in L2 cache"},
228 {0x42, 0, "L2_STORE_BUFF",
229 "Any bufferable store from load/store to L2 cache"},
230 {0x43, 0, "L2_ACCESS",
231 "Any access to L2 cache"},
232 {0x44, 0, "L2_CACH_MISS",
233 "Any cacheable miss in L2 cache"},
234 {0x45, 0, "AXI_READ_CYCLES",
235 "Number of cycles for an active AXI read"},
236 {0x46, 0, "AXI_WRITE_CYCLES",
237 "Number of cycles for an active AXI write"},
238 {0x47, 0, "MEMORY_REPLAY",
239 "Any replay event in the memory subsystem"},
240 {0x48, 0, "UNALIGNED_ACCESS_REPLAY",
241 "Unaligned access that causes a replay"},
242 {0x49, 0, "L1_DATA_MISS",
243 "L1 data cache miss as a result of the hashing algorithm"},
244 {0x4A, 0, "L1_INST_MISS",
245 "L1 instruction cache miss as a result of the hashing algorithm"},
246 {0x4B, 0, "L1_DATA_COLORING",
247 "L1 data access in which a page coloring alias occurs"},
248 {0x4C, 0, "L1_NEON_DATA",
249 "NEON data access that hits L1 cache"},
250 {0x4D, 0, "L1_NEON_CACH_DATA",
251 "NEON cacheable data access that hits L1 cache"},
252 {0x4E, 0, "L2_NEON",
253 "L2 access as a result of NEON memory access"},
254 {0x4F, 0, "L2_NEON_HIT",
255 "Any NEON hit in L2 cache"},
256 {0x50, 0, "L1_INST",
257 "Any L1 instruction cache access, excluding CP15 cache accesses"},
258 {0x51, 0, "PC_RETURN_MIS_PRED",
259 "Return stack misprediction at return stack pop"
260 "(incorrect target address)"},
261 {0x52, 0, "PC_BRANCH_FAILED",
262 "Branch prediction misprediction"},
263 {0x53, 0, "PC_BRANCH_TAKEN",
264 "Any predicted branch that is taken"},
265 {0x54, 0, "PC_BRANCH_EXECUTED",
266 "Any taken branch that is executed"},
267 {0x55, 0, "OP_EXECUTED",
268 "Number of operations executed"
269 "(in instruction or mutli-cycle instruction)"},
270 {0x56, 0, "CYCLES_INST_STALL",
271 "Cycles where no instruction available"},
272 {0x57, 0, "CYCLES_INST",
273 "Number of instructions issued in a cycle"},
274 {0x58, 0, "CYCLES_NEON_DATA_STALL",
275 "Number of cycles the processor waits on MRC data from NEON"},
276 {0x59, 0, "CYCLES_NEON_INST_STALL",
277 "Number of cycles the processor waits on NEON instruction queue or"
278 "NEON load queue"},
279 {0x5A, 0, "NEON_CYCLES",
280 "Number of cycles NEON and integer processors are not idle"},
281 {0x70, 0, "PMU0_EVENTS",
282 "Number of events from external input source PMUEXTIN[0]"},
283 {0x71, 0, "PMU1_EVENTS",
284 "Number of events from external input source PMUEXTIN[1]"},
285 {0x72, 0, "PMU_EVENTS",
286 "Number of events from both external input sources PMUEXTIN[0]"
287 "and PMUEXTIN[1]"},
288 {0xFF, 0, "CPU_CYCLES",
289 "Number of CPU cycles"},
290 #endif
291 };
292
usage()293 void usage()
294 {
295 printf("\nopcontrol: usage:\n"
296 " --list-events list event types\n"
297 " --help this message\n"
298 " --verbose show extra status\n"
299 " --verbose-log=lvl set daemon logging verbosity during setup\n"
300 " levels are: all,sfile,arcs,samples,module,misc\n"
301 " --setup setup directories\n"
302 #if defined(__i386__) || defined(__x86_64__)
303 " --quick setup and select CPU_CLK_UNHALTED:60000\n"
304 #else
305 " --quick setup and select CPU_CYCLES:150000\n"
306 #endif
307 " --timer timer-based profiling\n"
308 " --status show configuration\n"
309 " --start start data collection\n"
310 " --stop stop data collection\n"
311 " --reset clears out data from current session\n"
312 " --shutdown kill the oprofile daeman\n"
313 " --callgraph=depth callgraph depth\n"
314 " --event=eventspec\n"
315 " Choose an event. May be specified multiple times.\n"
316 " eventspec is in the form of name[:count], where :\n"
317 " name: event name, see \"opcontrol --list-events\"\n"
318 " count: reset counter value\n"
319 " --vmlinux=file vmlinux kernel image\n"
320 " --kernel-range=start,end\n"
321 " kernel range vma address in hexadecimal\n"
322 );
323 }
324
setup_session_dir()325 void setup_session_dir()
326 {
327 int fd;
328
329 fd = open(OP_DATA_DIR, O_RDONLY);
330 if (fd != -1) {
331 system("rm -r "OP_DATA_DIR);
332 close(fd);
333 }
334
335 if (mkdir(OP_DATA_DIR, 0755)) {
336 fprintf(stderr, "Cannot create directory \"%s\": %s\n",
337 OP_DATA_DIR, strerror(errno));
338 }
339 if (mkdir(OP_DATA_DIR"/samples", 0755)) {
340 fprintf(stderr, "Cannot create directory \"%s\": %s\n",
341 OP_DATA_DIR"/samples", strerror(errno));
342 }
343 }
344
do_setup()345 int do_setup()
346 {
347 char dir[1024];
348
349 setup_session_dir();
350
351 if (mkdir(OP_DRIVER_BASE, 0755)) {
352 if (errno != EEXIST) {
353 fprintf(stderr, "Cannot create directory "OP_DRIVER_BASE": %s\n",
354 strerror(errno));
355 return -1;
356 }
357 }
358
359 if (access(OP_DRIVER_BASE"/stats", F_OK)) {
360 if (system("mount -t oprofilefs nodev "OP_DRIVER_BASE)) {
361 return -1;
362 }
363 }
364 return 0;
365 }
366
do_list_events()367 void do_list_events()
368 {
369 unsigned int i;
370
371 printf("%-20s: %s\n", "name", "meaning");
372 printf("----------------------------------------"
373 "--------------------------------------\n");
374 for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) {
375 printf("%-20s: %s\n", event_info[i].name, event_info[i].explanation);
376 }
377 }
378
find_event_idx_from_name(const char * name)379 int find_event_idx_from_name(const char *name)
380 {
381 unsigned int i;
382
383 for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) {
384 if (!strcmp(name, event_info[i].name)) {
385 return i;
386 }
387 }
388 return -1;
389 }
390
find_event_name_from_id(int id)391 const char * find_event_name_from_id(int id)
392 {
393 unsigned int i;
394
395 for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) {
396 if (event_info[i].id == id) {
397 return event_info[i].name;
398 }
399 }
400 return NULL;
401 }
402
process_event(const char * event_spec)403 int process_event(const char *event_spec)
404 {
405 char event_name[512];
406 char count_name[512];
407 unsigned int i;
408 int event_idx;
409 int count_val;
410
411 strncpy(event_name, event_spec, 512);
412 count_name[0] = 0;
413
414 /* First, check if the name is followed by ":" */
415 for (i = 0; i < strlen(event_name); i++) {
416 if (event_name[i] == 0) {
417 break;
418 }
419 if (event_name[i] == ':') {
420 strncpy(count_name, event_name+i+1, 512);
421 event_name[i] = 0;
422 break;
423 }
424 }
425 event_idx = find_event_idx_from_name(event_name);
426 if (event_idx == -1) {
427 fprintf(stderr, "Unknown event name: %s\n", event_name);
428 return -1;
429 }
430
431 /* Use default count */
432 if (count_name[0] == 0) {
433 count_val = min_count[0];
434 } else {
435 count_val = atoi(count_name);
436 }
437
438 selected_events[num_events] = event_idx;
439 selected_counts[num_events++] = count_val;
440 verbose("event_id is %d\n", event_info[event_idx].id);
441 verbose("count_val is %d\n", count_val);
442 return 0;
443 }
444
echo_dev(const char * str,int val,const char * file,int counter)445 int echo_dev(const char* str, int val, const char* file, int counter)
446 {
447 char fullname[512];
448 char content[128];
449 int fd;
450
451 if (counter >= 0) {
452 snprintf(fullname, 512, OP_DRIVER_BASE"/%d/%s", counter, file);
453 }
454 else {
455 snprintf(fullname, 512, OP_DRIVER_BASE"/%s", file);
456 }
457 fd = open(fullname, O_WRONLY);
458 if (fd<0) {
459 fprintf(stderr, "Cannot open %s: %s\n", fullname, strerror(errno));
460 return fd;
461 }
462 if (str == 0) {
463 sprintf(content, "%d", val);
464 }
465 else {
466 strncpy(content, str, 128);
467 }
468 verbose("Configure %s (%s)\n", fullname, content);
469 write(fd, content, strlen(content));
470 close(fd);
471 return 0;
472 }
473
read_num(const char * file)474 int read_num(const char* file)
475 {
476 char buffer[256];
477 int fd = open(file, O_RDONLY);
478 if (fd<0) return -1;
479 int rd = read(fd, buffer, sizeof(buffer)-1);
480 buffer[rd] = 0;
481 return atoi(buffer);
482 }
483
do_status()484 void do_status()
485 {
486 int num;
487 char fullname[512];
488 int i;
489
490 printf("Driver directory: %s\n", OP_DRIVER_BASE);
491 printf("Session directory: %s\n", OP_DATA_DIR);
492 for (i = 0; i < MAX_EVENTS; i++) {
493 sprintf(fullname, OP_DRIVER_BASE"/%d/enabled", i);
494 num = read_num(fullname);
495 if (num > 0) {
496 printf("Counter %d:\n", i);
497
498 /* event name */
499 sprintf(fullname, OP_DRIVER_BASE"/%d/event", i);
500 num = read_num(fullname);
501 printf(" name: %s\n", find_event_name_from_id(num));
502
503 /* profile interval */
504 sprintf(fullname, OP_DRIVER_BASE"/%d/count", i);
505 num = read_num(fullname);
506 printf(" count: %d\n", num);
507 }
508 else {
509 printf("Counter %d disabled\n", i);
510 }
511 }
512
513 num = read_num(OP_DATA_DIR"/lock");
514 if (num >= 0) {
515 int fd;
516 /* Still needs to check if this lock is left-over */
517 sprintf(fullname, "/proc/%d", num);
518 fd = open(fullname, O_RDONLY);
519 if (fd == -1) {
520 printf("Session directory is not clean - do \"opcontrol --setup\""
521 " before you continue\n");
522 return;
523 }
524 else {
525 close(fd);
526
527 printf("oprofiled pid: %d\n", num);
528 num = read_num(OP_DRIVER_BASE"/enable");
529
530 printf("profiler is%s running\n", num == 0 ? " not" : "");
531
532 DIR* dir = opendir(OP_DRIVER_BASE"/stats");
533 if (dir) {
534 for (struct dirent* dirent; !!(dirent = readdir(dir));) {
535 if (strlen(dirent->d_name) >= 4 && memcmp(dirent->d_name, "cpu", 3) == 0) {
536 char cpupath[256];
537 strcpy(cpupath, OP_DRIVER_BASE"/stats/");
538 strcat(cpupath, dirent->d_name);
539
540 strcpy(fullname, cpupath);
541 strcat(fullname, "/sample_received");
542 num = read_num(fullname);
543 printf(" %s %9u samples received\n", dirent->d_name, num);
544
545 strcpy(fullname, cpupath);
546 strcat(fullname, "/sample_lost_overflow");
547 num = read_num(fullname);
548 printf(" %s %9u samples lost overflow\n", dirent->d_name, num);
549
550 strcpy(fullname, cpupath);
551 strcat(fullname, "/sample_invalid_eip");
552 num = read_num(fullname);
553 printf(" %s %9u samples invalid eip\n", dirent->d_name, num);
554
555 strcpy(fullname, cpupath);
556 strcat(fullname, "/backtrace_aborted");
557 num = read_num(fullname);
558 printf(" %s %9u backtrace aborted\n", dirent->d_name, num);
559 }
560 }
561 closedir(dir);
562 }
563
564 #if defined(__i386__) || defined(__x86_64__)
565 /* FIXME on ARM - backtrace seems broken there */
566 num = read_num(OP_DRIVER_BASE"/backtrace_depth");
567 printf(" %9u backtrace_depth\n", num);
568 #endif
569 }
570 }
571 else {
572 printf("oprofiled is not running\n");
573 }
574 }
575
do_reset()576 void do_reset()
577 {
578 int fd;
579
580 fd = open(OP_DATA_DIR"/samples/current", O_RDONLY);
581 if (fd == -1) {
582 return;
583 }
584 close(fd);
585 system("rm -r "OP_DATA_DIR"/samples/current");
586 }
587
main(int argc,char * const argv[])588 int main(int argc, char * const argv[])
589 {
590 int option_index;
591 bool show_status = false;
592 char* verbose_log = NULL;
593
594 /* Initialize default strings */
595 strcpy(vmlinux, "--no-vmlinux");
596 strcpy(kernel_range, "");
597
598 while (1) {
599 int c = getopt_long(argc, argv, "c:e:v:r:dhVtl:", long_options, &option_index);
600 if (c == -1) {
601 break;
602 }
603 switch (c) {
604 case 0:
605 break;
606 /* --callgraph */
607 case 'c':
608 strncpy(callgraph, optarg, sizeof(callgraph));
609 break;
610 /* --event */
611 case 'e':
612 if (num_events == MAX_EVENTS) {
613 fprintf(stderr, "More than %d events specified\n",
614 MAX_EVENTS);
615 exit(1);
616 }
617 if (process_event(optarg)) {
618 exit(1);
619 }
620 break;
621 /* --vmlinux */
622 case 'v':
623 sprintf(vmlinux, "-k %s", optarg);
624 break;
625 /* --kernel-range */
626 case 'r':
627 sprintf(kernel_range, "-r %s", optarg);
628 break;
629 case 'd':
630 /* --dump */ {
631 int pid = read_num(OP_DATA_DIR"/lock");
632 echo_dev("1", 0, "dump", -1);
633 if (pid >= 0) {
634 sleep(1);
635 kill(pid, SIGHUP);
636 }
637 break;
638 }
639 /* --shutdown */
640 case 'h': {
641 int pid = read_num(OP_DATA_DIR"/lock");
642 if (pid >= 0) {
643 kill(pid, SIGHUP); /* Politely ask the daemon to close files */
644 sleep(1);
645 kill(pid, SIGTERM);/* Politely ask the daemon to die */
646 sleep(1);
647 kill(pid, SIGKILL);
648 }
649 setup_session_dir();
650 break;
651 }
652 /* --verbose */
653 case 'V':
654 verbose_print++;
655 break;
656 /* --verbose-log */
657 case 'l':
658 verbose_log = strdup(optarg);
659 break;
660 /* --status */
661 case 't':
662 show_status = true;
663 break;
664 default:
665 usage();
666 exit(1);
667 }
668 }
669 verbose("list_events = %d\n", list_events);
670 verbose("setup = %d\n", setup);
671
672 if (list_events) {
673 do_list_events();
674 }
675
676 if (quick) {
677 #if defined(__i386__) || defined(__x86_64__)
678 process_event("CPU_CLK_UNHALTED");
679 #else
680 process_event("CPU_CYCLES");
681 #endif
682 setup = 1;
683 }
684
685 if (timer) {
686 setup = 1;
687 }
688
689 if (reset) {
690 do_reset();
691 }
692
693 if (show_usage) {
694 usage();
695 }
696
697 if (setup) {
698 if (do_setup()) {
699 fprintf(stderr, "do_setup failed");
700 exit(1);
701 }
702 }
703
704 if (strlen(callgraph)) {
705 echo_dev(callgraph, 0, "backtrace_depth", -1);
706 }
707
708 if (num_events != 0 || timer != 0) {
709 char command[1024];
710 int i;
711
712 strcpy(command, argv[0]);
713 char* slash = strrchr(command, '/');
714 strcpy(slash ? slash + 1 : command, "oprofiled --session-dir="OP_DATA_DIR);
715
716 #if defined(__i386__) || defined(__x86_64__)
717 /* Nothing */
718 #elif !defined(WITH_ARM_V7_A)
719 /* Since counter #3 can only handle CPU_CYCLES, check and shuffle the
720 * order a bit so that the maximal number of events can be profiled
721 * simultaneously
722 */
723 if (num_events == 3) {
724 for (i = 0; i < num_events; i++) {
725 int event_idx = selected_events[i];
726
727 if (event_info[event_idx].id == 0xff) {
728 break;
729 }
730 }
731
732 /* No CPU_CYCLES is found */
733 if (i == 3) {
734 fprintf(stderr, "You can only specify three events if one of "
735 "them is CPU_CYCLES\n");
736 exit(1);
737 }
738 /* Swap CPU_CYCLES to counter #2 (starting from #0)*/
739 else if (i != 2) {
740 int temp;
741
742 temp = selected_events[2];
743 selected_events[2] = selected_events[i];
744 selected_events[i] = temp;
745
746 temp = selected_counts[2];
747 selected_counts[2] = selected_counts[i];
748 selected_counts[i] = temp;
749 }
750 }
751 #endif
752
753 /* Configure the counters and enable them */
754 for (i = 0; i < num_events; i++) {
755 int event_idx = selected_events[i];
756 int setup_result = 0;
757
758 if (i == 0) {
759 snprintf(command + strlen(command), sizeof(command) - strlen(command),
760 " --events=");
761 } else {
762 snprintf(command + strlen(command), sizeof(command) - strlen(command), ",");
763 }
764 /* Compose name:id:count:unit_mask:kernel:user, something like
765 * --events=CYCLES_DATA_STALL:2:0:200000:0:1:1,....
766 */
767 snprintf(command + strlen(command), sizeof(command) - strlen(command),
768 "%s:%d:%d:%d:%d:1:1",
769 event_info[event_idx].name,
770 event_info[event_idx].id,
771 i,
772 selected_counts[i],
773 event_info[event_idx].um);
774
775 setup_result |= echo_dev("1", 0, "user", i);
776 setup_result |= echo_dev("1", 0, "kernel", i);
777 setup_result |= echo_dev(NULL, event_info[event_idx].um, "unit_mask", i);
778 setup_result |= echo_dev("1", 0, "enabled", i);
779 setup_result |= echo_dev(NULL, selected_counts[i], "count", i);
780 setup_result |= echo_dev(NULL, event_info[event_idx].id,
781 "event", i);
782 if (setup_result) {
783 fprintf(stderr, "Counter configuration failed for %s\n",
784 event_info[event_idx].name);
785 fprintf(stderr, "Did you do \"opcontrol --setup\" first?\n");
786 exit(1);
787 }
788 }
789
790 if (timer == 0) {
791 /* If not in timer mode, disable unused counters */
792 for (i = num_events; i < MAX_EVENTS; i++) {
793 echo_dev("0", 0, "enabled", i);
794 }
795 } else {
796 /* Timer mode uses empty event list */
797 snprintf(command + strlen(command), sizeof(command) - strlen(command),
798 " --events=");
799 }
800
801 snprintf(command + strlen(command), sizeof(command) - strlen(command),
802 " %s", vmlinux);
803 if (kernel_range[0]) {
804 snprintf(command + strlen(command), sizeof(command) - strlen(command),
805 " %s", kernel_range);
806 }
807
808 if (verbose_log) {
809 snprintf(command + strlen(command), sizeof(command) - strlen(command),
810 " --verbose=%s", verbose_log);
811 }
812
813 printf("Starting oprofiled...\n");
814 verbose("command: %s\n", command);
815
816 int rc = system(command);
817 if (rc) {
818 fprintf(stderr, "Failed, oprofile returned exit code: %d\n", rc);
819 } else {
820 sleep(2);
821 printf("Ready\n");
822 }
823 }
824
825 if (start) {
826 echo_dev("1", 0, "enable", -1);
827 }
828
829 if (stop) {
830 echo_dev("1", 0, "dump", -1);
831 echo_dev("0", 0, "enable", -1);
832 }
833
834 if (show_status) {
835 do_status();
836 }
837 }
838