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