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