Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.37-rc4 826 lines 18 kB view raw
1#include "builtin.h" 2 3#include "perf.h" 4#include "util/cache.h" 5#include "util/debug.h" 6#include "util/exec_cmd.h" 7#include "util/header.h" 8#include "util/parse-options.h" 9#include "util/session.h" 10#include "util/symbol.h" 11#include "util/thread.h" 12#include "util/trace-event.h" 13#include "util/parse-options.h" 14#include "util/util.h" 15 16static char const *script_name; 17static char const *generate_script_lang; 18static bool debug_mode; 19static u64 last_timestamp; 20static u64 nr_unordered; 21extern const struct option record_options[]; 22 23static int default_start_script(const char *script __unused, 24 int argc __unused, 25 const char **argv __unused) 26{ 27 return 0; 28} 29 30static int default_stop_script(void) 31{ 32 return 0; 33} 34 35static int default_generate_script(const char *outfile __unused) 36{ 37 return 0; 38} 39 40static struct scripting_ops default_scripting_ops = { 41 .start_script = default_start_script, 42 .stop_script = default_stop_script, 43 .process_event = print_event, 44 .generate_script = default_generate_script, 45}; 46 47static struct scripting_ops *scripting_ops; 48 49static void setup_scripting(void) 50{ 51 setup_perl_scripting(); 52 setup_python_scripting(); 53 54 scripting_ops = &default_scripting_ops; 55} 56 57static int cleanup_scripting(void) 58{ 59 pr_debug("\nperf trace script stopped\n"); 60 61 return scripting_ops->stop_script(); 62} 63 64static char const *input_name = "perf.data"; 65 66static int process_sample_event(event_t *event, struct perf_session *session) 67{ 68 struct sample_data data; 69 struct thread *thread; 70 71 memset(&data, 0, sizeof(data)); 72 data.time = -1; 73 data.cpu = -1; 74 data.period = 1; 75 76 event__parse_sample(event, session->sample_type, &data); 77 78 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, 79 data.pid, data.tid, data.ip, data.period); 80 81 thread = perf_session__findnew(session, event->ip.pid); 82 if (thread == NULL) { 83 pr_debug("problem processing %d event, skipping it.\n", 84 event->header.type); 85 return -1; 86 } 87 88 if (session->sample_type & PERF_SAMPLE_RAW) { 89 if (debug_mode) { 90 if (data.time < last_timestamp) { 91 pr_err("Samples misordered, previous: %llu " 92 "this: %llu\n", last_timestamp, 93 data.time); 94 nr_unordered++; 95 } 96 last_timestamp = data.time; 97 return 0; 98 } 99 /* 100 * FIXME: better resolve from pid from the struct trace_entry 101 * field, although it should be the same than this perf 102 * event pid 103 */ 104 scripting_ops->process_event(data.cpu, data.raw_data, 105 data.raw_size, 106 data.time, thread->comm); 107 } 108 109 session->hists.stats.total_period += data.period; 110 return 0; 111} 112 113static u64 nr_lost; 114 115static int process_lost_event(event_t *event, struct perf_session *session __used) 116{ 117 nr_lost += event->lost.lost; 118 119 return 0; 120} 121 122static struct perf_event_ops event_ops = { 123 .sample = process_sample_event, 124 .comm = event__process_comm, 125 .attr = event__process_attr, 126 .event_type = event__process_event_type, 127 .tracing_data = event__process_tracing_data, 128 .build_id = event__process_build_id, 129 .lost = process_lost_event, 130 .ordered_samples = true, 131}; 132 133extern volatile int session_done; 134 135static void sig_handler(int sig __unused) 136{ 137 session_done = 1; 138} 139 140static int __cmd_trace(struct perf_session *session) 141{ 142 int ret; 143 144 signal(SIGINT, sig_handler); 145 146 ret = perf_session__process_events(session, &event_ops); 147 148 if (debug_mode) { 149 pr_err("Misordered timestamps: %llu\n", nr_unordered); 150 pr_err("Lost events: %llu\n", nr_lost); 151 } 152 153 return ret; 154} 155 156struct script_spec { 157 struct list_head node; 158 struct scripting_ops *ops; 159 char spec[0]; 160}; 161 162LIST_HEAD(script_specs); 163 164static struct script_spec *script_spec__new(const char *spec, 165 struct scripting_ops *ops) 166{ 167 struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1); 168 169 if (s != NULL) { 170 strcpy(s->spec, spec); 171 s->ops = ops; 172 } 173 174 return s; 175} 176 177static void script_spec__delete(struct script_spec *s) 178{ 179 free(s->spec); 180 free(s); 181} 182 183static void script_spec__add(struct script_spec *s) 184{ 185 list_add_tail(&s->node, &script_specs); 186} 187 188static struct script_spec *script_spec__find(const char *spec) 189{ 190 struct script_spec *s; 191 192 list_for_each_entry(s, &script_specs, node) 193 if (strcasecmp(s->spec, spec) == 0) 194 return s; 195 return NULL; 196} 197 198static struct script_spec *script_spec__findnew(const char *spec, 199 struct scripting_ops *ops) 200{ 201 struct script_spec *s = script_spec__find(spec); 202 203 if (s) 204 return s; 205 206 s = script_spec__new(spec, ops); 207 if (!s) 208 goto out_delete_spec; 209 210 script_spec__add(s); 211 212 return s; 213 214out_delete_spec: 215 script_spec__delete(s); 216 217 return NULL; 218} 219 220int script_spec_register(const char *spec, struct scripting_ops *ops) 221{ 222 struct script_spec *s; 223 224 s = script_spec__find(spec); 225 if (s) 226 return -1; 227 228 s = script_spec__findnew(spec, ops); 229 if (!s) 230 return -1; 231 232 return 0; 233} 234 235static struct scripting_ops *script_spec__lookup(const char *spec) 236{ 237 struct script_spec *s = script_spec__find(spec); 238 if (!s) 239 return NULL; 240 241 return s->ops; 242} 243 244static void list_available_languages(void) 245{ 246 struct script_spec *s; 247 248 fprintf(stderr, "\n"); 249 fprintf(stderr, "Scripting language extensions (used in " 250 "perf trace -s [spec:]script.[spec]):\n\n"); 251 252 list_for_each_entry(s, &script_specs, node) 253 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name); 254 255 fprintf(stderr, "\n"); 256} 257 258static int parse_scriptname(const struct option *opt __used, 259 const char *str, int unset __used) 260{ 261 char spec[PATH_MAX]; 262 const char *script, *ext; 263 int len; 264 265 if (strcmp(str, "lang") == 0) { 266 list_available_languages(); 267 exit(0); 268 } 269 270 script = strchr(str, ':'); 271 if (script) { 272 len = script - str; 273 if (len >= PATH_MAX) { 274 fprintf(stderr, "invalid language specifier"); 275 return -1; 276 } 277 strncpy(spec, str, len); 278 spec[len] = '\0'; 279 scripting_ops = script_spec__lookup(spec); 280 if (!scripting_ops) { 281 fprintf(stderr, "invalid language specifier"); 282 return -1; 283 } 284 script++; 285 } else { 286 script = str; 287 ext = strrchr(script, '.'); 288 if (!ext) { 289 fprintf(stderr, "invalid script extension"); 290 return -1; 291 } 292 scripting_ops = script_spec__lookup(++ext); 293 if (!scripting_ops) { 294 fprintf(stderr, "invalid script extension"); 295 return -1; 296 } 297 } 298 299 script_name = strdup(script); 300 301 return 0; 302} 303 304#define for_each_lang(scripts_dir, lang_dirent, lang_next) \ 305 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \ 306 lang_next) \ 307 if (lang_dirent.d_type == DT_DIR && \ 308 (strcmp(lang_dirent.d_name, ".")) && \ 309 (strcmp(lang_dirent.d_name, ".."))) 310 311#define for_each_script(lang_dir, script_dirent, script_next) \ 312 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \ 313 script_next) \ 314 if (script_dirent.d_type != DT_DIR) 315 316 317#define RECORD_SUFFIX "-record" 318#define REPORT_SUFFIX "-report" 319 320struct script_desc { 321 struct list_head node; 322 char *name; 323 char *half_liner; 324 char *args; 325}; 326 327LIST_HEAD(script_descs); 328 329static struct script_desc *script_desc__new(const char *name) 330{ 331 struct script_desc *s = zalloc(sizeof(*s)); 332 333 if (s != NULL && name) 334 s->name = strdup(name); 335 336 return s; 337} 338 339static void script_desc__delete(struct script_desc *s) 340{ 341 free(s->name); 342 free(s->half_liner); 343 free(s->args); 344 free(s); 345} 346 347static void script_desc__add(struct script_desc *s) 348{ 349 list_add_tail(&s->node, &script_descs); 350} 351 352static struct script_desc *script_desc__find(const char *name) 353{ 354 struct script_desc *s; 355 356 list_for_each_entry(s, &script_descs, node) 357 if (strcasecmp(s->name, name) == 0) 358 return s; 359 return NULL; 360} 361 362static struct script_desc *script_desc__findnew(const char *name) 363{ 364 struct script_desc *s = script_desc__find(name); 365 366 if (s) 367 return s; 368 369 s = script_desc__new(name); 370 if (!s) 371 goto out_delete_desc; 372 373 script_desc__add(s); 374 375 return s; 376 377out_delete_desc: 378 script_desc__delete(s); 379 380 return NULL; 381} 382 383static char *ends_with(char *str, const char *suffix) 384{ 385 size_t suffix_len = strlen(suffix); 386 char *p = str; 387 388 if (strlen(str) > suffix_len) { 389 p = str + strlen(str) - suffix_len; 390 if (!strncmp(p, suffix, suffix_len)) 391 return p; 392 } 393 394 return NULL; 395} 396 397static char *ltrim(char *str) 398{ 399 int len = strlen(str); 400 401 while (len && isspace(*str)) { 402 len--; 403 str++; 404 } 405 406 return str; 407} 408 409static int read_script_info(struct script_desc *desc, const char *filename) 410{ 411 char line[BUFSIZ], *p; 412 FILE *fp; 413 414 fp = fopen(filename, "r"); 415 if (!fp) 416 return -1; 417 418 while (fgets(line, sizeof(line), fp)) { 419 p = ltrim(line); 420 if (strlen(p) == 0) 421 continue; 422 if (*p != '#') 423 continue; 424 p++; 425 if (strlen(p) && *p == '!') 426 continue; 427 428 p = ltrim(p); 429 if (strlen(p) && p[strlen(p) - 1] == '\n') 430 p[strlen(p) - 1] = '\0'; 431 432 if (!strncmp(p, "description:", strlen("description:"))) { 433 p += strlen("description:"); 434 desc->half_liner = strdup(ltrim(p)); 435 continue; 436 } 437 438 if (!strncmp(p, "args:", strlen("args:"))) { 439 p += strlen("args:"); 440 desc->args = strdup(ltrim(p)); 441 continue; 442 } 443 } 444 445 fclose(fp); 446 447 return 0; 448} 449 450static int list_available_scripts(const struct option *opt __used, 451 const char *s __used, int unset __used) 452{ 453 struct dirent *script_next, *lang_next, script_dirent, lang_dirent; 454 char scripts_path[MAXPATHLEN]; 455 DIR *scripts_dir, *lang_dir; 456 char script_path[MAXPATHLEN]; 457 char lang_path[MAXPATHLEN]; 458 struct script_desc *desc; 459 char first_half[BUFSIZ]; 460 char *script_root; 461 char *str; 462 463 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 464 465 scripts_dir = opendir(scripts_path); 466 if (!scripts_dir) 467 return -1; 468 469 for_each_lang(scripts_dir, lang_dirent, lang_next) { 470 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, 471 lang_dirent.d_name); 472 lang_dir = opendir(lang_path); 473 if (!lang_dir) 474 continue; 475 476 for_each_script(lang_dir, script_dirent, script_next) { 477 script_root = strdup(script_dirent.d_name); 478 str = ends_with(script_root, REPORT_SUFFIX); 479 if (str) { 480 *str = '\0'; 481 desc = script_desc__findnew(script_root); 482 snprintf(script_path, MAXPATHLEN, "%s/%s", 483 lang_path, script_dirent.d_name); 484 read_script_info(desc, script_path); 485 } 486 free(script_root); 487 } 488 } 489 490 fprintf(stdout, "List of available trace scripts:\n"); 491 list_for_each_entry(desc, &script_descs, node) { 492 sprintf(first_half, "%s %s", desc->name, 493 desc->args ? desc->args : ""); 494 fprintf(stdout, " %-36s %s\n", first_half, 495 desc->half_liner ? desc->half_liner : ""); 496 } 497 498 exit(0); 499} 500 501static char *get_script_path(const char *script_root, const char *suffix) 502{ 503 struct dirent *script_next, *lang_next, script_dirent, lang_dirent; 504 char scripts_path[MAXPATHLEN]; 505 char script_path[MAXPATHLEN]; 506 DIR *scripts_dir, *lang_dir; 507 char lang_path[MAXPATHLEN]; 508 char *str, *__script_root; 509 char *path = NULL; 510 511 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 512 513 scripts_dir = opendir(scripts_path); 514 if (!scripts_dir) 515 return NULL; 516 517 for_each_lang(scripts_dir, lang_dirent, lang_next) { 518 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, 519 lang_dirent.d_name); 520 lang_dir = opendir(lang_path); 521 if (!lang_dir) 522 continue; 523 524 for_each_script(lang_dir, script_dirent, script_next) { 525 __script_root = strdup(script_dirent.d_name); 526 str = ends_with(__script_root, suffix); 527 if (str) { 528 *str = '\0'; 529 if (strcmp(__script_root, script_root)) 530 continue; 531 snprintf(script_path, MAXPATHLEN, "%s/%s", 532 lang_path, script_dirent.d_name); 533 path = strdup(script_path); 534 free(__script_root); 535 break; 536 } 537 free(__script_root); 538 } 539 } 540 541 return path; 542} 543 544static bool is_top_script(const char *script_path) 545{ 546 return ends_with((char *)script_path, "top") == NULL ? false : true; 547} 548 549static int has_required_arg(char *script_path) 550{ 551 struct script_desc *desc; 552 int n_args = 0; 553 char *p; 554 555 desc = script_desc__new(NULL); 556 557 if (read_script_info(desc, script_path)) 558 goto out; 559 560 if (!desc->args) 561 goto out; 562 563 for (p = desc->args; *p; p++) 564 if (*p == '<') 565 n_args++; 566out: 567 script_desc__delete(desc); 568 569 return n_args; 570} 571 572static const char * const trace_usage[] = { 573 "perf trace [<options>]", 574 "perf trace [<options>] record <script> [<record-options>] <command>", 575 "perf trace [<options>] report <script> [script-args]", 576 "perf trace [<options>] <script> [<record-options>] <command>", 577 "perf trace [<options>] <top-script> [script-args]", 578 NULL 579}; 580 581static const struct option options[] = { 582 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 583 "dump raw trace in ASCII"), 584 OPT_INCR('v', "verbose", &verbose, 585 "be more verbose (show symbol address, etc)"), 586 OPT_BOOLEAN('L', "Latency", &latency_format, 587 "show latency attributes (irqs/preemption disabled, etc)"), 588 OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts", 589 list_available_scripts), 590 OPT_CALLBACK('s', "script", NULL, "name", 591 "script file name (lang:script name, script name, or *)", 592 parse_scriptname), 593 OPT_STRING('g', "gen-script", &generate_script_lang, "lang", 594 "generate perf-trace.xx script in specified language"), 595 OPT_STRING('i', "input", &input_name, "file", 596 "input file name"), 597 OPT_BOOLEAN('d', "debug-mode", &debug_mode, 598 "do various checks like samples ordering and lost events"), 599 600 OPT_END() 601}; 602 603static bool have_cmd(int argc, const char **argv) 604{ 605 char **__argv = malloc(sizeof(const char *) * argc); 606 607 if (!__argv) 608 die("malloc"); 609 memcpy(__argv, argv, sizeof(const char *) * argc); 610 argc = parse_options(argc, (const char **)__argv, record_options, 611 NULL, PARSE_OPT_STOP_AT_NON_OPTION); 612 free(__argv); 613 614 return argc != 0; 615} 616 617int cmd_trace(int argc, const char **argv, const char *prefix __used) 618{ 619 char *rec_script_path = NULL; 620 char *rep_script_path = NULL; 621 struct perf_session *session; 622 char *script_path = NULL; 623 const char **__argv; 624 bool system_wide; 625 int i, j, err; 626 627 setup_scripting(); 628 629 argc = parse_options(argc, argv, options, trace_usage, 630 PARSE_OPT_STOP_AT_NON_OPTION); 631 632 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { 633 rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); 634 if (!rec_script_path) 635 return cmd_record(argc, argv, NULL); 636 } 637 638 if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) { 639 rep_script_path = get_script_path(argv[1], REPORT_SUFFIX); 640 if (!rep_script_path) { 641 fprintf(stderr, 642 "Please specify a valid report script" 643 "(see 'perf trace -l' for listing)\n"); 644 return -1; 645 } 646 } 647 648 /* make sure PERF_EXEC_PATH is set for scripts */ 649 perf_set_argv_exec_path(perf_exec_path()); 650 651 if (argc && !script_name && !rec_script_path && !rep_script_path) { 652 int live_pipe[2]; 653 int rep_args; 654 pid_t pid; 655 656 rec_script_path = get_script_path(argv[0], RECORD_SUFFIX); 657 rep_script_path = get_script_path(argv[0], REPORT_SUFFIX); 658 659 if (!rec_script_path && !rep_script_path) { 660 fprintf(stderr, " Couldn't find script %s\n\n See perf" 661 " trace -l for available scripts.\n", argv[0]); 662 usage_with_options(trace_usage, options); 663 } 664 665 if (is_top_script(argv[0])) { 666 rep_args = argc - 1; 667 } else { 668 int rec_args; 669 670 rep_args = has_required_arg(rep_script_path); 671 rec_args = (argc - 1) - rep_args; 672 if (rec_args < 0) { 673 fprintf(stderr, " %s script requires options." 674 "\n\n See perf trace -l for available " 675 "scripts and options.\n", argv[0]); 676 usage_with_options(trace_usage, options); 677 } 678 } 679 680 if (pipe(live_pipe) < 0) { 681 perror("failed to create pipe"); 682 exit(-1); 683 } 684 685 pid = fork(); 686 if (pid < 0) { 687 perror("failed to fork"); 688 exit(-1); 689 } 690 691 if (!pid) { 692 system_wide = true; 693 j = 0; 694 695 dup2(live_pipe[1], 1); 696 close(live_pipe[0]); 697 698 if (!is_top_script(argv[0])) 699 system_wide = !have_cmd(argc - rep_args, 700 &argv[rep_args]); 701 702 __argv = malloc((argc + 6) * sizeof(const char *)); 703 if (!__argv) 704 die("malloc"); 705 706 __argv[j++] = "/bin/sh"; 707 __argv[j++] = rec_script_path; 708 if (system_wide) 709 __argv[j++] = "-a"; 710 __argv[j++] = "-q"; 711 __argv[j++] = "-o"; 712 __argv[j++] = "-"; 713 for (i = rep_args + 1; i < argc; i++) 714 __argv[j++] = argv[i]; 715 __argv[j++] = NULL; 716 717 execvp("/bin/sh", (char **)__argv); 718 free(__argv); 719 exit(-1); 720 } 721 722 dup2(live_pipe[0], 0); 723 close(live_pipe[1]); 724 725 __argv = malloc((argc + 4) * sizeof(const char *)); 726 if (!__argv) 727 die("malloc"); 728 j = 0; 729 __argv[j++] = "/bin/sh"; 730 __argv[j++] = rep_script_path; 731 for (i = 1; i < rep_args + 1; i++) 732 __argv[j++] = argv[i]; 733 __argv[j++] = "-i"; 734 __argv[j++] = "-"; 735 __argv[j++] = NULL; 736 737 execvp("/bin/sh", (char **)__argv); 738 free(__argv); 739 exit(-1); 740 } 741 742 if (rec_script_path) 743 script_path = rec_script_path; 744 if (rep_script_path) 745 script_path = rep_script_path; 746 747 if (script_path) { 748 system_wide = false; 749 j = 0; 750 751 if (rec_script_path) 752 system_wide = !have_cmd(argc - 1, &argv[1]); 753 754 __argv = malloc((argc + 2) * sizeof(const char *)); 755 if (!__argv) 756 die("malloc"); 757 __argv[j++] = "/bin/sh"; 758 __argv[j++] = script_path; 759 if (system_wide) 760 __argv[j++] = "-a"; 761 for (i = 2; i < argc; i++) 762 __argv[j++] = argv[i]; 763 __argv[j++] = NULL; 764 765 execvp("/bin/sh", (char **)__argv); 766 free(__argv); 767 exit(-1); 768 } 769 770 if (symbol__init() < 0) 771 return -1; 772 if (!script_name) 773 setup_pager(); 774 775 session = perf_session__new(input_name, O_RDONLY, 0, false); 776 if (session == NULL) 777 return -ENOMEM; 778 779 if (strcmp(input_name, "-") && 780 !perf_session__has_traces(session, "record -R")) 781 return -EINVAL; 782 783 if (generate_script_lang) { 784 struct stat perf_stat; 785 786 int input = open(input_name, O_RDONLY); 787 if (input < 0) { 788 perror("failed to open file"); 789 exit(-1); 790 } 791 792 err = fstat(input, &perf_stat); 793 if (err < 0) { 794 perror("failed to stat file"); 795 exit(-1); 796 } 797 798 if (!perf_stat.st_size) { 799 fprintf(stderr, "zero-sized file, nothing to do!\n"); 800 exit(0); 801 } 802 803 scripting_ops = script_spec__lookup(generate_script_lang); 804 if (!scripting_ops) { 805 fprintf(stderr, "invalid language specifier"); 806 return -1; 807 } 808 809 err = scripting_ops->generate_script("perf-trace"); 810 goto out; 811 } 812 813 if (script_name) { 814 err = scripting_ops->start_script(script_name, argc, argv); 815 if (err) 816 goto out; 817 pr_debug("perf trace started with script %s\n\n", script_name); 818 } 819 820 err = __cmd_trace(session); 821 822 perf_session__delete(session); 823 cleanup_scripting(); 824out: 825 return err; 826}