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