• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
read_num(const char * file)345 int read_num(const char* file)
346 {
347     char buffer[256];
348     int fd = open(file, O_RDONLY);
349     if (fd<0) return -1;
350     int rd = read(fd, buffer, sizeof(buffer)-1);
351     buffer[rd] = 0;
352     close(fd);
353     return atoi(buffer);
354 }
355 
do_setup()356 int do_setup()
357 {
358     char dir[1024];
359 
360     /*
361      * Kill the old daemon so that setup can be done more than once to achieve
362      * the same effect as reset.
363      */
364     int num = read_num(OP_DATA_DIR"/lock");
365     if (num >= 0) {
366         printf("Terminating the old daemon...\n");
367         kill(num, SIGTERM);
368         sleep(5);
369     }
370 
371     setup_session_dir();
372 
373     if (mkdir(OP_DRIVER_BASE, 0755)) {
374         if (errno != EEXIST) {
375             fprintf(stderr, "Cannot create directory "OP_DRIVER_BASE": %s\n",
376                     strerror(errno));
377             return -1;
378         }
379     }
380 
381     if (access(OP_DRIVER_BASE"/stats", F_OK)) {
382         if (system("mount -t oprofilefs nodev "OP_DRIVER_BASE)) {
383             return -1;
384         }
385     }
386     return 0;
387 }
388 
do_list_events()389 void do_list_events()
390 {
391     unsigned int i;
392 
393     printf("%-20s: %s\n", "name", "meaning");
394     printf("----------------------------------------"
395            "--------------------------------------\n");
396     for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) {
397         printf("%-20s: %s\n", event_info[i].name, event_info[i].explanation);
398     }
399 }
400 
find_event_idx_from_name(const char * name)401 int find_event_idx_from_name(const char *name)
402 {
403     unsigned int i;
404 
405     for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) {
406         if (!strcmp(name, event_info[i].name)) {
407             return i;
408         }
409     }
410     return -1;
411 }
412 
find_event_name_from_id(int id)413 const char * find_event_name_from_id(int id)
414 {
415     unsigned int i;
416 
417     for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) {
418         if (event_info[i].id == id) {
419             return event_info[i].name;
420         }
421     }
422     return NULL;
423 }
424 
process_event(const char * event_spec)425 int process_event(const char *event_spec)
426 {
427     char event_name[512];
428     char count_name[512];
429     unsigned int i;
430     int event_idx;
431     int count_val;
432 
433     strncpy(event_name, event_spec, 512);
434     count_name[0] = 0;
435 
436     /* First, check if the name is followed by ":" */
437     for (i = 0; i < strlen(event_name); i++) {
438         if (event_name[i] == 0) {
439             break;
440         }
441         if (event_name[i] == ':') {
442             strncpy(count_name, event_name+i+1, 512);
443             event_name[i] = 0;
444             break;
445         }
446     }
447     event_idx = find_event_idx_from_name(event_name);
448     if (event_idx == -1) {
449         fprintf(stderr, "Unknown event name: %s\n", event_name);
450         return -1;
451     }
452 
453     /* Use default count */
454     if (count_name[0] == 0) {
455         count_val = min_count[0];
456     } else {
457         count_val = atoi(count_name);
458     }
459 
460     selected_events[num_events] = event_idx;
461     selected_counts[num_events++] = count_val;
462     verbose("event_id is %d\n", event_info[event_idx].id);
463     verbose("count_val is %d\n", count_val);
464     return 0;
465 }
466 
echo_dev(const char * str,int val,const char * file,int counter)467 int echo_dev(const char* str, int val, const char* file, int counter)
468 {
469     char fullname[512];
470     char content[128];
471     int fd;
472 
473     if (counter >= 0) {
474         snprintf(fullname, 512, OP_DRIVER_BASE"/%d/%s", counter, file);
475     }
476     else {
477         snprintf(fullname, 512, OP_DRIVER_BASE"/%s", file);
478     }
479     fd = open(fullname, O_WRONLY);
480     if (fd<0) {
481         fprintf(stderr, "Cannot open %s: %s\n", fullname, strerror(errno));
482         return fd;
483     }
484     if (str == 0) {
485         sprintf(content, "%d", val);
486     }
487     else {
488         strncpy(content, str, 128);
489     }
490     verbose("Configure %s (%s)\n", fullname, content);
491     write(fd, content, strlen(content));
492     close(fd);
493     return 0;
494 }
495 
do_status()496 void do_status()
497 {
498     int num;
499     char fullname[512];
500     int i;
501 
502     printf("Driver directory: %s\n", OP_DRIVER_BASE);
503     printf("Session directory: %s\n", OP_DATA_DIR);
504     for (i = 0; i < MAX_EVENTS; i++) {
505         sprintf(fullname, OP_DRIVER_BASE"/%d/enabled", i);
506         num = read_num(fullname);
507         if (num > 0) {
508             printf("Counter %d:\n", i);
509 
510             /* event name */
511             sprintf(fullname, OP_DRIVER_BASE"/%d/event", i);
512             num = read_num(fullname);
513             printf("    name: %s\n", find_event_name_from_id(num));
514 
515             /* profile interval */
516             sprintf(fullname, OP_DRIVER_BASE"/%d/count", i);
517             num = read_num(fullname);
518             printf("    count: %d\n", num);
519         }
520         else {
521             printf("Counter %d disabled\n", i);
522         }
523     }
524 
525     num = read_num(OP_DATA_DIR"/lock");
526     if (num >= 0) {
527         int fd;
528         /* Still needs to check if this lock is left-over */
529         sprintf(fullname, "/proc/%d", num);
530         fd = open(fullname, O_RDONLY);
531         if (fd == -1) {
532             printf("OProfile daemon exited prematurely - redo setup"
533                    " before you continue\n");
534             return;
535         }
536         else {
537             close(fd);
538 
539             printf("oprofiled pid: %d\n", num);
540             num = read_num(OP_DRIVER_BASE"/enable");
541 
542             printf("profiler is%s running\n", num == 0 ? " not" : "");
543 
544             DIR* dir = opendir(OP_DRIVER_BASE"/stats");
545             if (dir) {
546                 for (struct dirent* dirent; !!(dirent = readdir(dir));) {
547                     if (strlen(dirent->d_name) >= 4 && memcmp(dirent->d_name, "cpu", 3) == 0) {
548                         char cpupath[256];
549                         strcpy(cpupath, OP_DRIVER_BASE"/stats/");
550                         strcat(cpupath, dirent->d_name);
551 
552                         strcpy(fullname, cpupath);
553                         strcat(fullname, "/sample_received");
554                         num = read_num(fullname);
555                         printf("  %s %9u samples received\n", dirent->d_name, num);
556 
557                         strcpy(fullname, cpupath);
558                         strcat(fullname, "/sample_lost_overflow");
559                         num = read_num(fullname);
560                         printf("  %s %9u samples lost overflow\n", dirent->d_name, num);
561 
562                         strcpy(fullname, cpupath);
563                         strcat(fullname, "/sample_invalid_eip");
564                         num = read_num(fullname);
565                         printf("  %s %9u samples invalid eip\n", dirent->d_name, num);
566 
567                         strcpy(fullname, cpupath);
568                         strcat(fullname, "/backtrace_aborted");
569                         num = read_num(fullname);
570                         printf("  %s %9u backtrace aborted\n", dirent->d_name, num);
571                     }
572                 }
573                 closedir(dir);
574             }
575 
576             num = read_num(OP_DRIVER_BASE"/backtrace_depth");
577             printf("backtrace_depth: %u\n", num);
578         }
579     }
580     else {
581         printf("oprofiled is not running\n");
582     }
583 }
584 
do_reset()585 void do_reset()
586 {
587     /*
588      * Sending SIGHUP will result in the following crash in oprofiled when
589      * profiling subsequent runs:
590      * Stack Trace:
591      * RELADDR   FUNCTION                         FILE:LINE
592      *   00008cd8  add_node+12                    oprofilelibdb/db_insert.c:32
593      *   00008d69  odb_update_node_with_offset+60 oprofilelibdb/db_insert.c:102
594      *
595      * However without sending SIGHUP oprofile cannot be restarted successfully.
596      * As a temporary workaround, change do_reset into a no-op for now and kill
597      * the old daemon in do_setup to start all over again as a heavy-weight
598      * reset.
599      */
600 #if 0
601     int fd;
602 
603     fd = open(OP_DATA_DIR"/samples/current", O_RDONLY);
604     if (fd == -1) {
605         return;
606     }
607     close(fd);
608     system("rm -r "OP_DATA_DIR"/samples/current");
609     int num = read_num(OP_DATA_DIR"/lock");
610 
611     if (num >= 0) {
612         printf("Signalling daemon...\n");
613         kill(num, SIGHUP);
614     }
615 #endif
616 }
617 
main(int argc,char * const argv[])618 int main(int argc, char * const argv[])
619 {
620     int option_index;
621     bool show_status = false;
622     char* verbose_log = NULL;
623 
624     /* Initialize default strings */
625     strcpy(vmlinux, "--no-vmlinux");
626     strcpy(kernel_range, "");
627 
628     while (1) {
629         int c = getopt_long(argc, argv, "c:e:v:r:dhVtl:", long_options, &option_index);
630         if (c == -1) {
631             break;
632         }
633         switch (c) {
634             case 0:
635                 break;
636             /* --callgraph */
637             case 'c':
638                 strncpy(callgraph, optarg, sizeof(callgraph));
639                 break;
640             /* --event */
641             case 'e':
642                 if (num_events == MAX_EVENTS) {
643                     fprintf(stderr, "More than %d events specified\n",
644                             MAX_EVENTS);
645                     exit(1);
646                 }
647                 if (process_event(optarg)) {
648                     exit(1);
649                 }
650                 break;
651             /* --vmlinux */
652             case 'v':
653                 sprintf(vmlinux, "-k %s", optarg);
654                 break;
655             /* --kernel-range */
656             case 'r':
657                 sprintf(kernel_range, "-r %s", optarg);
658                 break;
659             case 'd':
660             /* --dump */ {
661                 int pid = read_num(OP_DATA_DIR"/lock");
662                 echo_dev("1", 0, "dump", -1);
663                 break;
664             }
665             /* --shutdown */
666             case 'h': {
667                 int pid = read_num(OP_DATA_DIR"/lock");
668                 if (pid >= 0) {
669                     kill(pid, SIGHUP); /* Politely ask the daemon to close files */
670                     sleep(1);
671                     kill(pid, SIGTERM);/* Politely ask the daemon to die */
672                     sleep(1);
673                     kill(pid, SIGKILL);
674                 }
675                 setup_session_dir();
676                 break;
677             }
678             /* --verbose */
679             case 'V':
680                 verbose_print++;
681                 break;
682             /* --verbose-log */
683             case 'l':
684                 verbose_log = strdup(optarg);
685                 break;
686             /* --status */
687             case 't':
688                 show_status = true;
689                 break;
690             default:
691                 usage();
692                 exit(1);
693         }
694     }
695     verbose("list_events = %d\n", list_events);
696     verbose("setup = %d\n", setup);
697 
698     if (list_events) {
699         do_list_events();
700     }
701 
702     if (quick) {
703 #if defined(__i386__) || defined(__x86_64__)
704         process_event("CPU_CLK_UNHALTED");
705 #else
706         process_event("CPU_CYCLES");
707 #endif
708         setup = 1;
709     }
710 
711     if (timer) {
712         setup = 1;
713     }
714 
715     if (reset) {
716         do_reset();
717     }
718 
719     if (show_usage) {
720         usage();
721     }
722 
723     if (setup) {
724         if (do_setup()) {
725             fprintf(stderr, "do_setup failed");
726             exit(1);
727         }
728     }
729 
730     if (strlen(callgraph)) {
731         echo_dev(callgraph, 0, "backtrace_depth", -1);
732     }
733 
734     if (num_events != 0 || timer != 0) {
735         char command[1024];
736         int i;
737 
738         strcpy(command, argv[0]);
739         char* slash = strrchr(command, '/');
740         strcpy(slash ? slash + 1 : command, "oprofiled --session-dir="OP_DATA_DIR);
741 
742 #if defined(__i386__) || defined(__x86_64__)
743         /* Nothing */
744 #elif !defined(WITH_ARM_V7_A)
745         /* Since counter #3 can only handle CPU_CYCLES, check and shuffle the
746          * order a bit so that the maximal number of events can be profiled
747          * simultaneously
748          */
749         if (num_events == 3) {
750             for (i = 0; i < num_events; i++) {
751                 int event_idx = selected_events[i];
752 
753                 if (event_info[event_idx].id == 0xff) {
754                     break;
755                 }
756             }
757 
758             /* No CPU_CYCLES is found */
759             if (i == 3) {
760                 fprintf(stderr, "You can only specify three events if one of "
761                                 "them is CPU_CYCLES\n");
762                 exit(1);
763             }
764             /* Swap CPU_CYCLES to counter #2 (starting from #0)*/
765             else if (i != 2) {
766                 int temp;
767 
768                 temp = selected_events[2];
769                 selected_events[2] = selected_events[i];
770                 selected_events[i] = temp;
771 
772                 temp = selected_counts[2];
773                 selected_counts[2] = selected_counts[i];
774                 selected_counts[i] = temp;
775             }
776         }
777 #endif
778 
779         /* Configure the counters and enable them */
780         for (i = 0; i < num_events; i++) {
781             int event_idx = selected_events[i];
782             int setup_result = 0;
783 
784             if (i == 0) {
785                 snprintf(command + strlen(command), sizeof(command) - strlen(command),
786                         " --events=");
787             } else {
788                 snprintf(command + strlen(command), sizeof(command) - strlen(command), ",");
789             }
790             /* Compose name:id:count:unit_mask:kernel:user, something like
791              * --events=CYCLES_DATA_STALL:2:0:200000:0:1:1,....
792              */
793             snprintf(command + strlen(command), sizeof(command) - strlen(command),
794                      "%s:%d:%d:%d:%d:1:1",
795                      event_info[event_idx].name,
796                      event_info[event_idx].id,
797                      i,
798                      selected_counts[i],
799                      event_info[event_idx].um);
800 
801             setup_result |= echo_dev("1", 0, "user", i);
802             setup_result |= echo_dev("1", 0, "kernel", i);
803             setup_result |= echo_dev(NULL, event_info[event_idx].um, "unit_mask", i);
804             setup_result |= echo_dev("1", 0, "enabled", i);
805             setup_result |= echo_dev(NULL, selected_counts[i], "count", i);
806             setup_result |= echo_dev(NULL, event_info[event_idx].id,
807                                      "event", i);
808             if (setup_result) {
809                 fprintf(stderr, "Counter configuration failed for %s\n",
810                         event_info[event_idx].name);
811                 fprintf(stderr, "Did you do \"opcontrol --setup\" first?\n");
812                 exit(1);
813             }
814         }
815 
816         if (timer == 0) {
817             /* If not in timer mode, disable unused counters */
818             for (i = num_events; i < MAX_EVENTS; i++) {
819                 echo_dev("0", 0, "enabled", i);
820             }
821         } else {
822             /* Timer mode uses empty event list */
823             snprintf(command + strlen(command), sizeof(command) - strlen(command),
824                     " --events=");
825         }
826 
827         snprintf(command + strlen(command), sizeof(command) - strlen(command),
828                 " %s", vmlinux);
829         if (kernel_range[0]) {
830             snprintf(command + strlen(command), sizeof(command) - strlen(command),
831                     " %s", kernel_range);
832         }
833 
834         if (verbose_log) {
835             snprintf(command + strlen(command), sizeof(command) - strlen(command),
836                     " --verbose=%s", verbose_log);
837         }
838 
839         printf("Starting oprofiled...\n");
840         verbose("command: %s\n", command);
841 
842         int rc = system(command);
843         if (rc) {
844             fprintf(stderr, "Failed, oprofile returned exit code: %d\n", rc);
845         } else {
846             sleep(2);
847             printf("Ready\n");
848         }
849     }
850 
851     if (start) {
852         echo_dev("1", 0, "enable", -1);
853         int num = read_num(OP_DATA_DIR"/lock");
854 
855         if (num >= 0) {
856             kill(num, SIGUSR1);
857         }
858     }
859 
860     if (stop) {
861         echo_dev("1", 0, "dump", -1);
862         echo_dev("0", 0, "enable", -1);
863     }
864 
865     if (show_status) {
866         do_status();
867     }
868 }
869