aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-script.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r--tools/perf/builtin-script.c266
1 files changed, 239 insertions, 27 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index baf17989a216..9e9c91f5b7fa 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -43,6 +43,7 @@ enum perf_output_field {
43 PERF_OUTPUT_DSO = 1U << 9, 43 PERF_OUTPUT_DSO = 1U << 9,
44 PERF_OUTPUT_ADDR = 1U << 10, 44 PERF_OUTPUT_ADDR = 1U << 10,
45 PERF_OUTPUT_SYMOFFSET = 1U << 11, 45 PERF_OUTPUT_SYMOFFSET = 1U << 11,
46 PERF_OUTPUT_SRCLINE = 1U << 12,
46}; 47};
47 48
48struct output_option { 49struct output_option {
@@ -61,6 +62,7 @@ struct output_option {
61 {.str = "dso", .field = PERF_OUTPUT_DSO}, 62 {.str = "dso", .field = PERF_OUTPUT_DSO},
62 {.str = "addr", .field = PERF_OUTPUT_ADDR}, 63 {.str = "addr", .field = PERF_OUTPUT_ADDR},
63 {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, 64 {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},
65 {.str = "srcline", .field = PERF_OUTPUT_SRCLINE},
64}; 66};
65 67
66/* default set to maintain compatibility with current format */ 68/* default set to maintain compatibility with current format */
@@ -210,6 +212,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
210 "to DSO.\n"); 212 "to DSO.\n");
211 return -EINVAL; 213 return -EINVAL;
212 } 214 }
215 if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) {
216 pr_err("Display of source line number requested but sample IP is not\n"
217 "selected. Hence, no address to lookup the source line number.\n");
218 return -EINVAL;
219 }
213 220
214 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && 221 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
215 perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", 222 perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID",
@@ -245,6 +252,9 @@ static void set_print_ip_opts(struct perf_event_attr *attr)
245 252
246 if (PRINT_FIELD(SYMOFFSET)) 253 if (PRINT_FIELD(SYMOFFSET))
247 output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET; 254 output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
255
256 if (PRINT_FIELD(SRCLINE))
257 output[type].print_ip_opts |= PRINT_IP_OPT_SRCLINE;
248} 258}
249 259
250/* 260/*
@@ -280,6 +290,30 @@ static int perf_session__check_output_opt(struct perf_session *session)
280 set_print_ip_opts(&evsel->attr); 290 set_print_ip_opts(&evsel->attr);
281 } 291 }
282 292
293 /*
294 * set default for tracepoints to print symbols only
295 * if callchains are present
296 */
297 if (symbol_conf.use_callchain &&
298 !output[PERF_TYPE_TRACEPOINT].user_set) {
299 struct perf_event_attr *attr;
300
301 j = PERF_TYPE_TRACEPOINT;
302 evsel = perf_session__find_first_evtype(session, j);
303 if (evsel == NULL)
304 goto out;
305
306 attr = &evsel->attr;
307
308 if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) {
309 output[j].fields |= PERF_OUTPUT_IP;
310 output[j].fields |= PERF_OUTPUT_SYM;
311 output[j].fields |= PERF_OUTPUT_DSO;
312 set_print_ip_opts(attr);
313 }
314 }
315
316out:
283 return 0; 317 return 0;
284} 318}
285 319
@@ -288,7 +322,6 @@ static void print_sample_start(struct perf_sample *sample,
288 struct perf_evsel *evsel) 322 struct perf_evsel *evsel)
289{ 323{
290 struct perf_event_attr *attr = &evsel->attr; 324 struct perf_event_attr *attr = &evsel->attr;
291 const char *evname = NULL;
292 unsigned long secs; 325 unsigned long secs;
293 unsigned long usecs; 326 unsigned long usecs;
294 unsigned long long nsecs; 327 unsigned long long nsecs;
@@ -323,11 +356,6 @@ static void print_sample_start(struct perf_sample *sample,
323 usecs = nsecs / NSECS_PER_USEC; 356 usecs = nsecs / NSECS_PER_USEC;
324 printf("%5lu.%06lu: ", secs, usecs); 357 printf("%5lu.%06lu: ", secs, usecs);
325 } 358 }
326
327 if (PRINT_FIELD(EVNAME)) {
328 evname = perf_evsel__name(evsel);
329 printf("%s: ", evname ? evname : "[unknown]");
330 }
331} 359}
332 360
333static bool is_bts_event(struct perf_event_attr *attr) 361static bool is_bts_event(struct perf_event_attr *attr)
@@ -395,8 +423,8 @@ static void print_sample_addr(union perf_event *event,
395static void print_sample_bts(union perf_event *event, 423static void print_sample_bts(union perf_event *event,
396 struct perf_sample *sample, 424 struct perf_sample *sample,
397 struct perf_evsel *evsel, 425 struct perf_evsel *evsel,
398 struct machine *machine, 426 struct thread *thread,
399 struct thread *thread) 427 struct addr_location *al)
400{ 428{
401 struct perf_event_attr *attr = &evsel->attr; 429 struct perf_event_attr *attr = &evsel->attr;
402 430
@@ -406,7 +434,7 @@ static void print_sample_bts(union perf_event *event,
406 printf(" "); 434 printf(" ");
407 else 435 else
408 printf("\n"); 436 printf("\n");
409 perf_evsel__print_ip(evsel, event, sample, machine, 437 perf_evsel__print_ip(evsel, sample, al,
410 output[attr->type].print_ip_opts, 438 output[attr->type].print_ip_opts,
411 PERF_MAX_STACK_DEPTH); 439 PERF_MAX_STACK_DEPTH);
412 } 440 }
@@ -417,15 +445,14 @@ static void print_sample_bts(union perf_event *event,
417 if (PRINT_FIELD(ADDR) || 445 if (PRINT_FIELD(ADDR) ||
418 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 446 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
419 !output[attr->type].user_set)) 447 !output[attr->type].user_set))
420 print_sample_addr(event, sample, machine, thread, attr); 448 print_sample_addr(event, sample, al->machine, thread, attr);
421 449
422 printf("\n"); 450 printf("\n");
423} 451}
424 452
425static void process_event(union perf_event *event, struct perf_sample *sample, 453static void process_event(union perf_event *event, struct perf_sample *sample,
426 struct perf_evsel *evsel, struct machine *machine, 454 struct perf_evsel *evsel, struct thread *thread,
427 struct thread *thread, 455 struct addr_location *al)
428 struct addr_location *al __maybe_unused)
429{ 456{
430 struct perf_event_attr *attr = &evsel->attr; 457 struct perf_event_attr *attr = &evsel->attr;
431 458
@@ -434,8 +461,13 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
434 461
435 print_sample_start(sample, thread, evsel); 462 print_sample_start(sample, thread, evsel);
436 463
464 if (PRINT_FIELD(EVNAME)) {
465 const char *evname = perf_evsel__name(evsel);
466 printf("%s: ", evname ? evname : "[unknown]");
467 }
468
437 if (is_bts_event(attr)) { 469 if (is_bts_event(attr)) {
438 print_sample_bts(event, sample, evsel, machine, thread); 470 print_sample_bts(event, sample, evsel, thread, al);
439 return; 471 return;
440 } 472 }
441 473
@@ -443,7 +475,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
443 event_format__print(evsel->tp_format, sample->cpu, 475 event_format__print(evsel->tp_format, sample->cpu,
444 sample->raw_data, sample->raw_size); 476 sample->raw_data, sample->raw_size);
445 if (PRINT_FIELD(ADDR)) 477 if (PRINT_FIELD(ADDR))
446 print_sample_addr(event, sample, machine, thread, attr); 478 print_sample_addr(event, sample, al->machine, thread, attr);
447 479
448 if (PRINT_FIELD(IP)) { 480 if (PRINT_FIELD(IP)) {
449 if (!symbol_conf.use_callchain) 481 if (!symbol_conf.use_callchain)
@@ -451,7 +483,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
451 else 483 else
452 printf("\n"); 484 printf("\n");
453 485
454 perf_evsel__print_ip(evsel, event, sample, machine, 486 perf_evsel__print_ip(evsel, sample, al,
455 output[attr->type].print_ip_opts, 487 output[attr->type].print_ip_opts,
456 PERF_MAX_STACK_DEPTH); 488 PERF_MAX_STACK_DEPTH);
457 } 489 }
@@ -540,7 +572,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
540 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 572 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
541 return 0; 573 return 0;
542 574
543 scripting_ops->process_event(event, sample, evsel, machine, thread, &al); 575 scripting_ops->process_event(event, sample, evsel, thread, &al);
544 576
545 evsel->hists.stats.total_period += sample->period; 577 evsel->hists.stats.total_period += sample->period;
546 return 0; 578 return 0;
@@ -549,6 +581,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
549struct perf_script { 581struct perf_script {
550 struct perf_tool tool; 582 struct perf_tool tool;
551 struct perf_session *session; 583 struct perf_session *session;
584 bool show_task_events;
585 bool show_mmap_events;
552}; 586};
553 587
554static int process_attr(struct perf_tool *tool, union perf_event *event, 588static int process_attr(struct perf_tool *tool, union perf_event *event,
@@ -569,7 +603,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
569 if (evsel->attr.type >= PERF_TYPE_MAX) 603 if (evsel->attr.type >= PERF_TYPE_MAX)
570 return 0; 604 return 0;
571 605
572 list_for_each_entry(pos, &evlist->entries, node) { 606 evlist__for_each(evlist, pos) {
573 if (pos->attr.type == evsel->attr.type && pos != evsel) 607 if (pos->attr.type == evsel->attr.type && pos != evsel)
574 return 0; 608 return 0;
575 } 609 }
@@ -579,6 +613,163 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
579 return perf_evsel__check_attr(evsel, scr->session); 613 return perf_evsel__check_attr(evsel, scr->session);
580} 614}
581 615
616static int process_comm_event(struct perf_tool *tool,
617 union perf_event *event,
618 struct perf_sample *sample,
619 struct machine *machine)
620{
621 struct thread *thread;
622 struct perf_script *script = container_of(tool, struct perf_script, tool);
623 struct perf_session *session = script->session;
624 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
625 int ret = -1;
626
627 thread = machine__findnew_thread(machine, event->comm.pid, event->comm.tid);
628 if (thread == NULL) {
629 pr_debug("problem processing COMM event, skipping it.\n");
630 return -1;
631 }
632
633 if (perf_event__process_comm(tool, event, sample, machine) < 0)
634 goto out;
635
636 if (!evsel->attr.sample_id_all) {
637 sample->cpu = 0;
638 sample->time = 0;
639 sample->tid = event->comm.tid;
640 sample->pid = event->comm.pid;
641 }
642 print_sample_start(sample, thread, evsel);
643 perf_event__fprintf(event, stdout);
644 ret = 0;
645
646out:
647 return ret;
648}
649
650static int process_fork_event(struct perf_tool *tool,
651 union perf_event *event,
652 struct perf_sample *sample,
653 struct machine *machine)
654{
655 struct thread *thread;
656 struct perf_script *script = container_of(tool, struct perf_script, tool);
657 struct perf_session *session = script->session;
658 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
659
660 if (perf_event__process_fork(tool, event, sample, machine) < 0)
661 return -1;
662
663 thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid);
664 if (thread == NULL) {
665 pr_debug("problem processing FORK event, skipping it.\n");
666 return -1;
667 }
668
669 if (!evsel->attr.sample_id_all) {
670 sample->cpu = 0;
671 sample->time = event->fork.time;
672 sample->tid = event->fork.tid;
673 sample->pid = event->fork.pid;
674 }
675 print_sample_start(sample, thread, evsel);
676 perf_event__fprintf(event, stdout);
677
678 return 0;
679}
680static int process_exit_event(struct perf_tool *tool,
681 union perf_event *event,
682 struct perf_sample *sample,
683 struct machine *machine)
684{
685 struct thread *thread;
686 struct perf_script *script = container_of(tool, struct perf_script, tool);
687 struct perf_session *session = script->session;
688 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
689
690 thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid);
691 if (thread == NULL) {
692 pr_debug("problem processing EXIT event, skipping it.\n");
693 return -1;
694 }
695
696 if (!evsel->attr.sample_id_all) {
697 sample->cpu = 0;
698 sample->time = 0;
699 sample->tid = event->comm.tid;
700 sample->pid = event->comm.pid;
701 }
702 print_sample_start(sample, thread, evsel);
703 perf_event__fprintf(event, stdout);
704
705 if (perf_event__process_exit(tool, event, sample, machine) < 0)
706 return -1;
707
708 return 0;
709}
710
711static int process_mmap_event(struct perf_tool *tool,
712 union perf_event *event,
713 struct perf_sample *sample,
714 struct machine *machine)
715{
716 struct thread *thread;
717 struct perf_script *script = container_of(tool, struct perf_script, tool);
718 struct perf_session *session = script->session;
719 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
720
721 if (perf_event__process_mmap(tool, event, sample, machine) < 0)
722 return -1;
723
724 thread = machine__findnew_thread(machine, event->mmap.pid, event->mmap.tid);
725 if (thread == NULL) {
726 pr_debug("problem processing MMAP event, skipping it.\n");
727 return -1;
728 }
729
730 if (!evsel->attr.sample_id_all) {
731 sample->cpu = 0;
732 sample->time = 0;
733 sample->tid = event->mmap.tid;
734 sample->pid = event->mmap.pid;
735 }
736 print_sample_start(sample, thread, evsel);
737 perf_event__fprintf(event, stdout);
738
739 return 0;
740}
741
742static int process_mmap2_event(struct perf_tool *tool,
743 union perf_event *event,
744 struct perf_sample *sample,
745 struct machine *machine)
746{
747 struct thread *thread;
748 struct perf_script *script = container_of(tool, struct perf_script, tool);
749 struct perf_session *session = script->session;
750 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
751
752 if (perf_event__process_mmap2(tool, event, sample, machine) < 0)
753 return -1;
754
755 thread = machine__findnew_thread(machine, event->mmap2.pid, event->mmap2.tid);
756 if (thread == NULL) {
757 pr_debug("problem processing MMAP2 event, skipping it.\n");
758 return -1;
759 }
760
761 if (!evsel->attr.sample_id_all) {
762 sample->cpu = 0;
763 sample->time = 0;
764 sample->tid = event->mmap2.tid;
765 sample->pid = event->mmap2.pid;
766 }
767 print_sample_start(sample, thread, evsel);
768 perf_event__fprintf(event, stdout);
769
770 return 0;
771}
772
582static void sig_handler(int sig __maybe_unused) 773static void sig_handler(int sig __maybe_unused)
583{ 774{
584 session_done = 1; 775 session_done = 1;
@@ -590,6 +781,17 @@ static int __cmd_script(struct perf_script *script)
590 781
591 signal(SIGINT, sig_handler); 782 signal(SIGINT, sig_handler);
592 783
784 /* override event processing functions */
785 if (script->show_task_events) {
786 script->tool.comm = process_comm_event;
787 script->tool.fork = process_fork_event;
788 script->tool.exit = process_exit_event;
789 }
790 if (script->show_mmap_events) {
791 script->tool.mmap = process_mmap_event;
792 script->tool.mmap2 = process_mmap2_event;
793 }
794
593 ret = perf_session__process_events(script->session, &script->tool); 795 ret = perf_session__process_events(script->session, &script->tool);
594 796
595 if (debug_mode) 797 if (debug_mode)
@@ -900,9 +1102,9 @@ static struct script_desc *script_desc__new(const char *name)
900 1102
901static void script_desc__delete(struct script_desc *s) 1103static void script_desc__delete(struct script_desc *s)
902{ 1104{
903 free(s->name); 1105 zfree(&s->name);
904 free(s->half_liner); 1106 zfree(&s->half_liner);
905 free(s->args); 1107 zfree(&s->args);
906 free(s); 1108 free(s);
907} 1109}
908 1110
@@ -1107,8 +1309,7 @@ static int check_ev_match(char *dir_name, char *scriptname,
1107 snprintf(evname, len + 1, "%s", p); 1309 snprintf(evname, len + 1, "%s", p);
1108 1310
1109 match = 0; 1311 match = 0;
1110 list_for_each_entry(pos, 1312 evlist__for_each(session->evlist, pos) {
1111 &session->evlist->entries, node) {
1112 if (!strcmp(perf_evsel__name(pos), evname)) { 1313 if (!strcmp(perf_evsel__name(pos), evname)) {
1113 match = 1; 1314 match = 1;
1114 break; 1315 break;
@@ -1290,6 +1491,8 @@ static int have_cmd(int argc, const char **argv)
1290int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) 1491int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1291{ 1492{
1292 bool show_full_info = false; 1493 bool show_full_info = false;
1494 bool header = false;
1495 bool header_only = false;
1293 char *rec_script_path = NULL; 1496 char *rec_script_path = NULL;
1294 char *rep_script_path = NULL; 1497 char *rep_script_path = NULL;
1295 struct perf_session *session; 1498 struct perf_session *session;
@@ -1328,6 +1531,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1328 OPT_STRING('i', "input", &input_name, "file", "input file name"), 1531 OPT_STRING('i', "input", &input_name, "file", "input file name"),
1329 OPT_BOOLEAN('d', "debug-mode", &debug_mode, 1532 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
1330 "do various checks like samples ordering and lost events"), 1533 "do various checks like samples ordering and lost events"),
1534 OPT_BOOLEAN(0, "header", &header, "Show data header."),
1535 OPT_BOOLEAN(0, "header-only", &header_only, "Show only data header."),
1331 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1536 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1332 "file", "vmlinux pathname"), 1537 "file", "vmlinux pathname"),
1333 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, 1538 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
@@ -1352,6 +1557,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1352 "display extended information from perf.data file"), 1557 "display extended information from perf.data file"),
1353 OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, 1558 OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
1354 "Show the path of [kernel.kallsyms]"), 1559 "Show the path of [kernel.kallsyms]"),
1560 OPT_BOOLEAN('\0', "show-task-events", &script.show_task_events,
1561 "Show the fork/comm/exit events"),
1562 OPT_BOOLEAN('\0', "show-mmap-events", &script.show_mmap_events,
1563 "Show the mmap events"),
1355 OPT_END() 1564 OPT_END()
1356 }; 1565 };
1357 const char * const script_usage[] = { 1566 const char * const script_usage[] = {
@@ -1540,6 +1749,12 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1540 if (session == NULL) 1749 if (session == NULL)
1541 return -ENOMEM; 1750 return -ENOMEM;
1542 1751
1752 if (header || header_only) {
1753 perf_session__fprintf_info(session, stdout, show_full_info);
1754 if (header_only)
1755 return 0;
1756 }
1757
1543 script.session = session; 1758 script.session = session;
1544 1759
1545 if (cpu_list) { 1760 if (cpu_list) {
@@ -1547,9 +1762,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1547 return -1; 1762 return -1;
1548 } 1763 }
1549 1764
1550 if (!script_name && !generate_script_lang)
1551 perf_session__fprintf_info(session, stdout, show_full_info);
1552
1553 if (!no_callchain) 1765 if (!no_callchain)
1554 symbol_conf.use_callchain = true; 1766 symbol_conf.use_callchain = true;
1555 else 1767 else
@@ -1588,7 +1800,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1588 return -1; 1800 return -1;
1589 } 1801 }
1590 1802
1591 err = scripting_ops->generate_script(session->pevent, 1803 err = scripting_ops->generate_script(session->tevent.pevent,
1592 "perf-script"); 1804 "perf-script");
1593 goto out; 1805 goto out;
1594 } 1806 }