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