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