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