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