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 struct event_info {
     40     int id;
     41     int counters;
     42     int um;
     43     const char *name;
     44     const char *explanation;
     45 };
     46 
     47 #define CTR(n)  (1<<(n))
     48 
     49 #if defined(__i386__) || defined(__x86_64__)
     50 struct event_info event_info_arch_perfmon[] = {
     51     #include "../events/i386/arch_perfmon/events.h"
     52 };
     53 
     54 #define MAX_EVENTS 2
     55 int min_count[MAX_EVENTS] = {60000, 100000};
     56 
     57 const char *default_event = "CPU_CLK_UNHALTED";
     58 #endif
     59 
     60 #if defined(__arm__)
     61 #if !defined(WITH_ARM_V7_A)
     62 struct event_info event_info_armv6[] = {
     63     #include "../events/arm/armv6/events.h"
     64 };
     65 
     66 #define MAX_EVENTS 3
     67 int min_count[MAX_EVENTS] = {150000, 200000, 250000};
     68 
     69 #else
     70 struct event_info event_info_armv7[] = {
     71     #include "../events/arm/armv7/events.h"
     72 };
     73 
     74 #define MAX_EVENTS 5
     75 int min_count[MAX_EVENTS] = {150000, 20000, 25000, 30000, 35000};
     76 #endif
     77 
     78 const char *default_event = "CPU_CYCLES";
     79 #endif
     80 
     81 #if defined(__mips__)
     82 struct event_info event_info_24K[] = {
     83     #include "../events/mips/24K/events.h"
     84 };
     85 struct event_info event_info_34K[] = {
     86     #include "../events/mips/34K/events.h"
     87 };
     88 struct event_info event_info_74K[] = {
     89     #include "../events/mips/74K/events.h"
     90 };
     91 struct event_info event_info_1004K[] = {
     92     #include "../events/mips/1004K/events.h"
     93 };
     94 
     95 #define MAX_EVENTS 4
     96 int min_count[MAX_EVENTS] = {150000, 20000, 25000, 30000};
     97 
     98 const char *default_event = "CYCLES";
     99 #endif /* defined(__mips__) */
    100 
    101 #define ARRAYSZ(x) (sizeof(x)/sizeof((x)[0]))
    102 
    103 struct cpuevents {
    104     const char *cpu;
    105     struct event_info *event_info;
    106     unsigned int nevents;
    107 } cpuevents[] = {
    108 #if defined(__i386__) || defined(__x86_64__)
    109     {"i386/arch_perfmon", event_info_arch_perfmon, ARRAYSZ(event_info_arch_perfmon)},
    110 #endif /* defined(__i386__) || defined(__x86_64__) */
    111 #if defined(__arm__)
    112 #if !defined(WITH_ARM_V7_A)
    113     {"arm/armv6", event_info_armv6, ARRAYSZ(event_info_armv6)},
    114 #else
    115     {"arm/armv7", event_info_armv7, ARRAYSZ(event_info_armv7)},
    116 #endif
    117 #endif /* defined(__arm__) */
    118 #if defined(__mips__)
    119     {"mips/24K", event_info_24K, ARRAYSZ(event_info_24K)},
    120     {"mips/34K", event_info_34K, ARRAYSZ(event_info_34K)},
    121     {"mips/74K", event_info_74K, ARRAYSZ(event_info_74K)},
    122     {"mips/1004K", event_info_1004K, ARRAYSZ(event_info_1004K)},
    123 #endif /* defined(__mips__) */
    124 };
    125 
    126 struct cpuevents *cpuevent;
    127 #define event_info cpuevent->event_info
    128 #define NEVENTS cpuevent->nevents
    129 
    130 int verbose_print;
    131 int list_events;
    132 int show_usage;
    133 int setup;
    134 int quick;
    135 int timer;
    136 int num_events;
    137 int start;
    138 int stop;
    139 int reset;
    140 
    141 int selected_events[MAX_EVENTS];
    142 int selected_counts[MAX_EVENTS];
    143 int max_events;
    144 
    145 char callgraph[8];
    146 char kernel_range[512];
    147 char vmlinux[512];
    148 
    149 struct option long_options[] = {
    150     {"help", 0, &show_usage, 1},
    151     {"list-events", 0, &list_events, 1},
    152     {"reset", 0, &reset, 1},
    153     {"setup", 0, &setup, 1},
    154     {"quick", 0, &quick, 1},
    155     {"timer", 0, &timer, 1},
    156     {"callgraph", 1, 0, 'c'},
    157     {"event", 1, 0, 'e'},
    158     {"vmlinux", 1, 0, 'v'},
    159     {"kernel-range", 1, 0, 'r'},
    160     {"start", 0, &start, 1},
    161     {"stop", 0, &stop, 1},
    162     {"dump", 0, 0, 'd'},
    163     {"shutdown", 0, 0, 'h'},
    164     {"status", 0, 0, 't'},
    165     {"verbose", 0, 0, 'V'},
    166     {"verbose-log", 1, 0, 'l'},
    167     {0, 0, 0, 0},
    168 };
    169 
    170 
    171 void usage()
    172 {
    173     printf("\nopcontrol: usage:\n"
    174            "   --list-events    list event types\n"
    175            "   --help           this message\n"
    176            "   --verbose        show extra status\n"
    177            "   --verbose-log=lvl set daemon logging verbosity during setup\n"
    178            "                    levels are: all,sfile,arcs,samples,module,misc\n"
    179            "   --setup          setup directories\n"
    180 #if defined(__i386__) || defined(__x86_64__)
    181            "   --quick          setup and select CPU_CLK_UNHALTED:60000\n"
    182 #elif defined(__arm__)
    183            "   --quick          setup and select CPU_CYCLES:150000\n"
    184 #elif defined(__mips__)
    185            "   --quick          setup and select CYCLES:150000\n"
    186 #endif
    187            "   --timer          timer-based profiling\n"
    188            "   --status         show configuration\n"
    189            "   --start          start data collection\n"
    190            "   --stop           stop data collection\n"
    191            "   --reset          clears out data from current session\n"
    192            "   --shutdown       kill the oprofile daemon\n"
    193            "   --callgraph=depth callgraph depth\n"
    194            "   --event=eventspec\n"
    195            "      Choose an event. May be specified multiple times.\n"
    196            "      eventspec is in the form of name[:count], where :\n"
    197            "        name:  event name, see \"opcontrol --list-events\"\n"
    198            "        count: reset counter value\n"
    199            "   --vmlinux=file   vmlinux kernel image\n"
    200            "   --kernel-range=start,end\n"
    201            "                    kernel range vma address in hexadecimal\n"
    202           );
    203 }
    204 
    205 int setup_device(void)
    206 {
    207     if (mkdir(OP_DRIVER_BASE, 0755)) {
    208         if (errno != EEXIST) {
    209             fprintf(stderr, "Cannot create directory "OP_DRIVER_BASE": %s\n",
    210                     strerror(errno));
    211             return -1;
    212         }
    213     }
    214 
    215     if (access(OP_DRIVER_BASE"/stats", F_OK)) {
    216         if (system("mount -t oprofilefs nodev "OP_DRIVER_BASE)) {
    217             return -1;
    218         }
    219     }
    220 
    221     /* Selecting the event information by cpu_type has only been tested on MIPS */
    222 #if defined(__mips__)
    223     /* Use cpu_type to select the events */
    224     int fd = open(OP_DRIVER_BASE "/cpu_type", O_RDONLY);
    225     if (fd < 0) {
    226 	fprintf(stderr, OP_DRIVER_BASE "/cpu_type: %s\n",
    227 		strerror(errno));
    228 	return -1;
    229     }
    230 
    231     char buf[512];
    232     int n = read(fd, buf, sizeof(buf)-1);
    233     close(fd);
    234     if (n < 0) {
    235 	fprintf(stderr, OP_DRIVER_BASE "/cpu_type: %s\n",
    236 		strerror(errno));
    237 	return -1;
    238     }
    239     buf[n] = '\0';
    240     for (unsigned int i = 0; i < ARRAYSZ(cpuevents); i++) {
    241 	if (strcmp(buf, cpuevents[i].cpu) == 0) {
    242 	    cpuevent = &cpuevents[i];
    243 	}
    244     }
    245     if (cpuevent == NULL) {
    246 	fprintf(stderr, "Unrecognised CPU type %s\n", buf);
    247 	return -1;
    248     }
    249     for (max_events = 0; max_events < MAX_EVENTS; max_events++) {
    250 	snprintf(buf, sizeof(buf), OP_DRIVER_BASE"/%d", max_events);
    251 	if (access(buf, F_OK) < 0)
    252 	    break;
    253     }
    254 #else
    255     max_events = MAX_EVENTS;
    256     cpuevent = &cpuevents[0];
    257 #endif
    258     return 0;
    259 }
    260 
    261 void setup_session_dir()
    262 {
    263     if (access(OP_DATA_DIR, F_OK) == 0)
    264         system("rm -r "OP_DATA_DIR);
    265 
    266     if (mkdir(OP_DATA_DIR, 0755)) {
    267         fprintf(stderr, "Cannot create directory \"%s\": %s\n",
    268                 OP_DATA_DIR, strerror(errno));
    269     }
    270     if (mkdir(OP_DATA_DIR"/samples", 0755)) {
    271         fprintf(stderr, "Cannot create directory \"%s\": %s\n",
    272                 OP_DATA_DIR"/samples", strerror(errno));
    273     }
    274 }
    275 
    276 int read_num(const char* file)
    277 {
    278     char buffer[256];
    279     int fd = open(file, O_RDONLY);
    280     if (fd<0) return -1;
    281     int rd = read(fd, buffer, sizeof(buffer)-1);
    282     buffer[rd] = 0;
    283     close(fd);
    284     return atoi(buffer);
    285 }
    286 
    287 int do_setup()
    288 {
    289     char dir[1024];
    290 
    291     /*
    292      * Kill the old daemon so that setup can be done more than once to achieve
    293      * the same effect as reset.
    294      */
    295     int num = read_num(OP_DATA_DIR"/lock");
    296     if (num >= 0) {
    297         printf("Terminating the old daemon...\n");
    298         kill(num, SIGTERM);
    299         sleep(5);
    300     }
    301 
    302     setup_session_dir();
    303 
    304     return 0;
    305 }
    306 
    307 void stringify_counters(char *ctr_string, int ctr_mask)
    308 {
    309     int i, n, len;
    310     char *p = ctr_string;
    311 
    312     *p = '\0';
    313     for (i=0; i<32; ++i) {
    314         if (ctr_mask & (1<<i)) {
    315 	    p += sprintf(p, "%d,", i);
    316 	}
    317     }
    318     if (p != ctr_string) {
    319         *(p-1) = '\0';  /* erase the final comma */
    320     }
    321 }
    322 
    323 void do_list_events()
    324 {
    325     unsigned int i;
    326     char ctrs[32*3+1];
    327 
    328     printf("%-12s | %-30s: %s\n", "counter", "name", "meaning");
    329     printf("----------------------------------------"
    330            "--------------------------------------\n");
    331     for (i = 0; i < NEVENTS; i++) {
    332         stringify_counters(ctrs, event_info[i].counters);
    333         printf("%-12s | %-30s: %s\n", ctrs, event_info[i].name, event_info[i].explanation);
    334     }
    335 }
    336 
    337 int find_event_idx_from_name(const char *name)
    338 {
    339     unsigned int i;
    340 
    341     for (i = 0; i < NEVENTS; i++) {
    342         if (!strcmp(name, event_info[i].name)) {
    343             return i;
    344         }
    345     }
    346     return -1;
    347 }
    348 
    349 const char * find_event_name_from_id(int id, int mask)
    350 {
    351     unsigned int i;
    352 
    353     for (i = 0; i < NEVENTS; i++) {
    354 	if (event_info[i].id == id && (event_info[i].counters == 0 || (event_info[i].counters & mask))) {
    355             return event_info[i].name;
    356         }
    357     }
    358     return "Undefined Event";
    359 }
    360 
    361 int process_event(const char *event_spec)
    362 {
    363     char event_name[512];
    364     char count_name[512];
    365     unsigned int i;
    366     int event_idx;
    367     int count_val;
    368 
    369     strncpy(event_name, event_spec, 512);
    370     count_name[0] = 0;
    371 
    372     /* First, check if the name is followed by ":" */
    373     for (i = 0; i < strlen(event_name); i++) {
    374         if (event_name[i] == 0) {
    375             break;
    376         }
    377         if (event_name[i] == ':') {
    378             strncpy(count_name, event_name+i+1, 512);
    379             event_name[i] = 0;
    380             break;
    381         }
    382     }
    383     event_idx = find_event_idx_from_name(event_name);
    384     if (event_idx == -1) {
    385         fprintf(stderr, "Unknown event name: %s\n", event_name);
    386         return -1;
    387     }
    388 
    389     /*
    390      * check that the named event is valid for this event counter
    391      * 'num_events' represents the cpu internal counter number
    392      */
    393     verbose("idx: %d, name: %s, mask: %02x, ctr#: %d\n",
    394             event_idx, event_info[event_idx].name,
    395             event_info[event_idx].counters, num_events);
    396     if (event_info[event_idx].counters != 0 &&
    397 	(event_info[event_idx].counters & CTR(num_events)) == 0) {
    398 	fprintf(stderr, "Bad event name: %s for counter %d, see --list\n",
    399 		event_name, num_events);
    400 	return -1;
    401     }
    402 
    403     /* Use default count */
    404     if (count_name[0] == 0) {
    405         count_val = min_count[0];
    406     } else {
    407         count_val = atoi(count_name);
    408     }
    409 
    410     selected_events[num_events] = event_idx;
    411     selected_counts[num_events++] = count_val;
    412     verbose("event_id is %d\n", event_info[event_idx].id);
    413     verbose("count_val is %d\n", count_val);
    414     return 0;
    415 }
    416 
    417 int echo_dev(const char* str, int val, const char* file, int counter)
    418 {
    419     char fullname[512];
    420     char content[128];
    421     int fd;
    422 
    423     if (counter >= 0) {
    424         snprintf(fullname, 512, OP_DRIVER_BASE"/%d/%s", counter, file);
    425     }
    426     else {
    427         snprintf(fullname, 512, OP_DRIVER_BASE"/%s", file);
    428     }
    429     fd = open(fullname, O_WRONLY);
    430     if (fd<0) {
    431         fprintf(stderr, "Cannot open %s: %s\n", fullname, strerror(errno));
    432         return fd;
    433     }
    434     if (str == 0) {
    435         sprintf(content, "%d", val);
    436     }
    437     else {
    438         strncpy(content, str, 128);
    439     }
    440     verbose("Configure %s (%s)\n", fullname, content);
    441     write(fd, content, strlen(content));
    442     close(fd);
    443     return 0;
    444 }
    445 
    446 void do_status()
    447 {
    448     int num;
    449     char fullname[512];
    450     int i;
    451 
    452     printf("Driver directory: %s\n", OP_DRIVER_BASE);
    453     printf("Session directory: %s\n", OP_DATA_DIR);
    454     for (i = 0; i < max_events; i++) {
    455         sprintf(fullname, OP_DRIVER_BASE"/%d/enabled", i);
    456         num = read_num(fullname);
    457         if (num > 0) {
    458             printf("Counter %d:\n", i);
    459 
    460             /* event name */
    461             sprintf(fullname, OP_DRIVER_BASE"/%d/event", i);
    462             num = read_num(fullname);
    463             printf("    name: %s\n", find_event_name_from_id(num, CTR(i)));
    464 
    465             /* profile interval */
    466             sprintf(fullname, OP_DRIVER_BASE"/%d/count", i);
    467             num = read_num(fullname);
    468             printf("    count: %d\n", num);
    469         }
    470         else {
    471             printf("Counter %d disabled\n", i);
    472         }
    473     }
    474 
    475     num = read_num(OP_DATA_DIR"/lock");
    476     if (num >= 0) {
    477         /* Still needs to check if this lock is left-over */
    478         sprintf(fullname, "/proc/%d", num);
    479         if (access(fullname, R_OK) != 0) {
    480             printf("OProfile daemon exited prematurely - redo setup"
    481                    " before you continue\n");
    482             return;
    483         }
    484         else {
    485 
    486             printf("oprofiled pid: %d\n", num);
    487             num = read_num(OP_DRIVER_BASE"/enable");
    488 
    489             printf("profiler is%s running\n", num == 0 ? " not" : "");
    490 
    491             DIR* dir = opendir(OP_DRIVER_BASE"/stats");
    492             if (dir) {
    493                 for (struct dirent* dirent; !!(dirent = readdir(dir));) {
    494                     if (strlen(dirent->d_name) >= 4 && memcmp(dirent->d_name, "cpu", 3) == 0) {
    495                         char cpupath[256];
    496                         strcpy(cpupath, OP_DRIVER_BASE"/stats/");
    497                         strcat(cpupath, dirent->d_name);
    498 
    499                         strcpy(fullname, cpupath);
    500                         strcat(fullname, "/sample_received");
    501                         num = read_num(fullname);
    502                         printf("  %s %9u samples received\n", dirent->d_name, num);
    503 
    504                         strcpy(fullname, cpupath);
    505                         strcat(fullname, "/sample_lost_overflow");
    506                         num = read_num(fullname);
    507                         printf("  %s %9u samples lost overflow\n", dirent->d_name, num);
    508 
    509                         strcpy(fullname, cpupath);
    510                         strcat(fullname, "/sample_invalid_eip");
    511                         num = read_num(fullname);
    512                         printf("  %s %9u samples invalid eip\n", dirent->d_name, num);
    513 
    514                         strcpy(fullname, cpupath);
    515                         strcat(fullname, "/backtrace_aborted");
    516                         num = read_num(fullname);
    517                         printf("  %s %9u backtrace aborted\n", dirent->d_name, num);
    518                     }
    519                 }
    520                 closedir(dir);
    521             }
    522 
    523             num = read_num(OP_DRIVER_BASE"/backtrace_depth");
    524             printf("backtrace_depth: %u\n", num);
    525         }
    526     }
    527     else {
    528         printf("oprofiled is not running\n");
    529     }
    530 }
    531 
    532 void do_reset()
    533 {
    534     /*
    535      * Sending SIGHUP will result in the following crash in oprofiled when
    536      * profiling subsequent runs:
    537      * Stack Trace:
    538      * RELADDR   FUNCTION                         FILE:LINE
    539      *   00008cd8  add_node+12                    oprofilelibdb/db_insert.c:32
    540      *   00008d69  odb_update_node_with_offset+60 oprofilelibdb/db_insert.c:102
    541      *
    542      * However without sending SIGHUP oprofile cannot be restarted successfully.
    543      * As a temporary workaround, change do_reset into a no-op for now and kill
    544      * the old daemon in do_setup to start all over again as a heavy-weight
    545      * reset.
    546      */
    547 #if 0
    548     int pid = read_num(OP_DATA_DIR"/lock");
    549     if (pid >= 0)
    550         kill(pid, SIGHUP);  /* HUP makes oprofiled close its sample files */
    551 
    552     if (access(OP_DATA_DIR"/samples/current", R_OK) == 0)
    553       system("rm -r "OP_DATA_DIR"/samples/current");
    554 #endif
    555 }
    556 
    557 int main(int argc, char * const argv[])
    558 {
    559     int option_index;
    560     bool show_status = false;
    561     char* verbose_log = NULL;
    562 
    563     /* Initialize default strings */
    564     strcpy(vmlinux, "--no-vmlinux");
    565     strcpy(kernel_range, "");
    566 
    567     setup_device();
    568 
    569     while (1) {
    570         int c = getopt_long(argc, argv, "c:e:v:r:dhVtl:", long_options, &option_index);
    571         if (c == -1) {
    572             break;
    573         }
    574         switch (c) {
    575             case 0:
    576                 break;
    577             /* --callgraph */
    578             case 'c':
    579                 strncpy(callgraph, optarg, sizeof(callgraph));
    580                 break;
    581             /* --event */
    582             case 'e':
    583                 if (num_events == MAX_EVENTS) {
    584                     fprintf(stderr, "More than %d events specified\n",
    585                             MAX_EVENTS);
    586                     exit(1);
    587                 }
    588                 if (process_event(optarg)) {
    589                     exit(1);
    590                 }
    591                 break;
    592             /* --vmlinux */
    593             case 'v':
    594                 sprintf(vmlinux, "-k %s", optarg);
    595                 break;
    596             /* --kernel-range */
    597             case 'r':
    598                 sprintf(kernel_range, "-r %s", optarg);
    599                 break;
    600             case 'd':
    601             /* --dump */ {
    602                 int pid = read_num(OP_DATA_DIR"/lock");
    603                 echo_dev("1", 0, "dump", -1);
    604                 break;
    605             }
    606             /* --shutdown */
    607             case 'h': {
    608                 int pid = read_num(OP_DATA_DIR"/lock");
    609                 if (pid >= 0) {
    610                     kill(pid, SIGHUP); /* Politely ask the daemon to close files */
    611                     sleep(1);
    612                     kill(pid, SIGTERM);/* Politely ask the daemon to die */
    613                     sleep(1);
    614                     kill(pid, SIGKILL);
    615                 }
    616                 setup_session_dir();
    617                 break;
    618             }
    619             /* --verbose */
    620             case 'V':
    621                 verbose_print++;
    622                 break;
    623             /* --verbose-log */
    624             case 'l':
    625                 verbose_log = strdup(optarg);
    626                 break;
    627             /* --status */
    628             case 't':
    629                 show_status = true;
    630                 break;
    631             default:
    632                 usage();
    633                 exit(1);
    634         }
    635     }
    636     verbose("list_events = %d\n", list_events);
    637     verbose("setup = %d\n", setup);
    638 
    639     if (list_events) {
    640         do_list_events();
    641     }
    642 
    643     if (quick) {
    644         process_event(default_event);
    645         setup = 1;
    646     }
    647 
    648     if (timer) {
    649         setup = 1;
    650     }
    651 
    652     if (reset) {
    653         do_reset();
    654     }
    655 
    656     if (show_usage) {
    657         usage();
    658     }
    659 
    660     if (setup) {
    661         if (do_setup()) {
    662             fprintf(stderr, "do_setup failed");
    663             exit(1);
    664         }
    665     }
    666 
    667     if (strlen(callgraph)) {
    668         echo_dev(callgraph, 0, "backtrace_depth", -1);
    669     }
    670 
    671     if (num_events != 0 || timer != 0) {
    672         char command[1024];
    673         int i;
    674 
    675         strcpy(command, argv[0]);
    676         char* slash = strrchr(command, '/');
    677         strcpy(slash ? slash + 1 : command, "oprofiled --session-dir="OP_DATA_DIR);
    678 
    679 #if defined(__arm__) && !defined(WITH_ARM_V7_A)
    680         /* Since counter #3 can only handle CPU_CYCLES, check and shuffle the
    681          * order a bit so that the maximal number of events can be profiled
    682          * simultaneously
    683          */
    684         if (num_events == 3) {
    685             for (i = 0; i < num_events; i++) {
    686                 int event_idx = selected_events[i];
    687 
    688                 if (event_info[event_idx].id == 0xff) {
    689                     break;
    690                 }
    691             }
    692 
    693             /* No CPU_CYCLES is found */
    694             if (i == 3) {
    695                 fprintf(stderr, "You can only specify three events if one of "
    696                                 "them is CPU_CYCLES\n");
    697                 exit(1);
    698             }
    699             /* Swap CPU_CYCLES to counter #2 (starting from #0)*/
    700             else if (i != 2) {
    701                 int temp;
    702 
    703                 temp = selected_events[2];
    704                 selected_events[2] = selected_events[i];
    705                 selected_events[i] = temp;
    706 
    707                 temp = selected_counts[2];
    708                 selected_counts[2] = selected_counts[i];
    709                 selected_counts[i] = temp;
    710             }
    711         }
    712 #endif
    713 
    714         /* Configure the counters and enable them */
    715         for (i = 0; i < num_events; i++) {
    716             int event_idx = selected_events[i];
    717             int setup_result = 0;
    718 
    719             if (i == 0) {
    720                 snprintf(command + strlen(command), sizeof(command) - strlen(command),
    721                         " --events=");
    722             } else {
    723                 snprintf(command + strlen(command), sizeof(command) - strlen(command), ",");
    724             }
    725             /* Compose name:id:count:unit_mask:kernel:user, something like
    726              * --events=CYCLES_DATA_STALL:2:0:200000:0:1:1,....
    727              */
    728             snprintf(command + strlen(command), sizeof(command) - strlen(command),
    729                      "%s:%d:%d:%d:%d:1:1",
    730                      event_info[event_idx].name,
    731                      event_info[event_idx].id,
    732                      i,
    733                      selected_counts[i],
    734                      event_info[event_idx].um);
    735 
    736             setup_result |= echo_dev("1", 0, "user", i);
    737             setup_result |= echo_dev("1", 0, "kernel", i);
    738             setup_result |= echo_dev(NULL, event_info[event_idx].um, "unit_mask", i);
    739             setup_result |= echo_dev("1", 0, "enabled", i);
    740             setup_result |= echo_dev(NULL, selected_counts[i], "count", i);
    741             setup_result |= echo_dev(NULL, event_info[event_idx].id,
    742                                      "event", i);
    743             if (setup_result) {
    744                 fprintf(stderr, "Counter configuration failed for %s\n",
    745                         event_info[event_idx].name);
    746                 fprintf(stderr, "Did you do \"opcontrol --setup\" first?\n");
    747                 exit(1);
    748             }
    749         }
    750 
    751         if (timer == 0) {
    752             /* If not in timer mode, disable unused counters */
    753             for (i = num_events; i < max_events; i++) {
    754                 echo_dev("0", 0, "enabled", i);
    755             }
    756         } else {
    757             /* Timer mode uses empty event list */
    758             snprintf(command + strlen(command), sizeof(command) - strlen(command),
    759                     " --events=");
    760         }
    761 
    762         snprintf(command + strlen(command), sizeof(command) - strlen(command),
    763                 " %s", vmlinux);
    764         if (kernel_range[0]) {
    765             snprintf(command + strlen(command), sizeof(command) - strlen(command),
    766                     " %s", kernel_range);
    767         }
    768 
    769         if (verbose_log) {
    770             snprintf(command + strlen(command), sizeof(command) - strlen(command),
    771                     " --verbose=%s", verbose_log);
    772         }
    773 
    774         printf("Starting oprofiled...\n");
    775         verbose("command: %s\n", command);
    776 
    777         int rc = system(command);
    778         if (rc) {
    779             fprintf(stderr, "Failed, oprofile returned exit code: %d\n", rc);
    780         } else {
    781             sleep(2);
    782             printf("Ready\n");
    783         }
    784     }
    785 
    786     if (start) {
    787         echo_dev("1", 0, "enable", -1);
    788         int num = read_num(OP_DATA_DIR"/lock");
    789 
    790         if (num >= 0) {
    791             kill(num, SIGUSR1);
    792         }
    793     }
    794 
    795     if (stop) {
    796         echo_dev("1", 0, "dump", -1);
    797         echo_dev("0", 0, "enable", -1);
    798     }
    799 
    800     if (show_status) {
    801         do_status();
    802     }
    803 }
    804