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
45int min_count[MAX_EVENTS] = {60000, 100000};
46#elif !defined(WITH_ARM_V7_A)
47#define MAX_EVENTS 3
48int min_count[MAX_EVENTS] = {150000, 200000, 250000};
49#else
50#define MAX_EVENTS 5
51int min_count[MAX_EVENTS] = {150000, 20000, 25000, 30000, 35000};
52#endif
53
54int verbose_print;
55int list_events;
56int show_usage;
57int setup;
58int quick;
59int timer;
60int num_events;
61int start;
62int stop;
63int reset;
64
65int selected_events[MAX_EVENTS];
66int selected_counts[MAX_EVENTS];
67
68char callgraph[8];
69char kernel_range[512];
70char vmlinux[512];
71
72struct 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
93struct 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
293void 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
325void 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
345int 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
356int 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
389void 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
401int 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
413const 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
425int 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
467int 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
496void 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
585void 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
618int 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