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