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 <dirent.h> 31 #include <sys/stat.h> 32 #include <sys/types.h> 33 #include <sys/wait.h> 34 35 #include "op_config.h" 36 37 #define verbose(fmt...) if (verbose_print) printf(fmt) 38 39 struct event_info { 40 int id; 41 int counters; 42 int um; 43 const char *name; 44 const char *explanation; 45 }; 46 47 #define CTR(n) (1<<(n)) 48 49 #if defined(__i386__) || defined(__x86_64__) 50 struct event_info event_info_arch_perfmon[] = { 51 #include "../events/i386/arch_perfmon/events.h" 52 }; 53 54 #define MAX_EVENTS 2 55 int min_count[MAX_EVENTS] = {60000, 100000}; 56 57 const char *default_event = "CPU_CLK_UNHALTED"; 58 #endif 59 60 #if defined(__arm__) 61 #if !defined(WITH_ARM_V7_A) 62 struct event_info event_info_armv6[] = { 63 #include "../events/arm/armv6/events.h" 64 }; 65 66 #define MAX_EVENTS 3 67 int min_count[MAX_EVENTS] = {150000, 200000, 250000}; 68 69 #else 70 struct event_info event_info_armv7[] = { 71 #include "../events/arm/armv7/events.h" 72 }; 73 74 #define MAX_EVENTS 5 75 int min_count[MAX_EVENTS] = {150000, 20000, 25000, 30000, 35000}; 76 #endif 77 78 const char *default_event = "CPU_CYCLES"; 79 #endif 80 81 #if defined(__mips__) 82 struct event_info event_info_24K[] = { 83 #include "../events/mips/24K/events.h" 84 }; 85 struct event_info event_info_34K[] = { 86 #include "../events/mips/34K/events.h" 87 }; 88 struct event_info event_info_74K[] = { 89 #include "../events/mips/74K/events.h" 90 }; 91 struct event_info event_info_1004K[] = { 92 #include "../events/mips/1004K/events.h" 93 }; 94 95 #define MAX_EVENTS 4 96 int min_count[MAX_EVENTS] = {150000, 20000, 25000, 30000}; 97 98 const char *default_event = "CYCLES"; 99 #endif /* defined(__mips__) */ 100 101 #define ARRAYSZ(x) (sizeof(x)/sizeof((x)[0])) 102 103 struct cpuevents { 104 const char *cpu; 105 struct event_info *event_info; 106 unsigned int nevents; 107 } cpuevents[] = { 108 #if defined(__i386__) || defined(__x86_64__) 109 {"i386/arch_perfmon", event_info_arch_perfmon, ARRAYSZ(event_info_arch_perfmon)}, 110 #endif /* defined(__i386__) || defined(__x86_64__) */ 111 #if defined(__arm__) 112 #if !defined(WITH_ARM_V7_A) 113 {"arm/armv6", event_info_armv6, ARRAYSZ(event_info_armv6)}, 114 #else 115 {"arm/armv7", event_info_armv7, ARRAYSZ(event_info_armv7)}, 116 #endif 117 #endif /* defined(__arm__) */ 118 #if defined(__mips__) 119 {"mips/24K", event_info_24K, ARRAYSZ(event_info_24K)}, 120 {"mips/34K", event_info_34K, ARRAYSZ(event_info_34K)}, 121 {"mips/74K", event_info_74K, ARRAYSZ(event_info_74K)}, 122 {"mips/1004K", event_info_1004K, ARRAYSZ(event_info_1004K)}, 123 #endif /* defined(__mips__) */ 124 }; 125 126 struct cpuevents *cpuevent; 127 #define event_info cpuevent->event_info 128 #define NEVENTS cpuevent->nevents 129 130 int verbose_print; 131 int list_events; 132 int show_usage; 133 int setup; 134 int quick; 135 int timer; 136 int num_events; 137 int start; 138 int stop; 139 int reset; 140 141 int selected_events[MAX_EVENTS]; 142 int selected_counts[MAX_EVENTS]; 143 int max_events; 144 145 char callgraph[8]; 146 char kernel_range[512]; 147 char vmlinux[512]; 148 149 struct option long_options[] = { 150 {"help", 0, &show_usage, 1}, 151 {"list-events", 0, &list_events, 1}, 152 {"reset", 0, &reset, 1}, 153 {"setup", 0, &setup, 1}, 154 {"quick", 0, &quick, 1}, 155 {"timer", 0, &timer, 1}, 156 {"callgraph", 1, 0, 'c'}, 157 {"event", 1, 0, 'e'}, 158 {"vmlinux", 1, 0, 'v'}, 159 {"kernel-range", 1, 0, 'r'}, 160 {"start", 0, &start, 1}, 161 {"stop", 0, &stop, 1}, 162 {"dump", 0, 0, 'd'}, 163 {"shutdown", 0, 0, 'h'}, 164 {"status", 0, 0, 't'}, 165 {"verbose", 0, 0, 'V'}, 166 {"verbose-log", 1, 0, 'l'}, 167 {0, 0, 0, 0}, 168 }; 169 170 171 void usage() 172 { 173 printf("\nopcontrol: usage:\n" 174 " --list-events list event types\n" 175 " --help this message\n" 176 " --verbose show extra status\n" 177 " --verbose-log=lvl set daemon logging verbosity during setup\n" 178 " levels are: all,sfile,arcs,samples,module,misc\n" 179 " --setup setup directories\n" 180 #if defined(__i386__) || defined(__x86_64__) 181 " --quick setup and select CPU_CLK_UNHALTED:60000\n" 182 #elif defined(__arm__) 183 " --quick setup and select CPU_CYCLES:150000\n" 184 #elif defined(__mips__) 185 " --quick setup and select CYCLES:150000\n" 186 #endif 187 " --timer timer-based profiling\n" 188 " --status show configuration\n" 189 " --start start data collection\n" 190 " --stop stop data collection\n" 191 " --reset clears out data from current session\n" 192 " --shutdown kill the oprofile daemon\n" 193 " --callgraph=depth callgraph depth\n" 194 " --event=eventspec\n" 195 " Choose an event. May be specified multiple times.\n" 196 " eventspec is in the form of name[:count], where :\n" 197 " name: event name, see \"opcontrol --list-events\"\n" 198 " count: reset counter value\n" 199 " --vmlinux=file vmlinux kernel image\n" 200 " --kernel-range=start,end\n" 201 " kernel range vma address in hexadecimal\n" 202 ); 203 } 204 205 int setup_device(void) 206 { 207 if (mkdir(OP_DRIVER_BASE, 0755)) { 208 if (errno != EEXIST) { 209 fprintf(stderr, "Cannot create directory "OP_DRIVER_BASE": %s\n", 210 strerror(errno)); 211 return -1; 212 } 213 } 214 215 if (access(OP_DRIVER_BASE"/stats", F_OK)) { 216 if (system("mount -t oprofilefs nodev "OP_DRIVER_BASE)) { 217 return -1; 218 } 219 } 220 221 /* Selecting the event information by cpu_type has only been tested on MIPS */ 222 #if defined(__mips__) 223 /* Use cpu_type to select the events */ 224 int fd = open(OP_DRIVER_BASE "/cpu_type", O_RDONLY); 225 if (fd < 0) { 226 fprintf(stderr, OP_DRIVER_BASE "/cpu_type: %s\n", 227 strerror(errno)); 228 return -1; 229 } 230 231 char buf[512]; 232 int n = read(fd, buf, sizeof(buf)-1); 233 close(fd); 234 if (n < 0) { 235 fprintf(stderr, OP_DRIVER_BASE "/cpu_type: %s\n", 236 strerror(errno)); 237 return -1; 238 } 239 buf[n] = '\0'; 240 for (unsigned int i = 0; i < ARRAYSZ(cpuevents); i++) { 241 if (strcmp(buf, cpuevents[i].cpu) == 0) { 242 cpuevent = &cpuevents[i]; 243 } 244 } 245 if (cpuevent == NULL) { 246 fprintf(stderr, "Unrecognised CPU type %s\n", buf); 247 return -1; 248 } 249 for (max_events = 0; max_events < MAX_EVENTS; max_events++) { 250 snprintf(buf, sizeof(buf), OP_DRIVER_BASE"/%d", max_events); 251 if (access(buf, F_OK) < 0) 252 break; 253 } 254 #else 255 max_events = MAX_EVENTS; 256 cpuevent = &cpuevents[0]; 257 #endif 258 return 0; 259 } 260 261 void setup_session_dir() 262 { 263 if (access(OP_DATA_DIR, F_OK) == 0) 264 system("rm -r "OP_DATA_DIR); 265 266 if (mkdir(OP_DATA_DIR, 0755)) { 267 fprintf(stderr, "Cannot create directory \"%s\": %s\n", 268 OP_DATA_DIR, strerror(errno)); 269 } 270 if (mkdir(OP_DATA_DIR"/samples", 0755)) { 271 fprintf(stderr, "Cannot create directory \"%s\": %s\n", 272 OP_DATA_DIR"/samples", strerror(errno)); 273 } 274 } 275 276 int read_num(const char* file) 277 { 278 char buffer[256]; 279 int fd = open(file, O_RDONLY); 280 if (fd<0) return -1; 281 int rd = read(fd, buffer, sizeof(buffer)-1); 282 buffer[rd] = 0; 283 close(fd); 284 return atoi(buffer); 285 } 286 287 int do_setup() 288 { 289 char dir[1024]; 290 291 /* 292 * Kill the old daemon so that setup can be done more than once to achieve 293 * the same effect as reset. 294 */ 295 int num = read_num(OP_DATA_DIR"/lock"); 296 if (num >= 0) { 297 printf("Terminating the old daemon...\n"); 298 kill(num, SIGTERM); 299 sleep(5); 300 } 301 302 setup_session_dir(); 303 304 return 0; 305 } 306 307 void stringify_counters(char *ctr_string, int ctr_mask) 308 { 309 int i, n, len; 310 char *p = ctr_string; 311 312 *p = '\0'; 313 for (i=0; i<32; ++i) { 314 if (ctr_mask & (1<<i)) { 315 p += sprintf(p, "%d,", i); 316 } 317 } 318 if (p != ctr_string) { 319 *(p-1) = '\0'; /* erase the final comma */ 320 } 321 } 322 323 void do_list_events() 324 { 325 unsigned int i; 326 char ctrs[32*3+1]; 327 328 printf("%-12s | %-30s: %s\n", "counter", "name", "meaning"); 329 printf("----------------------------------------" 330 "--------------------------------------\n"); 331 for (i = 0; i < NEVENTS; i++) { 332 stringify_counters(ctrs, event_info[i].counters); 333 printf("%-12s | %-30s: %s\n", ctrs, event_info[i].name, event_info[i].explanation); 334 } 335 } 336 337 int find_event_idx_from_name(const char *name) 338 { 339 unsigned int i; 340 341 for (i = 0; i < NEVENTS; i++) { 342 if (!strcmp(name, event_info[i].name)) { 343 return i; 344 } 345 } 346 return -1; 347 } 348 349 const char * find_event_name_from_id(int id, int mask) 350 { 351 unsigned int i; 352 353 for (i = 0; i < NEVENTS; i++) { 354 if (event_info[i].id == id && (event_info[i].counters == 0 || (event_info[i].counters & mask))) { 355 return event_info[i].name; 356 } 357 } 358 return "Undefined Event"; 359 } 360 361 int process_event(const char *event_spec) 362 { 363 char event_name[512]; 364 char count_name[512]; 365 unsigned int i; 366 int event_idx; 367 int count_val; 368 369 strncpy(event_name, event_spec, 512); 370 count_name[0] = 0; 371 372 /* First, check if the name is followed by ":" */ 373 for (i = 0; i < strlen(event_name); i++) { 374 if (event_name[i] == 0) { 375 break; 376 } 377 if (event_name[i] == ':') { 378 strncpy(count_name, event_name+i+1, 512); 379 event_name[i] = 0; 380 break; 381 } 382 } 383 event_idx = find_event_idx_from_name(event_name); 384 if (event_idx == -1) { 385 fprintf(stderr, "Unknown event name: %s\n", event_name); 386 return -1; 387 } 388 389 /* 390 * check that the named event is valid for this event counter 391 * 'num_events' represents the cpu internal counter number 392 */ 393 verbose("idx: %d, name: %s, mask: %02x, ctr#: %d\n", 394 event_idx, event_info[event_idx].name, 395 event_info[event_idx].counters, num_events); 396 if (event_info[event_idx].counters != 0 && 397 (event_info[event_idx].counters & CTR(num_events)) == 0) { 398 fprintf(stderr, "Bad event name: %s for counter %d, see --list\n", 399 event_name, num_events); 400 return -1; 401 } 402 403 /* Use default count */ 404 if (count_name[0] == 0) { 405 count_val = min_count[0]; 406 } else { 407 count_val = atoi(count_name); 408 } 409 410 selected_events[num_events] = event_idx; 411 selected_counts[num_events++] = count_val; 412 verbose("event_id is %d\n", event_info[event_idx].id); 413 verbose("count_val is %d\n", count_val); 414 return 0; 415 } 416 417 int echo_dev(const char* str, int val, const char* file, int counter) 418 { 419 char fullname[512]; 420 char content[128]; 421 int fd; 422 423 if (counter >= 0) { 424 snprintf(fullname, 512, OP_DRIVER_BASE"/%d/%s", counter, file); 425 } 426 else { 427 snprintf(fullname, 512, OP_DRIVER_BASE"/%s", file); 428 } 429 fd = open(fullname, O_WRONLY); 430 if (fd<0) { 431 fprintf(stderr, "Cannot open %s: %s\n", fullname, strerror(errno)); 432 return fd; 433 } 434 if (str == 0) { 435 sprintf(content, "%d", val); 436 } 437 else { 438 strncpy(content, str, 128); 439 } 440 verbose("Configure %s (%s)\n", fullname, content); 441 write(fd, content, strlen(content)); 442 close(fd); 443 return 0; 444 } 445 446 void do_status() 447 { 448 int num; 449 char fullname[512]; 450 int i; 451 452 printf("Driver directory: %s\n", OP_DRIVER_BASE); 453 printf("Session directory: %s\n", OP_DATA_DIR); 454 for (i = 0; i < max_events; i++) { 455 sprintf(fullname, OP_DRIVER_BASE"/%d/enabled", i); 456 num = read_num(fullname); 457 if (num > 0) { 458 printf("Counter %d:\n", i); 459 460 /* event name */ 461 sprintf(fullname, OP_DRIVER_BASE"/%d/event", i); 462 num = read_num(fullname); 463 printf(" name: %s\n", find_event_name_from_id(num, CTR(i))); 464 465 /* profile interval */ 466 sprintf(fullname, OP_DRIVER_BASE"/%d/count", i); 467 num = read_num(fullname); 468 printf(" count: %d\n", num); 469 } 470 else { 471 printf("Counter %d disabled\n", i); 472 } 473 } 474 475 num = read_num(OP_DATA_DIR"/lock"); 476 if (num >= 0) { 477 /* Still needs to check if this lock is left-over */ 478 sprintf(fullname, "/proc/%d", num); 479 if (access(fullname, R_OK) != 0) { 480 printf("OProfile daemon exited prematurely - redo setup" 481 " before you continue\n"); 482 return; 483 } 484 else { 485 486 printf("oprofiled pid: %d\n", num); 487 num = read_num(OP_DRIVER_BASE"/enable"); 488 489 printf("profiler is%s running\n", num == 0 ? " not" : ""); 490 491 DIR* dir = opendir(OP_DRIVER_BASE"/stats"); 492 if (dir) { 493 for (struct dirent* dirent; !!(dirent = readdir(dir));) { 494 if (strlen(dirent->d_name) >= 4 && memcmp(dirent->d_name, "cpu", 3) == 0) { 495 char cpupath[256]; 496 strcpy(cpupath, OP_DRIVER_BASE"/stats/"); 497 strcat(cpupath, dirent->d_name); 498 499 strcpy(fullname, cpupath); 500 strcat(fullname, "/sample_received"); 501 num = read_num(fullname); 502 printf(" %s %9u samples received\n", dirent->d_name, num); 503 504 strcpy(fullname, cpupath); 505 strcat(fullname, "/sample_lost_overflow"); 506 num = read_num(fullname); 507 printf(" %s %9u samples lost overflow\n", dirent->d_name, num); 508 509 strcpy(fullname, cpupath); 510 strcat(fullname, "/sample_invalid_eip"); 511 num = read_num(fullname); 512 printf(" %s %9u samples invalid eip\n", dirent->d_name, num); 513 514 strcpy(fullname, cpupath); 515 strcat(fullname, "/backtrace_aborted"); 516 num = read_num(fullname); 517 printf(" %s %9u backtrace aborted\n", dirent->d_name, num); 518 } 519 } 520 closedir(dir); 521 } 522 523 num = read_num(OP_DRIVER_BASE"/backtrace_depth"); 524 printf("backtrace_depth: %u\n", num); 525 } 526 } 527 else { 528 printf("oprofiled is not running\n"); 529 } 530 } 531 532 void do_reset() 533 { 534 /* 535 * Sending SIGHUP will result in the following crash in oprofiled when 536 * profiling subsequent runs: 537 * Stack Trace: 538 * RELADDR FUNCTION FILE:LINE 539 * 00008cd8 add_node+12 oprofilelibdb/db_insert.c:32 540 * 00008d69 odb_update_node_with_offset+60 oprofilelibdb/db_insert.c:102 541 * 542 * However without sending SIGHUP oprofile cannot be restarted successfully. 543 * As a temporary workaround, change do_reset into a no-op for now and kill 544 * the old daemon in do_setup to start all over again as a heavy-weight 545 * reset. 546 */ 547 #if 0 548 int pid = read_num(OP_DATA_DIR"/lock"); 549 if (pid >= 0) 550 kill(pid, SIGHUP); /* HUP makes oprofiled close its sample files */ 551 552 if (access(OP_DATA_DIR"/samples/current", R_OK) == 0) 553 system("rm -r "OP_DATA_DIR"/samples/current"); 554 #endif 555 } 556 557 int main(int argc, char * const argv[]) 558 { 559 int option_index; 560 bool show_status = false; 561 char* verbose_log = NULL; 562 563 /* Initialize default strings */ 564 strcpy(vmlinux, "--no-vmlinux"); 565 strcpy(kernel_range, ""); 566 567 setup_device(); 568 569 while (1) { 570 int c = getopt_long(argc, argv, "c:e:v:r:dhVtl:", long_options, &option_index); 571 if (c == -1) { 572 break; 573 } 574 switch (c) { 575 case 0: 576 break; 577 /* --callgraph */ 578 case 'c': 579 strncpy(callgraph, optarg, sizeof(callgraph)); 580 break; 581 /* --event */ 582 case 'e': 583 if (num_events == MAX_EVENTS) { 584 fprintf(stderr, "More than %d events specified\n", 585 MAX_EVENTS); 586 exit(1); 587 } 588 if (process_event(optarg)) { 589 exit(1); 590 } 591 break; 592 /* --vmlinux */ 593 case 'v': 594 sprintf(vmlinux, "-k %s", optarg); 595 break; 596 /* --kernel-range */ 597 case 'r': 598 sprintf(kernel_range, "-r %s", optarg); 599 break; 600 case 'd': 601 /* --dump */ { 602 int pid = read_num(OP_DATA_DIR"/lock"); 603 echo_dev("1", 0, "dump", -1); 604 break; 605 } 606 /* --shutdown */ 607 case 'h': { 608 int pid = read_num(OP_DATA_DIR"/lock"); 609 if (pid >= 0) { 610 kill(pid, SIGHUP); /* Politely ask the daemon to close files */ 611 sleep(1); 612 kill(pid, SIGTERM);/* Politely ask the daemon to die */ 613 sleep(1); 614 kill(pid, SIGKILL); 615 } 616 setup_session_dir(); 617 break; 618 } 619 /* --verbose */ 620 case 'V': 621 verbose_print++; 622 break; 623 /* --verbose-log */ 624 case 'l': 625 verbose_log = strdup(optarg); 626 break; 627 /* --status */ 628 case 't': 629 show_status = true; 630 break; 631 default: 632 usage(); 633 exit(1); 634 } 635 } 636 verbose("list_events = %d\n", list_events); 637 verbose("setup = %d\n", setup); 638 639 if (list_events) { 640 do_list_events(); 641 } 642 643 if (quick) { 644 process_event(default_event); 645 setup = 1; 646 } 647 648 if (timer) { 649 setup = 1; 650 } 651 652 if (reset) { 653 do_reset(); 654 } 655 656 if (show_usage) { 657 usage(); 658 } 659 660 if (setup) { 661 if (do_setup()) { 662 fprintf(stderr, "do_setup failed"); 663 exit(1); 664 } 665 } 666 667 if (strlen(callgraph)) { 668 echo_dev(callgraph, 0, "backtrace_depth", -1); 669 } 670 671 if (num_events != 0 || timer != 0) { 672 char command[1024]; 673 int i; 674 675 strcpy(command, argv[0]); 676 char* slash = strrchr(command, '/'); 677 strcpy(slash ? slash + 1 : command, "oprofiled --session-dir="OP_DATA_DIR); 678 679 #if defined(__arm__) && !defined(WITH_ARM_V7_A) 680 /* Since counter #3 can only handle CPU_CYCLES, check and shuffle the 681 * order a bit so that the maximal number of events can be profiled 682 * simultaneously 683 */ 684 if (num_events == 3) { 685 for (i = 0; i < num_events; i++) { 686 int event_idx = selected_events[i]; 687 688 if (event_info[event_idx].id == 0xff) { 689 break; 690 } 691 } 692 693 /* No CPU_CYCLES is found */ 694 if (i == 3) { 695 fprintf(stderr, "You can only specify three events if one of " 696 "them is CPU_CYCLES\n"); 697 exit(1); 698 } 699 /* Swap CPU_CYCLES to counter #2 (starting from #0)*/ 700 else if (i != 2) { 701 int temp; 702 703 temp = selected_events[2]; 704 selected_events[2] = selected_events[i]; 705 selected_events[i] = temp; 706 707 temp = selected_counts[2]; 708 selected_counts[2] = selected_counts[i]; 709 selected_counts[i] = temp; 710 } 711 } 712 #endif 713 714 /* Configure the counters and enable them */ 715 for (i = 0; i < num_events; i++) { 716 int event_idx = selected_events[i]; 717 int setup_result = 0; 718 719 if (i == 0) { 720 snprintf(command + strlen(command), sizeof(command) - strlen(command), 721 " --events="); 722 } else { 723 snprintf(command + strlen(command), sizeof(command) - strlen(command), ","); 724 } 725 /* Compose name:id:count:unit_mask:kernel:user, something like 726 * --events=CYCLES_DATA_STALL:2:0:200000:0:1:1,.... 727 */ 728 snprintf(command + strlen(command), sizeof(command) - strlen(command), 729 "%s:%d:%d:%d:%d:1:1", 730 event_info[event_idx].name, 731 event_info[event_idx].id, 732 i, 733 selected_counts[i], 734 event_info[event_idx].um); 735 736 setup_result |= echo_dev("1", 0, "user", i); 737 setup_result |= echo_dev("1", 0, "kernel", i); 738 setup_result |= echo_dev(NULL, event_info[event_idx].um, "unit_mask", i); 739 setup_result |= echo_dev("1", 0, "enabled", i); 740 setup_result |= echo_dev(NULL, selected_counts[i], "count", i); 741 setup_result |= echo_dev(NULL, event_info[event_idx].id, 742 "event", i); 743 if (setup_result) { 744 fprintf(stderr, "Counter configuration failed for %s\n", 745 event_info[event_idx].name); 746 fprintf(stderr, "Did you do \"opcontrol --setup\" first?\n"); 747 exit(1); 748 } 749 } 750 751 if (timer == 0) { 752 /* If not in timer mode, disable unused counters */ 753 for (i = num_events; i < max_events; i++) { 754 echo_dev("0", 0, "enabled", i); 755 } 756 } else { 757 /* Timer mode uses empty event list */ 758 snprintf(command + strlen(command), sizeof(command) - strlen(command), 759 " --events="); 760 } 761 762 snprintf(command + strlen(command), sizeof(command) - strlen(command), 763 " %s", vmlinux); 764 if (kernel_range[0]) { 765 snprintf(command + strlen(command), sizeof(command) - strlen(command), 766 " %s", kernel_range); 767 } 768 769 if (verbose_log) { 770 snprintf(command + strlen(command), sizeof(command) - strlen(command), 771 " --verbose=%s", verbose_log); 772 } 773 774 printf("Starting oprofiled...\n"); 775 verbose("command: %s\n", command); 776 777 int rc = system(command); 778 if (rc) { 779 fprintf(stderr, "Failed, oprofile returned exit code: %d\n", rc); 780 } else { 781 sleep(2); 782 printf("Ready\n"); 783 } 784 } 785 786 if (start) { 787 echo_dev("1", 0, "enable", -1); 788 int num = read_num(OP_DATA_DIR"/lock"); 789 790 if (num >= 0) { 791 kill(num, SIGUSR1); 792 } 793 } 794 795 if (stop) { 796 echo_dev("1", 0, "dump", -1); 797 echo_dev("0", 0, "enable", -1); 798 } 799 800 if (show_status) { 801 do_status(); 802 } 803 } 804