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