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 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 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 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 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 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 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 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 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 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 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 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 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