opcontrol.cpp revision a9404b820caf434bba3c3c54c5e786a0eb9ebedb
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, 20000, 25000, 30000, 35000};
49#endif
50
51int verbose_print;
52int list_events;
53int show_usage;
54int setup;
55int quick;
56int timer;
57int num_events;
58int start;
59int stop;
60int reset;
61
62int selected_events[MAX_EVENTS];
63int selected_counts[MAX_EVENTS];
64
65char callgraph[8];
66char kernel_range[512];
67char vmlinux[512];
68
69struct 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
89struct 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
289void 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
319void 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, 0755)) {
330        fprintf(stderr, "Cannot create directory \"%s\": %s\n",
331                OP_DATA_DIR, strerror(errno));
332    }
333    if (mkdir(OP_DATA_DIR"/samples", 0755)) {
334        fprintf(stderr, "Cannot create directory \"%s\": %s\n",
335                OP_DATA_DIR"/samples", strerror(errno));
336    }
337}
338
339int do_setup()
340{
341    char dir[1024];
342
343    setup_session_dir();
344
345    if (mkdir(OP_DRIVER_BASE, 0755)) {
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
356void 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
368int 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
380const 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
392int 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
434int 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
463int 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
473void 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
537void 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
549int 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