Home | History | Annotate | Download | only in opcontrol
      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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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