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