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