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