diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 739 |
1 files changed, 465 insertions, 274 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 83cdc0a61fd6..68f36dc0344f 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -1,3 +1,4 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
1 | #include "builtin.h" | 2 | #include "builtin.h" |
2 | 3 | ||
3 | #include "perf.h" | 4 | #include "perf.h" |
@@ -87,6 +88,8 @@ enum perf_output_field { | |||
87 | PERF_OUTPUT_BRSTACKINSN = 1U << 23, | 88 | PERF_OUTPUT_BRSTACKINSN = 1U << 23, |
88 | PERF_OUTPUT_BRSTACKOFF = 1U << 24, | 89 | PERF_OUTPUT_BRSTACKOFF = 1U << 24, |
89 | PERF_OUTPUT_SYNTH = 1U << 25, | 90 | PERF_OUTPUT_SYNTH = 1U << 25, |
91 | PERF_OUTPUT_PHYS_ADDR = 1U << 26, | ||
92 | PERF_OUTPUT_UREGS = 1U << 27, | ||
90 | }; | 93 | }; |
91 | 94 | ||
92 | struct output_option { | 95 | struct output_option { |
@@ -108,6 +111,7 @@ struct output_option { | |||
108 | {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, | 111 | {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, |
109 | {.str = "period", .field = PERF_OUTPUT_PERIOD}, | 112 | {.str = "period", .field = PERF_OUTPUT_PERIOD}, |
110 | {.str = "iregs", .field = PERF_OUTPUT_IREGS}, | 113 | {.str = "iregs", .field = PERF_OUTPUT_IREGS}, |
114 | {.str = "uregs", .field = PERF_OUTPUT_UREGS}, | ||
111 | {.str = "brstack", .field = PERF_OUTPUT_BRSTACK}, | 115 | {.str = "brstack", .field = PERF_OUTPUT_BRSTACK}, |
112 | {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, | 116 | {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, |
113 | {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC}, | 117 | {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC}, |
@@ -119,6 +123,7 @@ struct output_option { | |||
119 | {.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN}, | 123 | {.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN}, |
120 | {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, | 124 | {.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF}, |
121 | {.str = "synth", .field = PERF_OUTPUT_SYNTH}, | 125 | {.str = "synth", .field = PERF_OUTPUT_SYNTH}, |
126 | {.str = "phys_addr", .field = PERF_OUTPUT_PHYS_ADDR}, | ||
122 | }; | 127 | }; |
123 | 128 | ||
124 | enum { | 129 | enum { |
@@ -175,7 +180,8 @@ static struct { | |||
175 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | | 180 | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | |
176 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | | 181 | PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | |
177 | PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR | | 182 | PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR | |
178 | PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT, | 183 | PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT | |
184 | PERF_OUTPUT_PHYS_ADDR, | ||
179 | 185 | ||
180 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, | 186 | .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, |
181 | }, | 187 | }, |
@@ -205,6 +211,51 @@ static struct { | |||
205 | }, | 211 | }, |
206 | }; | 212 | }; |
207 | 213 | ||
214 | struct perf_evsel_script { | ||
215 | char *filename; | ||
216 | FILE *fp; | ||
217 | u64 samples; | ||
218 | }; | ||
219 | |||
220 | static struct perf_evsel_script *perf_evsel_script__new(struct perf_evsel *evsel, | ||
221 | struct perf_data *data) | ||
222 | { | ||
223 | struct perf_evsel_script *es = malloc(sizeof(*es)); | ||
224 | |||
225 | if (es != NULL) { | ||
226 | if (asprintf(&es->filename, "%s.%s.dump", data->file.path, perf_evsel__name(evsel)) < 0) | ||
227 | goto out_free; | ||
228 | es->fp = fopen(es->filename, "w"); | ||
229 | if (es->fp == NULL) | ||
230 | goto out_free_filename; | ||
231 | es->samples = 0; | ||
232 | } | ||
233 | |||
234 | return es; | ||
235 | out_free_filename: | ||
236 | zfree(&es->filename); | ||
237 | out_free: | ||
238 | free(es); | ||
239 | return NULL; | ||
240 | } | ||
241 | |||
242 | static void perf_evsel_script__delete(struct perf_evsel_script *es) | ||
243 | { | ||
244 | zfree(&es->filename); | ||
245 | fclose(es->fp); | ||
246 | es->fp = NULL; | ||
247 | free(es); | ||
248 | } | ||
249 | |||
250 | static int perf_evsel_script__fprintf(struct perf_evsel_script *es, FILE *fp) | ||
251 | { | ||
252 | struct stat st; | ||
253 | |||
254 | fstat(fileno(es->fp), &st); | ||
255 | return fprintf(fp, "[ perf script: Wrote %.3f MB %s (%" PRIu64 " samples) ]\n", | ||
256 | st.st_size / 1024.0 / 1024.0, es->filename, es->samples); | ||
257 | } | ||
258 | |||
208 | static inline int output_type(unsigned int type) | 259 | static inline int output_type(unsigned int type) |
209 | { | 260 | { |
210 | switch (type) { | 261 | switch (type) { |
@@ -382,6 +433,16 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
382 | PERF_OUTPUT_IREGS)) | 433 | PERF_OUTPUT_IREGS)) |
383 | return -EINVAL; | 434 | return -EINVAL; |
384 | 435 | ||
436 | if (PRINT_FIELD(UREGS) && | ||
437 | perf_evsel__check_stype(evsel, PERF_SAMPLE_REGS_USER, "UREGS", | ||
438 | PERF_OUTPUT_UREGS)) | ||
439 | return -EINVAL; | ||
440 | |||
441 | if (PRINT_FIELD(PHYS_ADDR) && | ||
442 | perf_evsel__check_stype(evsel, PERF_SAMPLE_PHYS_ADDR, "PHYS_ADDR", | ||
443 | PERF_OUTPUT_PHYS_ADDR)) | ||
444 | return -EINVAL; | ||
445 | |||
385 | return 0; | 446 | return 0; |
386 | } | 447 | } |
387 | 448 | ||
@@ -485,51 +546,76 @@ out: | |||
485 | return 0; | 546 | return 0; |
486 | } | 547 | } |
487 | 548 | ||
488 | static void print_sample_iregs(struct perf_sample *sample, | 549 | static int perf_sample__fprintf_iregs(struct perf_sample *sample, |
489 | struct perf_event_attr *attr) | 550 | struct perf_event_attr *attr, FILE *fp) |
490 | { | 551 | { |
491 | struct regs_dump *regs = &sample->intr_regs; | 552 | struct regs_dump *regs = &sample->intr_regs; |
492 | uint64_t mask = attr->sample_regs_intr; | 553 | uint64_t mask = attr->sample_regs_intr; |
493 | unsigned i = 0, r; | 554 | unsigned i = 0, r; |
555 | int printed = 0; | ||
494 | 556 | ||
495 | if (!regs) | 557 | if (!regs) |
496 | return; | 558 | return 0; |
559 | |||
560 | for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { | ||
561 | u64 val = regs->regs[i++]; | ||
562 | printed += fprintf(fp, "%5s:0x%"PRIx64" ", perf_reg_name(r), val); | ||
563 | } | ||
564 | |||
565 | return printed; | ||
566 | } | ||
567 | |||
568 | static int perf_sample__fprintf_uregs(struct perf_sample *sample, | ||
569 | struct perf_event_attr *attr, FILE *fp) | ||
570 | { | ||
571 | struct regs_dump *regs = &sample->user_regs; | ||
572 | uint64_t mask = attr->sample_regs_user; | ||
573 | unsigned i = 0, r; | ||
574 | int printed = 0; | ||
575 | |||
576 | if (!regs || !regs->regs) | ||
577 | return 0; | ||
578 | |||
579 | printed += fprintf(fp, " ABI:%" PRIu64 " ", regs->abi); | ||
497 | 580 | ||
498 | for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { | 581 | for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { |
499 | u64 val = regs->regs[i++]; | 582 | u64 val = regs->regs[i++]; |
500 | printf("%5s:0x%"PRIx64" ", perf_reg_name(r), val); | 583 | printed += fprintf(fp, "%5s:0x%"PRIx64" ", perf_reg_name(r), val); |
501 | } | 584 | } |
585 | |||
586 | return printed; | ||
502 | } | 587 | } |
503 | 588 | ||
504 | static void print_sample_start(struct perf_sample *sample, | 589 | static int perf_sample__fprintf_start(struct perf_sample *sample, |
505 | struct thread *thread, | 590 | struct thread *thread, |
506 | struct perf_evsel *evsel) | 591 | struct perf_evsel *evsel, FILE *fp) |
507 | { | 592 | { |
508 | struct perf_event_attr *attr = &evsel->attr; | 593 | struct perf_event_attr *attr = &evsel->attr; |
509 | unsigned long secs; | 594 | unsigned long secs; |
510 | unsigned long long nsecs; | 595 | unsigned long long nsecs; |
596 | int printed = 0; | ||
511 | 597 | ||
512 | if (PRINT_FIELD(COMM)) { | 598 | if (PRINT_FIELD(COMM)) { |
513 | if (latency_format) | 599 | if (latency_format) |
514 | printf("%8.8s ", thread__comm_str(thread)); | 600 | printed += fprintf(fp, "%8.8s ", thread__comm_str(thread)); |
515 | else if (PRINT_FIELD(IP) && symbol_conf.use_callchain) | 601 | else if (PRINT_FIELD(IP) && symbol_conf.use_callchain) |
516 | printf("%s ", thread__comm_str(thread)); | 602 | printed += fprintf(fp, "%s ", thread__comm_str(thread)); |
517 | else | 603 | else |
518 | printf("%16s ", thread__comm_str(thread)); | 604 | printed += fprintf(fp, "%16s ", thread__comm_str(thread)); |
519 | } | 605 | } |
520 | 606 | ||
521 | if (PRINT_FIELD(PID) && PRINT_FIELD(TID)) | 607 | if (PRINT_FIELD(PID) && PRINT_FIELD(TID)) |
522 | printf("%5d/%-5d ", sample->pid, sample->tid); | 608 | printed += fprintf(fp, "%5d/%-5d ", sample->pid, sample->tid); |
523 | else if (PRINT_FIELD(PID)) | 609 | else if (PRINT_FIELD(PID)) |
524 | printf("%5d ", sample->pid); | 610 | printed += fprintf(fp, "%5d ", sample->pid); |
525 | else if (PRINT_FIELD(TID)) | 611 | else if (PRINT_FIELD(TID)) |
526 | printf("%5d ", sample->tid); | 612 | printed += fprintf(fp, "%5d ", sample->tid); |
527 | 613 | ||
528 | if (PRINT_FIELD(CPU)) { | 614 | if (PRINT_FIELD(CPU)) { |
529 | if (latency_format) | 615 | if (latency_format) |
530 | printf("%3d ", sample->cpu); | 616 | printed += fprintf(fp, "%3d ", sample->cpu); |
531 | else | 617 | else |
532 | printf("[%03d] ", sample->cpu); | 618 | printed += fprintf(fp, "[%03d] ", sample->cpu); |
533 | } | 619 | } |
534 | 620 | ||
535 | if (PRINT_FIELD(TIME)) { | 621 | if (PRINT_FIELD(TIME)) { |
@@ -538,13 +624,15 @@ static void print_sample_start(struct perf_sample *sample, | |||
538 | nsecs -= secs * NSEC_PER_SEC; | 624 | nsecs -= secs * NSEC_PER_SEC; |
539 | 625 | ||
540 | if (nanosecs) | 626 | if (nanosecs) |
541 | printf("%5lu.%09llu: ", secs, nsecs); | 627 | printed += fprintf(fp, "%5lu.%09llu: ", secs, nsecs); |
542 | else { | 628 | else { |
543 | char sample_time[32]; | 629 | char sample_time[32]; |
544 | timestamp__scnprintf_usec(sample->time, sample_time, sizeof(sample_time)); | 630 | timestamp__scnprintf_usec(sample->time, sample_time, sizeof(sample_time)); |
545 | printf("%12s: ", sample_time); | 631 | printed += fprintf(fp, "%12s: ", sample_time); |
546 | } | 632 | } |
547 | } | 633 | } |
634 | |||
635 | return printed; | ||
548 | } | 636 | } |
549 | 637 | ||
550 | static inline char | 638 | static inline char |
@@ -556,16 +644,17 @@ mispred_str(struct branch_entry *br) | |||
556 | return br->flags.predicted ? 'P' : 'M'; | 644 | return br->flags.predicted ? 'P' : 'M'; |
557 | } | 645 | } |
558 | 646 | ||
559 | static void print_sample_brstack(struct perf_sample *sample, | 647 | static int perf_sample__fprintf_brstack(struct perf_sample *sample, |
560 | struct thread *thread, | 648 | struct thread *thread, |
561 | struct perf_event_attr *attr) | 649 | struct perf_event_attr *attr, FILE *fp) |
562 | { | 650 | { |
563 | struct branch_stack *br = sample->branch_stack; | 651 | struct branch_stack *br = sample->branch_stack; |
564 | struct addr_location alf, alt; | 652 | struct addr_location alf, alt; |
565 | u64 i, from, to; | 653 | u64 i, from, to; |
654 | int printed = 0; | ||
566 | 655 | ||
567 | if (!(br && br->nr)) | 656 | if (!(br && br->nr)) |
568 | return; | 657 | return 0; |
569 | 658 | ||
570 | for (i = 0; i < br->nr; i++) { | 659 | for (i = 0; i < br->nr; i++) { |
571 | from = br->entries[i].from; | 660 | from = br->entries[i].from; |
@@ -578,38 +667,41 @@ static void print_sample_brstack(struct perf_sample *sample, | |||
578 | thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt); | 667 | thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt); |
579 | } | 668 | } |
580 | 669 | ||
581 | printf("0x%"PRIx64, from); | 670 | printed += fprintf(fp, " 0x%"PRIx64, from); |
582 | if (PRINT_FIELD(DSO)) { | 671 | if (PRINT_FIELD(DSO)) { |
583 | printf("("); | 672 | printed += fprintf(fp, "("); |
584 | map__fprintf_dsoname(alf.map, stdout); | 673 | printed += map__fprintf_dsoname(alf.map, fp); |
585 | printf(")"); | 674 | printed += fprintf(fp, ")"); |
586 | } | 675 | } |
587 | 676 | ||
588 | printf("/0x%"PRIx64, to); | 677 | printed += fprintf(fp, "/0x%"PRIx64, to); |
589 | if (PRINT_FIELD(DSO)) { | 678 | if (PRINT_FIELD(DSO)) { |
590 | printf("("); | 679 | printed += fprintf(fp, "("); |
591 | map__fprintf_dsoname(alt.map, stdout); | 680 | printed += map__fprintf_dsoname(alt.map, fp); |
592 | printf(")"); | 681 | printed += fprintf(fp, ")"); |
593 | } | 682 | } |
594 | 683 | ||
595 | printf("/%c/%c/%c/%d ", | 684 | printed += fprintf(fp, "/%c/%c/%c/%d ", |
596 | mispred_str( br->entries + i), | 685 | mispred_str( br->entries + i), |
597 | br->entries[i].flags.in_tx? 'X' : '-', | 686 | br->entries[i].flags.in_tx? 'X' : '-', |
598 | br->entries[i].flags.abort? 'A' : '-', | 687 | br->entries[i].flags.abort? 'A' : '-', |
599 | br->entries[i].flags.cycles); | 688 | br->entries[i].flags.cycles); |
600 | } | 689 | } |
690 | |||
691 | return printed; | ||
601 | } | 692 | } |
602 | 693 | ||
603 | static void print_sample_brstacksym(struct perf_sample *sample, | 694 | static int perf_sample__fprintf_brstacksym(struct perf_sample *sample, |
604 | struct thread *thread, | 695 | struct thread *thread, |
605 | struct perf_event_attr *attr) | 696 | struct perf_event_attr *attr, FILE *fp) |
606 | { | 697 | { |
607 | struct branch_stack *br = sample->branch_stack; | 698 | struct branch_stack *br = sample->branch_stack; |
608 | struct addr_location alf, alt; | 699 | struct addr_location alf, alt; |
609 | u64 i, from, to; | 700 | u64 i, from, to; |
701 | int printed = 0; | ||
610 | 702 | ||
611 | if (!(br && br->nr)) | 703 | if (!(br && br->nr)) |
612 | return; | 704 | return 0; |
613 | 705 | ||
614 | for (i = 0; i < br->nr; i++) { | 706 | for (i = 0; i < br->nr; i++) { |
615 | 707 | ||
@@ -626,37 +718,40 @@ static void print_sample_brstacksym(struct perf_sample *sample, | |||
626 | if (alt.map) | 718 | if (alt.map) |
627 | alt.sym = map__find_symbol(alt.map, alt.addr); | 719 | alt.sym = map__find_symbol(alt.map, alt.addr); |
628 | 720 | ||
629 | symbol__fprintf_symname_offs(alf.sym, &alf, stdout); | 721 | printed += symbol__fprintf_symname_offs(alf.sym, &alf, fp); |
630 | if (PRINT_FIELD(DSO)) { | 722 | if (PRINT_FIELD(DSO)) { |
631 | printf("("); | 723 | printed += fprintf(fp, "("); |
632 | map__fprintf_dsoname(alf.map, stdout); | 724 | printed += map__fprintf_dsoname(alf.map, fp); |
633 | printf(")"); | 725 | printed += fprintf(fp, ")"); |
634 | } | 726 | } |
635 | putchar('/'); | 727 | printed += fprintf(fp, "%c", '/'); |
636 | symbol__fprintf_symname_offs(alt.sym, &alt, stdout); | 728 | printed += symbol__fprintf_symname_offs(alt.sym, &alt, fp); |
637 | if (PRINT_FIELD(DSO)) { | 729 | if (PRINT_FIELD(DSO)) { |
638 | printf("("); | 730 | printed += fprintf(fp, "("); |
639 | map__fprintf_dsoname(alt.map, stdout); | 731 | printed += map__fprintf_dsoname(alt.map, fp); |
640 | printf(")"); | 732 | printed += fprintf(fp, ")"); |
641 | } | 733 | } |
642 | printf("/%c/%c/%c/%d ", | 734 | printed += fprintf(fp, "/%c/%c/%c/%d ", |
643 | mispred_str( br->entries + i), | 735 | mispred_str( br->entries + i), |
644 | br->entries[i].flags.in_tx? 'X' : '-', | 736 | br->entries[i].flags.in_tx? 'X' : '-', |
645 | br->entries[i].flags.abort? 'A' : '-', | 737 | br->entries[i].flags.abort? 'A' : '-', |
646 | br->entries[i].flags.cycles); | 738 | br->entries[i].flags.cycles); |
647 | } | 739 | } |
740 | |||
741 | return printed; | ||
648 | } | 742 | } |
649 | 743 | ||
650 | static void print_sample_brstackoff(struct perf_sample *sample, | 744 | static int perf_sample__fprintf_brstackoff(struct perf_sample *sample, |
651 | struct thread *thread, | 745 | struct thread *thread, |
652 | struct perf_event_attr *attr) | 746 | struct perf_event_attr *attr, FILE *fp) |
653 | { | 747 | { |
654 | struct branch_stack *br = sample->branch_stack; | 748 | struct branch_stack *br = sample->branch_stack; |
655 | struct addr_location alf, alt; | 749 | struct addr_location alf, alt; |
656 | u64 i, from, to; | 750 | u64 i, from, to; |
751 | int printed = 0; | ||
657 | 752 | ||
658 | if (!(br && br->nr)) | 753 | if (!(br && br->nr)) |
659 | return; | 754 | return 0; |
660 | 755 | ||
661 | for (i = 0; i < br->nr; i++) { | 756 | for (i = 0; i < br->nr; i++) { |
662 | 757 | ||
@@ -673,24 +768,26 @@ static void print_sample_brstackoff(struct perf_sample *sample, | |||
673 | if (alt.map && !alt.map->dso->adjust_symbols) | 768 | if (alt.map && !alt.map->dso->adjust_symbols) |
674 | to = map__map_ip(alt.map, to); | 769 | to = map__map_ip(alt.map, to); |
675 | 770 | ||
676 | printf("0x%"PRIx64, from); | 771 | printed += fprintf(fp, " 0x%"PRIx64, from); |
677 | if (PRINT_FIELD(DSO)) { | 772 | if (PRINT_FIELD(DSO)) { |
678 | printf("("); | 773 | printed += fprintf(fp, "("); |
679 | map__fprintf_dsoname(alf.map, stdout); | 774 | printed += map__fprintf_dsoname(alf.map, fp); |
680 | printf(")"); | 775 | printed += fprintf(fp, ")"); |
681 | } | 776 | } |
682 | printf("/0x%"PRIx64, to); | 777 | printed += fprintf(fp, "/0x%"PRIx64, to); |
683 | if (PRINT_FIELD(DSO)) { | 778 | if (PRINT_FIELD(DSO)) { |
684 | printf("("); | 779 | printed += fprintf(fp, "("); |
685 | map__fprintf_dsoname(alt.map, stdout); | 780 | printed += map__fprintf_dsoname(alt.map, fp); |
686 | printf(")"); | 781 | printed += fprintf(fp, ")"); |
687 | } | 782 | } |
688 | printf("/%c/%c/%c/%d ", | 783 | printed += fprintf(fp, "/%c/%c/%c/%d ", |
689 | mispred_str(br->entries + i), | 784 | mispred_str(br->entries + i), |
690 | br->entries[i].flags.in_tx ? 'X' : '-', | 785 | br->entries[i].flags.in_tx ? 'X' : '-', |
691 | br->entries[i].flags.abort ? 'A' : '-', | 786 | br->entries[i].flags.abort ? 'A' : '-', |
692 | br->entries[i].flags.cycles); | 787 | br->entries[i].flags.cycles); |
693 | } | 788 | } |
789 | |||
790 | return printed; | ||
694 | } | 791 | } |
695 | #define MAXBB 16384UL | 792 | #define MAXBB 16384UL |
696 | 793 | ||
@@ -718,27 +815,26 @@ static int grab_bb(u8 *buffer, u64 start, u64 end, | |||
718 | * but the exit is not. Let the caller patch it up. | 815 | * but the exit is not. Let the caller patch it up. |
719 | */ | 816 | */ |
720 | if (kernel != machine__kernel_ip(machine, end)) { | 817 | if (kernel != machine__kernel_ip(machine, end)) { |
721 | printf("\tblock %" PRIx64 "-%" PRIx64 " transfers between kernel and user\n", | 818 | pr_debug("\tblock %" PRIx64 "-%" PRIx64 " transfers between kernel and user\n", start, end); |
722 | start, end); | ||
723 | return -ENXIO; | 819 | return -ENXIO; |
724 | } | 820 | } |
725 | 821 | ||
726 | memset(&al, 0, sizeof(al)); | 822 | memset(&al, 0, sizeof(al)); |
727 | if (end - start > MAXBB - MAXINSN) { | 823 | if (end - start > MAXBB - MAXINSN) { |
728 | if (last) | 824 | if (last) |
729 | printf("\tbrstack does not reach to final jump (%" PRIx64 "-%" PRIx64 ")\n", start, end); | 825 | pr_debug("\tbrstack does not reach to final jump (%" PRIx64 "-%" PRIx64 ")\n", start, end); |
730 | else | 826 | else |
731 | printf("\tblock %" PRIx64 "-%" PRIx64 " (%" PRIu64 ") too long to dump\n", start, end, end - start); | 827 | pr_debug("\tblock %" PRIx64 "-%" PRIx64 " (%" PRIu64 ") too long to dump\n", start, end, end - start); |
732 | return 0; | 828 | return 0; |
733 | } | 829 | } |
734 | 830 | ||
735 | thread__find_addr_map(thread, *cpumode, MAP__FUNCTION, start, &al); | 831 | thread__find_addr_map(thread, *cpumode, MAP__FUNCTION, start, &al); |
736 | if (!al.map || !al.map->dso) { | 832 | if (!al.map || !al.map->dso) { |
737 | printf("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end); | 833 | pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end); |
738 | return 0; | 834 | return 0; |
739 | } | 835 | } |
740 | if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR) { | 836 | if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR) { |
741 | printf("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end); | 837 | pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end); |
742 | return 0; | 838 | return 0; |
743 | } | 839 | } |
744 | 840 | ||
@@ -751,36 +847,35 @@ static int grab_bb(u8 *buffer, u64 start, u64 end, | |||
751 | 847 | ||
752 | *is64bit = al.map->dso->is_64_bit; | 848 | *is64bit = al.map->dso->is_64_bit; |
753 | if (len <= 0) | 849 | if (len <= 0) |
754 | printf("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n", | 850 | pr_debug("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n", |
755 | start, end); | 851 | start, end); |
756 | return len; | 852 | return len; |
757 | } | 853 | } |
758 | 854 | ||
759 | static void print_jump(uint64_t ip, struct branch_entry *en, | 855 | static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, |
760 | struct perf_insn *x, u8 *inbuf, int len, | 856 | struct perf_insn *x, u8 *inbuf, int len, |
761 | int insn) | 857 | int insn, FILE *fp) |
762 | { | 858 | { |
763 | printf("\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", | 859 | int printed = fprintf(fp, "\t%016" PRIx64 "\t%-30s\t#%s%s%s%s", ip, |
764 | ip, | 860 | dump_insn(x, ip, inbuf, len, NULL), |
765 | dump_insn(x, ip, inbuf, len, NULL), | 861 | en->flags.predicted ? " PRED" : "", |
766 | en->flags.predicted ? " PRED" : "", | 862 | en->flags.mispred ? " MISPRED" : "", |
767 | en->flags.mispred ? " MISPRED" : "", | 863 | en->flags.in_tx ? " INTX" : "", |
768 | en->flags.in_tx ? " INTX" : "", | 864 | en->flags.abort ? " ABORT" : ""); |
769 | en->flags.abort ? " ABORT" : ""); | ||
770 | if (en->flags.cycles) { | 865 | if (en->flags.cycles) { |
771 | printf(" %d cycles", en->flags.cycles); | 866 | printed += fprintf(fp, " %d cycles", en->flags.cycles); |
772 | if (insn) | 867 | if (insn) |
773 | printf(" %.2f IPC", (float)insn / en->flags.cycles); | 868 | printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles); |
774 | } | 869 | } |
775 | putchar('\n'); | 870 | return printed + fprintf(fp, "\n"); |
776 | } | 871 | } |
777 | 872 | ||
778 | static void print_ip_sym(struct thread *thread, u8 cpumode, int cpu, | 873 | static int ip__fprintf_sym(uint64_t addr, struct thread *thread, |
779 | uint64_t addr, struct symbol **lastsym, | 874 | u8 cpumode, int cpu, struct symbol **lastsym, |
780 | struct perf_event_attr *attr) | 875 | struct perf_event_attr *attr, FILE *fp) |
781 | { | 876 | { |
782 | struct addr_location al; | 877 | struct addr_location al; |
783 | int off; | 878 | int off, printed = 0; |
784 | 879 | ||
785 | memset(&al, 0, sizeof(al)); | 880 | memset(&al, 0, sizeof(al)); |
786 | 881 | ||
@@ -789,7 +884,7 @@ static void print_ip_sym(struct thread *thread, u8 cpumode, int cpu, | |||
789 | thread__find_addr_map(thread, cpumode, MAP__VARIABLE, | 884 | thread__find_addr_map(thread, cpumode, MAP__VARIABLE, |
790 | addr, &al); | 885 | addr, &al); |
791 | if ((*lastsym) && al.addr >= (*lastsym)->start && al.addr < (*lastsym)->end) | 886 | if ((*lastsym) && al.addr >= (*lastsym)->start && al.addr < (*lastsym)->end) |
792 | return; | 887 | return 0; |
793 | 888 | ||
794 | al.cpu = cpu; | 889 | al.cpu = cpu; |
795 | al.sym = NULL; | 890 | al.sym = NULL; |
@@ -797,37 +892,39 @@ static void print_ip_sym(struct thread *thread, u8 cpumode, int cpu, | |||
797 | al.sym = map__find_symbol(al.map, al.addr); | 892 | al.sym = map__find_symbol(al.map, al.addr); |
798 | 893 | ||
799 | if (!al.sym) | 894 | if (!al.sym) |
800 | return; | 895 | return 0; |
801 | 896 | ||
802 | if (al.addr < al.sym->end) | 897 | if (al.addr < al.sym->end) |
803 | off = al.addr - al.sym->start; | 898 | off = al.addr - al.sym->start; |
804 | else | 899 | else |
805 | off = al.addr - al.map->start - al.sym->start; | 900 | off = al.addr - al.map->start - al.sym->start; |
806 | printf("\t%s", al.sym->name); | 901 | printed += fprintf(fp, "\t%s", al.sym->name); |
807 | if (off) | 902 | if (off) |
808 | printf("%+d", off); | 903 | printed += fprintf(fp, "%+d", off); |
809 | putchar(':'); | 904 | printed += fprintf(fp, ":"); |
810 | if (PRINT_FIELD(SRCLINE)) | 905 | if (PRINT_FIELD(SRCLINE)) |
811 | map__fprintf_srcline(al.map, al.addr, "\t", stdout); | 906 | printed += map__fprintf_srcline(al.map, al.addr, "\t", fp); |
812 | putchar('\n'); | 907 | printed += fprintf(fp, "\n"); |
813 | *lastsym = al.sym; | 908 | *lastsym = al.sym; |
909 | |||
910 | return printed; | ||
814 | } | 911 | } |
815 | 912 | ||
816 | static void print_sample_brstackinsn(struct perf_sample *sample, | 913 | static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, |
817 | struct thread *thread, | 914 | struct thread *thread, |
818 | struct perf_event_attr *attr, | 915 | struct perf_event_attr *attr, |
819 | struct machine *machine) | 916 | struct machine *machine, FILE *fp) |
820 | { | 917 | { |
821 | struct branch_stack *br = sample->branch_stack; | 918 | struct branch_stack *br = sample->branch_stack; |
822 | u64 start, end; | 919 | u64 start, end; |
823 | int i, insn, len, nr, ilen; | 920 | int i, insn, len, nr, ilen, printed = 0; |
824 | struct perf_insn x; | 921 | struct perf_insn x; |
825 | u8 buffer[MAXBB]; | 922 | u8 buffer[MAXBB]; |
826 | unsigned off; | 923 | unsigned off; |
827 | struct symbol *lastsym = NULL; | 924 | struct symbol *lastsym = NULL; |
828 | 925 | ||
829 | if (!(br && br->nr)) | 926 | if (!(br && br->nr)) |
830 | return; | 927 | return 0; |
831 | nr = br->nr; | 928 | nr = br->nr; |
832 | if (max_blocks && nr > max_blocks + 1) | 929 | if (max_blocks && nr > max_blocks + 1) |
833 | nr = max_blocks + 1; | 930 | nr = max_blocks + 1; |
@@ -835,17 +932,17 @@ static void print_sample_brstackinsn(struct perf_sample *sample, | |||
835 | x.thread = thread; | 932 | x.thread = thread; |
836 | x.cpu = sample->cpu; | 933 | x.cpu = sample->cpu; |
837 | 934 | ||
838 | putchar('\n'); | 935 | printed += fprintf(fp, "%c", '\n'); |
839 | 936 | ||
840 | /* Handle first from jump, of which we don't know the entry. */ | 937 | /* Handle first from jump, of which we don't know the entry. */ |
841 | len = grab_bb(buffer, br->entries[nr-1].from, | 938 | len = grab_bb(buffer, br->entries[nr-1].from, |
842 | br->entries[nr-1].from, | 939 | br->entries[nr-1].from, |
843 | machine, thread, &x.is64bit, &x.cpumode, false); | 940 | machine, thread, &x.is64bit, &x.cpumode, false); |
844 | if (len > 0) { | 941 | if (len > 0) { |
845 | print_ip_sym(thread, x.cpumode, x.cpu, | 942 | printed += ip__fprintf_sym(br->entries[nr - 1].from, thread, |
846 | br->entries[nr - 1].from, &lastsym, attr); | 943 | x.cpumode, x.cpu, &lastsym, attr, fp); |
847 | print_jump(br->entries[nr - 1].from, &br->entries[nr - 1], | 944 | printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1], |
848 | &x, buffer, len, 0); | 945 | &x, buffer, len, 0, fp); |
849 | } | 946 | } |
850 | 947 | ||
851 | /* Print all blocks */ | 948 | /* Print all blocks */ |
@@ -871,13 +968,13 @@ static void print_sample_brstackinsn(struct perf_sample *sample, | |||
871 | for (off = 0;; off += ilen) { | 968 | for (off = 0;; off += ilen) { |
872 | uint64_t ip = start + off; | 969 | uint64_t ip = start + off; |
873 | 970 | ||
874 | print_ip_sym(thread, x.cpumode, x.cpu, ip, &lastsym, attr); | 971 | printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp); |
875 | if (ip == end) { | 972 | if (ip == end) { |
876 | print_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn); | 973 | printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, insn, fp); |
877 | break; | 974 | break; |
878 | } else { | 975 | } else { |
879 | printf("\t%016" PRIx64 "\t%s\n", ip, | 976 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip, |
880 | dump_insn(&x, ip, buffer + off, len - off, &ilen)); | 977 | dump_insn(&x, ip, buffer + off, len - off, &ilen)); |
881 | if (ilen == 0) | 978 | if (ilen == 0) |
882 | break; | 979 | break; |
883 | insn++; | 980 | insn++; |
@@ -890,9 +987,9 @@ static void print_sample_brstackinsn(struct perf_sample *sample, | |||
890 | * has not been executed yet. | 987 | * has not been executed yet. |
891 | */ | 988 | */ |
892 | if (br->entries[0].from == sample->ip) | 989 | if (br->entries[0].from == sample->ip) |
893 | return; | 990 | goto out; |
894 | if (br->entries[0].flags.abort) | 991 | if (br->entries[0].flags.abort) |
895 | return; | 992 | goto out; |
896 | 993 | ||
897 | /* | 994 | /* |
898 | * Print final block upto sample | 995 | * Print final block upto sample |
@@ -900,58 +997,61 @@ static void print_sample_brstackinsn(struct perf_sample *sample, | |||
900 | start = br->entries[0].to; | 997 | start = br->entries[0].to; |
901 | end = sample->ip; | 998 | end = sample->ip; |
902 | len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, true); | 999 | len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, true); |
903 | print_ip_sym(thread, x.cpumode, x.cpu, start, &lastsym, attr); | 1000 | printed += ip__fprintf_sym(start, thread, x.cpumode, x.cpu, &lastsym, attr, fp); |
904 | if (len <= 0) { | 1001 | if (len <= 0) { |
905 | /* Print at least last IP if basic block did not work */ | 1002 | /* Print at least last IP if basic block did not work */ |
906 | len = grab_bb(buffer, sample->ip, sample->ip, | 1003 | len = grab_bb(buffer, sample->ip, sample->ip, |
907 | machine, thread, &x.is64bit, &x.cpumode, false); | 1004 | machine, thread, &x.is64bit, &x.cpumode, false); |
908 | if (len <= 0) | 1005 | if (len <= 0) |
909 | return; | 1006 | goto out; |
910 | 1007 | ||
911 | printf("\t%016" PRIx64 "\t%s\n", sample->ip, | 1008 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", sample->ip, |
912 | dump_insn(&x, sample->ip, buffer, len, NULL)); | 1009 | dump_insn(&x, sample->ip, buffer, len, NULL)); |
913 | return; | 1010 | goto out; |
914 | } | 1011 | } |
915 | for (off = 0; off <= end - start; off += ilen) { | 1012 | for (off = 0; off <= end - start; off += ilen) { |
916 | printf("\t%016" PRIx64 "\t%s\n", start + off, | 1013 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", start + off, |
917 | dump_insn(&x, start + off, buffer + off, len - off, &ilen)); | 1014 | dump_insn(&x, start + off, buffer + off, len - off, &ilen)); |
918 | if (ilen == 0) | 1015 | if (ilen == 0) |
919 | break; | 1016 | break; |
920 | } | 1017 | } |
1018 | out: | ||
1019 | return printed; | ||
921 | } | 1020 | } |
922 | 1021 | ||
923 | static void print_sample_addr(struct perf_sample *sample, | 1022 | static int perf_sample__fprintf_addr(struct perf_sample *sample, |
924 | struct thread *thread, | 1023 | struct thread *thread, |
925 | struct perf_event_attr *attr) | 1024 | struct perf_event_attr *attr, FILE *fp) |
926 | { | 1025 | { |
927 | struct addr_location al; | 1026 | struct addr_location al; |
928 | 1027 | int printed = fprintf(fp, "%16" PRIx64, sample->addr); | |
929 | printf("%16" PRIx64, sample->addr); | ||
930 | 1028 | ||
931 | if (!sample_addr_correlates_sym(attr)) | 1029 | if (!sample_addr_correlates_sym(attr)) |
932 | return; | 1030 | goto out; |
933 | 1031 | ||
934 | thread__resolve(thread, &al, sample); | 1032 | thread__resolve(thread, &al, sample); |
935 | 1033 | ||
936 | if (PRINT_FIELD(SYM)) { | 1034 | if (PRINT_FIELD(SYM)) { |
937 | printf(" "); | 1035 | printed += fprintf(fp, " "); |
938 | if (PRINT_FIELD(SYMOFFSET)) | 1036 | if (PRINT_FIELD(SYMOFFSET)) |
939 | symbol__fprintf_symname_offs(al.sym, &al, stdout); | 1037 | printed += symbol__fprintf_symname_offs(al.sym, &al, fp); |
940 | else | 1038 | else |
941 | symbol__fprintf_symname(al.sym, stdout); | 1039 | printed += symbol__fprintf_symname(al.sym, fp); |
942 | } | 1040 | } |
943 | 1041 | ||
944 | if (PRINT_FIELD(DSO)) { | 1042 | if (PRINT_FIELD(DSO)) { |
945 | printf(" ("); | 1043 | printed += fprintf(fp, " ("); |
946 | map__fprintf_dsoname(al.map, stdout); | 1044 | printed += map__fprintf_dsoname(al.map, fp); |
947 | printf(")"); | 1045 | printed += fprintf(fp, ")"); |
948 | } | 1046 | } |
1047 | out: | ||
1048 | return printed; | ||
949 | } | 1049 | } |
950 | 1050 | ||
951 | static void print_sample_callindent(struct perf_sample *sample, | 1051 | static int perf_sample__fprintf_callindent(struct perf_sample *sample, |
952 | struct perf_evsel *evsel, | 1052 | struct perf_evsel *evsel, |
953 | struct thread *thread, | 1053 | struct thread *thread, |
954 | struct addr_location *al) | 1054 | struct addr_location *al, FILE *fp) |
955 | { | 1055 | { |
956 | struct perf_event_attr *attr = &evsel->attr; | 1056 | struct perf_event_attr *attr = &evsel->attr; |
957 | size_t depth = thread_stack__depth(thread); | 1057 | size_t depth = thread_stack__depth(thread); |
@@ -986,12 +1086,12 @@ static void print_sample_callindent(struct perf_sample *sample, | |||
986 | } | 1086 | } |
987 | 1087 | ||
988 | if (name) | 1088 | if (name) |
989 | len = printf("%*s%s", (int)depth * 4, "", name); | 1089 | len = fprintf(fp, "%*s%s", (int)depth * 4, "", name); |
990 | else if (ip) | 1090 | else if (ip) |
991 | len = printf("%*s%16" PRIx64, (int)depth * 4, "", ip); | 1091 | len = fprintf(fp, "%*s%16" PRIx64, (int)depth * 4, "", ip); |
992 | 1092 | ||
993 | if (len < 0) | 1093 | if (len < 0) |
994 | return; | 1094 | return len; |
995 | 1095 | ||
996 | /* | 1096 | /* |
997 | * Try to keep the output length from changing frequently so that the | 1097 | * Try to keep the output length from changing frequently so that the |
@@ -1001,39 +1101,46 @@ static void print_sample_callindent(struct perf_sample *sample, | |||
1001 | spacing = round_up(len + 4, 32); | 1101 | spacing = round_up(len + 4, 32); |
1002 | 1102 | ||
1003 | if (len < spacing) | 1103 | if (len < spacing) |
1004 | printf("%*s", spacing - len, ""); | 1104 | len += fprintf(fp, "%*s", spacing - len, ""); |
1105 | |||
1106 | return len; | ||
1005 | } | 1107 | } |
1006 | 1108 | ||
1007 | static void print_insn(struct perf_sample *sample, | 1109 | static int perf_sample__fprintf_insn(struct perf_sample *sample, |
1008 | struct perf_event_attr *attr, | 1110 | struct perf_event_attr *attr, |
1009 | struct thread *thread, | 1111 | struct thread *thread, |
1010 | struct machine *machine) | 1112 | struct machine *machine, FILE *fp) |
1011 | { | 1113 | { |
1114 | int printed = 0; | ||
1115 | |||
1012 | if (PRINT_FIELD(INSNLEN)) | 1116 | if (PRINT_FIELD(INSNLEN)) |
1013 | printf(" ilen: %d", sample->insn_len); | 1117 | printed += fprintf(fp, " ilen: %d", sample->insn_len); |
1014 | if (PRINT_FIELD(INSN)) { | 1118 | if (PRINT_FIELD(INSN)) { |
1015 | int i; | 1119 | int i; |
1016 | 1120 | ||
1017 | printf(" insn:"); | 1121 | printed += fprintf(fp, " insn:"); |
1018 | for (i = 0; i < sample->insn_len; i++) | 1122 | for (i = 0; i < sample->insn_len; i++) |
1019 | printf(" %02x", (unsigned char)sample->insn[i]); | 1123 | printed += fprintf(fp, " %02x", (unsigned char)sample->insn[i]); |
1020 | } | 1124 | } |
1021 | if (PRINT_FIELD(BRSTACKINSN)) | 1125 | if (PRINT_FIELD(BRSTACKINSN)) |
1022 | print_sample_brstackinsn(sample, thread, attr, machine); | 1126 | printed += perf_sample__fprintf_brstackinsn(sample, thread, attr, machine, fp); |
1127 | |||
1128 | return printed; | ||
1023 | } | 1129 | } |
1024 | 1130 | ||
1025 | static void print_sample_bts(struct perf_sample *sample, | 1131 | static int perf_sample__fprintf_bts(struct perf_sample *sample, |
1026 | struct perf_evsel *evsel, | 1132 | struct perf_evsel *evsel, |
1027 | struct thread *thread, | 1133 | struct thread *thread, |
1028 | struct addr_location *al, | 1134 | struct addr_location *al, |
1029 | struct machine *machine) | 1135 | struct machine *machine, FILE *fp) |
1030 | { | 1136 | { |
1031 | struct perf_event_attr *attr = &evsel->attr; | 1137 | struct perf_event_attr *attr = &evsel->attr; |
1032 | unsigned int type = output_type(attr->type); | 1138 | unsigned int type = output_type(attr->type); |
1033 | bool print_srcline_last = false; | 1139 | bool print_srcline_last = false; |
1140 | int printed = 0; | ||
1034 | 1141 | ||
1035 | if (PRINT_FIELD(CALLINDENT)) | 1142 | if (PRINT_FIELD(CALLINDENT)) |
1036 | print_sample_callindent(sample, evsel, thread, al); | 1143 | printed += perf_sample__fprintf_callindent(sample, evsel, thread, al, fp); |
1037 | 1144 | ||
1038 | /* print branch_from information */ | 1145 | /* print branch_from information */ |
1039 | if (PRINT_FIELD(IP)) { | 1146 | if (PRINT_FIELD(IP)) { |
@@ -1046,31 +1153,30 @@ static void print_sample_bts(struct perf_sample *sample, | |||
1046 | cursor = &callchain_cursor; | 1153 | cursor = &callchain_cursor; |
1047 | 1154 | ||
1048 | if (cursor == NULL) { | 1155 | if (cursor == NULL) { |
1049 | putchar(' '); | 1156 | printed += fprintf(fp, " "); |
1050 | if (print_opts & EVSEL__PRINT_SRCLINE) { | 1157 | if (print_opts & EVSEL__PRINT_SRCLINE) { |
1051 | print_srcline_last = true; | 1158 | print_srcline_last = true; |
1052 | print_opts &= ~EVSEL__PRINT_SRCLINE; | 1159 | print_opts &= ~EVSEL__PRINT_SRCLINE; |
1053 | } | 1160 | } |
1054 | } else | 1161 | } else |
1055 | putchar('\n'); | 1162 | printed += fprintf(fp, "\n"); |
1056 | 1163 | ||
1057 | sample__fprintf_sym(sample, al, 0, print_opts, cursor, stdout); | 1164 | printed += sample__fprintf_sym(sample, al, 0, print_opts, cursor, fp); |
1058 | } | 1165 | } |
1059 | 1166 | ||
1060 | /* print branch_to information */ | 1167 | /* print branch_to information */ |
1061 | if (PRINT_FIELD(ADDR) || | 1168 | if (PRINT_FIELD(ADDR) || |
1062 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && | 1169 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && |
1063 | !output[type].user_set)) { | 1170 | !output[type].user_set)) { |
1064 | printf(" => "); | 1171 | printed += fprintf(fp, " => "); |
1065 | print_sample_addr(sample, thread, attr); | 1172 | printed += perf_sample__fprintf_addr(sample, thread, attr, fp); |
1066 | } | 1173 | } |
1067 | 1174 | ||
1068 | if (print_srcline_last) | 1175 | if (print_srcline_last) |
1069 | map__fprintf_srcline(al->map, al->addr, "\n ", stdout); | 1176 | printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); |
1070 | |||
1071 | print_insn(sample, attr, thread, machine); | ||
1072 | 1177 | ||
1073 | printf("\n"); | 1178 | printed += perf_sample__fprintf_insn(sample, attr, thread, machine, fp); |
1179 | return printed + fprintf(fp, "\n"); | ||
1074 | } | 1180 | } |
1075 | 1181 | ||
1076 | static struct { | 1182 | static struct { |
@@ -1093,7 +1199,7 @@ static struct { | |||
1093 | {0, NULL} | 1199 | {0, NULL} |
1094 | }; | 1200 | }; |
1095 | 1201 | ||
1096 | static void print_sample_flags(u32 flags) | 1202 | static int perf_sample__fprintf_flags(u32 flags, FILE *fp) |
1097 | { | 1203 | { |
1098 | const char *chars = PERF_IP_FLAG_CHARS; | 1204 | const char *chars = PERF_IP_FLAG_CHARS; |
1099 | const int n = strlen(PERF_IP_FLAG_CHARS); | 1205 | const int n = strlen(PERF_IP_FLAG_CHARS); |
@@ -1120,9 +1226,9 @@ static void print_sample_flags(u32 flags) | |||
1120 | str[pos] = 0; | 1226 | str[pos] = 0; |
1121 | 1227 | ||
1122 | if (name) | 1228 | if (name) |
1123 | printf(" %-7s%4s ", name, in_tx ? "(x)" : ""); | 1229 | return fprintf(fp, " %-7s%4s ", name, in_tx ? "(x)" : ""); |
1124 | else | 1230 | |
1125 | printf(" %-11s ", str); | 1231 | return fprintf(fp, " %-11s ", str); |
1126 | } | 1232 | } |
1127 | 1233 | ||
1128 | struct printer_data { | 1234 | struct printer_data { |
@@ -1131,40 +1237,40 @@ struct printer_data { | |||
1131 | bool is_printable; | 1237 | bool is_printable; |
1132 | }; | 1238 | }; |
1133 | 1239 | ||
1134 | static void | 1240 | static int sample__fprintf_bpf_output(enum binary_printer_ops op, |
1135 | print_sample_bpf_output_printer(enum binary_printer_ops op, | 1241 | unsigned int val, |
1136 | unsigned int val, | 1242 | void *extra, FILE *fp) |
1137 | void *extra) | ||
1138 | { | 1243 | { |
1139 | unsigned char ch = (unsigned char)val; | 1244 | unsigned char ch = (unsigned char)val; |
1140 | struct printer_data *printer_data = extra; | 1245 | struct printer_data *printer_data = extra; |
1246 | int printed = 0; | ||
1141 | 1247 | ||
1142 | switch (op) { | 1248 | switch (op) { |
1143 | case BINARY_PRINT_DATA_BEGIN: | 1249 | case BINARY_PRINT_DATA_BEGIN: |
1144 | printf("\n"); | 1250 | printed += fprintf(fp, "\n"); |
1145 | break; | 1251 | break; |
1146 | case BINARY_PRINT_LINE_BEGIN: | 1252 | case BINARY_PRINT_LINE_BEGIN: |
1147 | printf("%17s", !printer_data->line_no ? "BPF output:" : | 1253 | printed += fprintf(fp, "%17s", !printer_data->line_no ? "BPF output:" : |
1148 | " "); | 1254 | " "); |
1149 | break; | 1255 | break; |
1150 | case BINARY_PRINT_ADDR: | 1256 | case BINARY_PRINT_ADDR: |
1151 | printf(" %04x:", val); | 1257 | printed += fprintf(fp, " %04x:", val); |
1152 | break; | 1258 | break; |
1153 | case BINARY_PRINT_NUM_DATA: | 1259 | case BINARY_PRINT_NUM_DATA: |
1154 | printf(" %02x", val); | 1260 | printed += fprintf(fp, " %02x", val); |
1155 | break; | 1261 | break; |
1156 | case BINARY_PRINT_NUM_PAD: | 1262 | case BINARY_PRINT_NUM_PAD: |
1157 | printf(" "); | 1263 | printed += fprintf(fp, " "); |
1158 | break; | 1264 | break; |
1159 | case BINARY_PRINT_SEP: | 1265 | case BINARY_PRINT_SEP: |
1160 | printf(" "); | 1266 | printed += fprintf(fp, " "); |
1161 | break; | 1267 | break; |
1162 | case BINARY_PRINT_CHAR_DATA: | 1268 | case BINARY_PRINT_CHAR_DATA: |
1163 | if (printer_data->hit_nul && ch) | 1269 | if (printer_data->hit_nul && ch) |
1164 | printer_data->is_printable = false; | 1270 | printer_data->is_printable = false; |
1165 | 1271 | ||
1166 | if (!isprint(ch)) { | 1272 | if (!isprint(ch)) { |
1167 | printf("%c", '.'); | 1273 | printed += fprintf(fp, "%c", '.'); |
1168 | 1274 | ||
1169 | if (!printer_data->is_printable) | 1275 | if (!printer_data->is_printable) |
1170 | break; | 1276 | break; |
@@ -1174,154 +1280,154 @@ print_sample_bpf_output_printer(enum binary_printer_ops op, | |||
1174 | else | 1280 | else |
1175 | printer_data->is_printable = false; | 1281 | printer_data->is_printable = false; |
1176 | } else { | 1282 | } else { |
1177 | printf("%c", ch); | 1283 | printed += fprintf(fp, "%c", ch); |
1178 | } | 1284 | } |
1179 | break; | 1285 | break; |
1180 | case BINARY_PRINT_CHAR_PAD: | 1286 | case BINARY_PRINT_CHAR_PAD: |
1181 | printf(" "); | 1287 | printed += fprintf(fp, " "); |
1182 | break; | 1288 | break; |
1183 | case BINARY_PRINT_LINE_END: | 1289 | case BINARY_PRINT_LINE_END: |
1184 | printf("\n"); | 1290 | printed += fprintf(fp, "\n"); |
1185 | printer_data->line_no++; | 1291 | printer_data->line_no++; |
1186 | break; | 1292 | break; |
1187 | case BINARY_PRINT_DATA_END: | 1293 | case BINARY_PRINT_DATA_END: |
1188 | default: | 1294 | default: |
1189 | break; | 1295 | break; |
1190 | } | 1296 | } |
1297 | |||
1298 | return printed; | ||
1191 | } | 1299 | } |
1192 | 1300 | ||
1193 | static void print_sample_bpf_output(struct perf_sample *sample) | 1301 | static int perf_sample__fprintf_bpf_output(struct perf_sample *sample, FILE *fp) |
1194 | { | 1302 | { |
1195 | unsigned int nr_bytes = sample->raw_size; | 1303 | unsigned int nr_bytes = sample->raw_size; |
1196 | struct printer_data printer_data = {0, false, true}; | 1304 | struct printer_data printer_data = {0, false, true}; |
1197 | 1305 | int printed = binary__fprintf(sample->raw_data, nr_bytes, 8, | |
1198 | print_binary(sample->raw_data, nr_bytes, 8, | 1306 | sample__fprintf_bpf_output, &printer_data, fp); |
1199 | print_sample_bpf_output_printer, &printer_data); | ||
1200 | 1307 | ||
1201 | if (printer_data.is_printable && printer_data.hit_nul) | 1308 | if (printer_data.is_printable && printer_data.hit_nul) |
1202 | printf("%17s \"%s\"\n", "BPF string:", | 1309 | printed += fprintf(fp, "%17s \"%s\"\n", "BPF string:", (char *)(sample->raw_data)); |
1203 | (char *)(sample->raw_data)); | 1310 | |
1311 | return printed; | ||
1204 | } | 1312 | } |
1205 | 1313 | ||
1206 | static void print_sample_spacing(int len, int spacing) | 1314 | static int perf_sample__fprintf_spacing(int len, int spacing, FILE *fp) |
1207 | { | 1315 | { |
1208 | if (len > 0 && len < spacing) | 1316 | if (len > 0 && len < spacing) |
1209 | printf("%*s", spacing - len, ""); | 1317 | return fprintf(fp, "%*s", spacing - len, ""); |
1318 | |||
1319 | return 0; | ||
1210 | } | 1320 | } |
1211 | 1321 | ||
1212 | static void print_sample_pt_spacing(int len) | 1322 | static int perf_sample__fprintf_pt_spacing(int len, FILE *fp) |
1213 | { | 1323 | { |
1214 | print_sample_spacing(len, 34); | 1324 | return perf_sample__fprintf_spacing(len, 34, fp); |
1215 | } | 1325 | } |
1216 | 1326 | ||
1217 | static void print_sample_synth_ptwrite(struct perf_sample *sample) | 1327 | static int perf_sample__fprintf_synth_ptwrite(struct perf_sample *sample, FILE *fp) |
1218 | { | 1328 | { |
1219 | struct perf_synth_intel_ptwrite *data = perf_sample__synth_ptr(sample); | 1329 | struct perf_synth_intel_ptwrite *data = perf_sample__synth_ptr(sample); |
1220 | int len; | 1330 | int len; |
1221 | 1331 | ||
1222 | if (perf_sample__bad_synth_size(sample, *data)) | 1332 | if (perf_sample__bad_synth_size(sample, *data)) |
1223 | return; | 1333 | return 0; |
1224 | 1334 | ||
1225 | len = printf(" IP: %u payload: %#" PRIx64 " ", | 1335 | len = fprintf(fp, " IP: %u payload: %#" PRIx64 " ", |
1226 | data->ip, le64_to_cpu(data->payload)); | 1336 | data->ip, le64_to_cpu(data->payload)); |
1227 | print_sample_pt_spacing(len); | 1337 | return len + perf_sample__fprintf_pt_spacing(len, fp); |
1228 | } | 1338 | } |
1229 | 1339 | ||
1230 | static void print_sample_synth_mwait(struct perf_sample *sample) | 1340 | static int perf_sample__fprintf_synth_mwait(struct perf_sample *sample, FILE *fp) |
1231 | { | 1341 | { |
1232 | struct perf_synth_intel_mwait *data = perf_sample__synth_ptr(sample); | 1342 | struct perf_synth_intel_mwait *data = perf_sample__synth_ptr(sample); |
1233 | int len; | 1343 | int len; |
1234 | 1344 | ||
1235 | if (perf_sample__bad_synth_size(sample, *data)) | 1345 | if (perf_sample__bad_synth_size(sample, *data)) |
1236 | return; | 1346 | return 0; |
1237 | 1347 | ||
1238 | len = printf(" hints: %#x extensions: %#x ", | 1348 | len = fprintf(fp, " hints: %#x extensions: %#x ", |
1239 | data->hints, data->extensions); | 1349 | data->hints, data->extensions); |
1240 | print_sample_pt_spacing(len); | 1350 | return len + perf_sample__fprintf_pt_spacing(len, fp); |
1241 | } | 1351 | } |
1242 | 1352 | ||
1243 | static void print_sample_synth_pwre(struct perf_sample *sample) | 1353 | static int perf_sample__fprintf_synth_pwre(struct perf_sample *sample, FILE *fp) |
1244 | { | 1354 | { |
1245 | struct perf_synth_intel_pwre *data = perf_sample__synth_ptr(sample); | 1355 | struct perf_synth_intel_pwre *data = perf_sample__synth_ptr(sample); |
1246 | int len; | 1356 | int len; |
1247 | 1357 | ||
1248 | if (perf_sample__bad_synth_size(sample, *data)) | 1358 | if (perf_sample__bad_synth_size(sample, *data)) |
1249 | return; | 1359 | return 0; |
1250 | 1360 | ||
1251 | len = printf(" hw: %u cstate: %u sub-cstate: %u ", | 1361 | len = fprintf(fp, " hw: %u cstate: %u sub-cstate: %u ", |
1252 | data->hw, data->cstate, data->subcstate); | 1362 | data->hw, data->cstate, data->subcstate); |
1253 | print_sample_pt_spacing(len); | 1363 | return len + perf_sample__fprintf_pt_spacing(len, fp); |
1254 | } | 1364 | } |
1255 | 1365 | ||
1256 | static void print_sample_synth_exstop(struct perf_sample *sample) | 1366 | static int perf_sample__fprintf_synth_exstop(struct perf_sample *sample, FILE *fp) |
1257 | { | 1367 | { |
1258 | struct perf_synth_intel_exstop *data = perf_sample__synth_ptr(sample); | 1368 | struct perf_synth_intel_exstop *data = perf_sample__synth_ptr(sample); |
1259 | int len; | 1369 | int len; |
1260 | 1370 | ||
1261 | if (perf_sample__bad_synth_size(sample, *data)) | 1371 | if (perf_sample__bad_synth_size(sample, *data)) |
1262 | return; | 1372 | return 0; |
1263 | 1373 | ||
1264 | len = printf(" IP: %u ", data->ip); | 1374 | len = fprintf(fp, " IP: %u ", data->ip); |
1265 | print_sample_pt_spacing(len); | 1375 | return len + perf_sample__fprintf_pt_spacing(len, fp); |
1266 | } | 1376 | } |
1267 | 1377 | ||
1268 | static void print_sample_synth_pwrx(struct perf_sample *sample) | 1378 | static int perf_sample__fprintf_synth_pwrx(struct perf_sample *sample, FILE *fp) |
1269 | { | 1379 | { |
1270 | struct perf_synth_intel_pwrx *data = perf_sample__synth_ptr(sample); | 1380 | struct perf_synth_intel_pwrx *data = perf_sample__synth_ptr(sample); |
1271 | int len; | 1381 | int len; |
1272 | 1382 | ||
1273 | if (perf_sample__bad_synth_size(sample, *data)) | 1383 | if (perf_sample__bad_synth_size(sample, *data)) |
1274 | return; | 1384 | return 0; |
1275 | 1385 | ||
1276 | len = printf(" deepest cstate: %u last cstate: %u wake reason: %#x ", | 1386 | len = fprintf(fp, " deepest cstate: %u last cstate: %u wake reason: %#x ", |
1277 | data->deepest_cstate, data->last_cstate, | 1387 | data->deepest_cstate, data->last_cstate, |
1278 | data->wake_reason); | 1388 | data->wake_reason); |
1279 | print_sample_pt_spacing(len); | 1389 | return len + perf_sample__fprintf_pt_spacing(len, fp); |
1280 | } | 1390 | } |
1281 | 1391 | ||
1282 | static void print_sample_synth_cbr(struct perf_sample *sample) | 1392 | static int perf_sample__fprintf_synth_cbr(struct perf_sample *sample, FILE *fp) |
1283 | { | 1393 | { |
1284 | struct perf_synth_intel_cbr *data = perf_sample__synth_ptr(sample); | 1394 | struct perf_synth_intel_cbr *data = perf_sample__synth_ptr(sample); |
1285 | unsigned int percent, freq; | 1395 | unsigned int percent, freq; |
1286 | int len; | 1396 | int len; |
1287 | 1397 | ||
1288 | if (perf_sample__bad_synth_size(sample, *data)) | 1398 | if (perf_sample__bad_synth_size(sample, *data)) |
1289 | return; | 1399 | return 0; |
1290 | 1400 | ||
1291 | freq = (le32_to_cpu(data->freq) + 500) / 1000; | 1401 | freq = (le32_to_cpu(data->freq) + 500) / 1000; |
1292 | len = printf(" cbr: %2u freq: %4u MHz ", data->cbr, freq); | 1402 | len = fprintf(fp, " cbr: %2u freq: %4u MHz ", data->cbr, freq); |
1293 | if (data->max_nonturbo) { | 1403 | if (data->max_nonturbo) { |
1294 | percent = (5 + (1000 * data->cbr) / data->max_nonturbo) / 10; | 1404 | percent = (5 + (1000 * data->cbr) / data->max_nonturbo) / 10; |
1295 | len += printf("(%3u%%) ", percent); | 1405 | len += fprintf(fp, "(%3u%%) ", percent); |
1296 | } | 1406 | } |
1297 | print_sample_pt_spacing(len); | 1407 | return len + perf_sample__fprintf_pt_spacing(len, fp); |
1298 | } | 1408 | } |
1299 | 1409 | ||
1300 | static void print_sample_synth(struct perf_sample *sample, | 1410 | static int perf_sample__fprintf_synth(struct perf_sample *sample, |
1301 | struct perf_evsel *evsel) | 1411 | struct perf_evsel *evsel, FILE *fp) |
1302 | { | 1412 | { |
1303 | switch (evsel->attr.config) { | 1413 | switch (evsel->attr.config) { |
1304 | case PERF_SYNTH_INTEL_PTWRITE: | 1414 | case PERF_SYNTH_INTEL_PTWRITE: |
1305 | print_sample_synth_ptwrite(sample); | 1415 | return perf_sample__fprintf_synth_ptwrite(sample, fp); |
1306 | break; | ||
1307 | case PERF_SYNTH_INTEL_MWAIT: | 1416 | case PERF_SYNTH_INTEL_MWAIT: |
1308 | print_sample_synth_mwait(sample); | 1417 | return perf_sample__fprintf_synth_mwait(sample, fp); |
1309 | break; | ||
1310 | case PERF_SYNTH_INTEL_PWRE: | 1418 | case PERF_SYNTH_INTEL_PWRE: |
1311 | print_sample_synth_pwre(sample); | 1419 | return perf_sample__fprintf_synth_pwre(sample, fp); |
1312 | break; | ||
1313 | case PERF_SYNTH_INTEL_EXSTOP: | 1420 | case PERF_SYNTH_INTEL_EXSTOP: |
1314 | print_sample_synth_exstop(sample); | 1421 | return perf_sample__fprintf_synth_exstop(sample, fp); |
1315 | break; | ||
1316 | case PERF_SYNTH_INTEL_PWRX: | 1422 | case PERF_SYNTH_INTEL_PWRX: |
1317 | print_sample_synth_pwrx(sample); | 1423 | return perf_sample__fprintf_synth_pwrx(sample, fp); |
1318 | break; | ||
1319 | case PERF_SYNTH_INTEL_CBR: | 1424 | case PERF_SYNTH_INTEL_CBR: |
1320 | print_sample_synth_cbr(sample); | 1425 | return perf_sample__fprintf_synth_cbr(sample, fp); |
1321 | break; | ||
1322 | default: | 1426 | default: |
1323 | break; | 1427 | break; |
1324 | } | 1428 | } |
1429 | |||
1430 | return 0; | ||
1325 | } | 1431 | } |
1326 | 1432 | ||
1327 | struct perf_script { | 1433 | struct perf_script { |
@@ -1332,6 +1438,7 @@ struct perf_script { | |||
1332 | bool show_switch_events; | 1438 | bool show_switch_events; |
1333 | bool show_namespace_events; | 1439 | bool show_namespace_events; |
1334 | bool allocated; | 1440 | bool allocated; |
1441 | bool per_event_dump; | ||
1335 | struct cpu_map *cpus; | 1442 | struct cpu_map *cpus; |
1336 | struct thread_map *threads; | 1443 | struct thread_map *threads; |
1337 | int name_width; | 1444 | int name_width; |
@@ -1353,7 +1460,7 @@ static int perf_evlist__max_name_len(struct perf_evlist *evlist) | |||
1353 | return max; | 1460 | return max; |
1354 | } | 1461 | } |
1355 | 1462 | ||
1356 | static size_t data_src__printf(u64 data_src) | 1463 | static int data_src__fprintf(u64 data_src, FILE *fp) |
1357 | { | 1464 | { |
1358 | struct mem_info mi = { .data_src.val = data_src }; | 1465 | struct mem_info mi = { .data_src.val = data_src }; |
1359 | char decode[100]; | 1466 | char decode[100]; |
@@ -1367,7 +1474,7 @@ static size_t data_src__printf(u64 data_src) | |||
1367 | if (maxlen < len) | 1474 | if (maxlen < len) |
1368 | maxlen = len; | 1475 | maxlen = len; |
1369 | 1476 | ||
1370 | return printf("%-*s", maxlen, out); | 1477 | return fprintf(fp, "%-*s", maxlen, out); |
1371 | } | 1478 | } |
1372 | 1479 | ||
1373 | static void process_event(struct perf_script *script, | 1480 | static void process_event(struct perf_script *script, |
@@ -1378,14 +1485,18 @@ static void process_event(struct perf_script *script, | |||
1378 | struct thread *thread = al->thread; | 1485 | struct thread *thread = al->thread; |
1379 | struct perf_event_attr *attr = &evsel->attr; | 1486 | struct perf_event_attr *attr = &evsel->attr; |
1380 | unsigned int type = output_type(attr->type); | 1487 | unsigned int type = output_type(attr->type); |
1488 | struct perf_evsel_script *es = evsel->priv; | ||
1489 | FILE *fp = es->fp; | ||
1381 | 1490 | ||
1382 | if (output[type].fields == 0) | 1491 | if (output[type].fields == 0) |
1383 | return; | 1492 | return; |
1384 | 1493 | ||
1385 | print_sample_start(sample, thread, evsel); | 1494 | ++es->samples; |
1495 | |||
1496 | perf_sample__fprintf_start(sample, thread, evsel, fp); | ||
1386 | 1497 | ||
1387 | if (PRINT_FIELD(PERIOD)) | 1498 | if (PRINT_FIELD(PERIOD)) |
1388 | printf("%10" PRIu64 " ", sample->period); | 1499 | fprintf(fp, "%10" PRIu64 " ", sample->period); |
1389 | 1500 | ||
1390 | if (PRINT_FIELD(EVNAME)) { | 1501 | if (PRINT_FIELD(EVNAME)) { |
1391 | const char *evname = perf_evsel__name(evsel); | 1502 | const char *evname = perf_evsel__name(evsel); |
@@ -1393,33 +1504,33 @@ static void process_event(struct perf_script *script, | |||
1393 | if (!script->name_width) | 1504 | if (!script->name_width) |
1394 | script->name_width = perf_evlist__max_name_len(script->session->evlist); | 1505 | script->name_width = perf_evlist__max_name_len(script->session->evlist); |
1395 | 1506 | ||
1396 | printf("%*s: ", script->name_width, | 1507 | fprintf(fp, "%*s: ", script->name_width, evname ?: "[unknown]"); |
1397 | evname ? evname : "[unknown]"); | ||
1398 | } | 1508 | } |
1399 | 1509 | ||
1400 | if (print_flags) | 1510 | if (print_flags) |
1401 | print_sample_flags(sample->flags); | 1511 | perf_sample__fprintf_flags(sample->flags, fp); |
1402 | 1512 | ||
1403 | if (is_bts_event(attr)) { | 1513 | if (is_bts_event(attr)) { |
1404 | print_sample_bts(sample, evsel, thread, al, machine); | 1514 | perf_sample__fprintf_bts(sample, evsel, thread, al, machine, fp); |
1405 | return; | 1515 | return; |
1406 | } | 1516 | } |
1407 | 1517 | ||
1408 | if (PRINT_FIELD(TRACE)) | 1518 | if (PRINT_FIELD(TRACE)) { |
1409 | event_format__print(evsel->tp_format, sample->cpu, | 1519 | event_format__fprintf(evsel->tp_format, sample->cpu, |
1410 | sample->raw_data, sample->raw_size); | 1520 | sample->raw_data, sample->raw_size, fp); |
1521 | } | ||
1411 | 1522 | ||
1412 | if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH)) | 1523 | if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH)) |
1413 | print_sample_synth(sample, evsel); | 1524 | perf_sample__fprintf_synth(sample, evsel, fp); |
1414 | 1525 | ||
1415 | if (PRINT_FIELD(ADDR)) | 1526 | if (PRINT_FIELD(ADDR)) |
1416 | print_sample_addr(sample, thread, attr); | 1527 | perf_sample__fprintf_addr(sample, thread, attr, fp); |
1417 | 1528 | ||
1418 | if (PRINT_FIELD(DATA_SRC)) | 1529 | if (PRINT_FIELD(DATA_SRC)) |
1419 | data_src__printf(sample->data_src); | 1530 | data_src__fprintf(sample->data_src, fp); |
1420 | 1531 | ||
1421 | if (PRINT_FIELD(WEIGHT)) | 1532 | if (PRINT_FIELD(WEIGHT)) |
1422 | printf("%16" PRIu64, sample->weight); | 1533 | fprintf(fp, "%16" PRIu64, sample->weight); |
1423 | 1534 | ||
1424 | if (PRINT_FIELD(IP)) { | 1535 | if (PRINT_FIELD(IP)) { |
1425 | struct callchain_cursor *cursor = NULL; | 1536 | struct callchain_cursor *cursor = NULL; |
@@ -1429,24 +1540,30 @@ static void process_event(struct perf_script *script, | |||
1429 | sample, NULL, NULL, scripting_max_stack) == 0) | 1540 | sample, NULL, NULL, scripting_max_stack) == 0) |
1430 | cursor = &callchain_cursor; | 1541 | cursor = &callchain_cursor; |
1431 | 1542 | ||
1432 | putchar(cursor ? '\n' : ' '); | 1543 | fputc(cursor ? '\n' : ' ', fp); |
1433 | sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, stdout); | 1544 | sample__fprintf_sym(sample, al, 0, output[type].print_ip_opts, cursor, fp); |
1434 | } | 1545 | } |
1435 | 1546 | ||
1436 | if (PRINT_FIELD(IREGS)) | 1547 | if (PRINT_FIELD(IREGS)) |
1437 | print_sample_iregs(sample, attr); | 1548 | perf_sample__fprintf_iregs(sample, attr, fp); |
1549 | |||
1550 | if (PRINT_FIELD(UREGS)) | ||
1551 | perf_sample__fprintf_uregs(sample, attr, fp); | ||
1438 | 1552 | ||
1439 | if (PRINT_FIELD(BRSTACK)) | 1553 | if (PRINT_FIELD(BRSTACK)) |
1440 | print_sample_brstack(sample, thread, attr); | 1554 | perf_sample__fprintf_brstack(sample, thread, attr, fp); |
1441 | else if (PRINT_FIELD(BRSTACKSYM)) | 1555 | else if (PRINT_FIELD(BRSTACKSYM)) |
1442 | print_sample_brstacksym(sample, thread, attr); | 1556 | perf_sample__fprintf_brstacksym(sample, thread, attr, fp); |
1443 | else if (PRINT_FIELD(BRSTACKOFF)) | 1557 | else if (PRINT_FIELD(BRSTACKOFF)) |
1444 | print_sample_brstackoff(sample, thread, attr); | 1558 | perf_sample__fprintf_brstackoff(sample, thread, attr, fp); |
1445 | 1559 | ||
1446 | if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) | 1560 | if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) |
1447 | print_sample_bpf_output(sample); | 1561 | perf_sample__fprintf_bpf_output(sample, fp); |
1448 | print_insn(sample, attr, thread, machine); | 1562 | perf_sample__fprintf_insn(sample, attr, thread, machine, fp); |
1449 | printf("\n"); | 1563 | |
1564 | if (PRINT_FIELD(PHYS_ADDR)) | ||
1565 | fprintf(fp, "%16" PRIx64, sample->phys_addr); | ||
1566 | fprintf(fp, "\n"); | ||
1450 | } | 1567 | } |
1451 | 1568 | ||
1452 | static struct scripting_ops *scripting_ops; | 1569 | static struct scripting_ops *scripting_ops; |
@@ -1620,7 +1737,7 @@ static int process_comm_event(struct perf_tool *tool, | |||
1620 | sample->tid = event->comm.tid; | 1737 | sample->tid = event->comm.tid; |
1621 | sample->pid = event->comm.pid; | 1738 | sample->pid = event->comm.pid; |
1622 | } | 1739 | } |
1623 | print_sample_start(sample, thread, evsel); | 1740 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1624 | perf_event__fprintf(event, stdout); | 1741 | perf_event__fprintf(event, stdout); |
1625 | ret = 0; | 1742 | ret = 0; |
1626 | out: | 1743 | out: |
@@ -1655,7 +1772,7 @@ static int process_namespaces_event(struct perf_tool *tool, | |||
1655 | sample->tid = event->namespaces.tid; | 1772 | sample->tid = event->namespaces.tid; |
1656 | sample->pid = event->namespaces.pid; | 1773 | sample->pid = event->namespaces.pid; |
1657 | } | 1774 | } |
1658 | print_sample_start(sample, thread, evsel); | 1775 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1659 | perf_event__fprintf(event, stdout); | 1776 | perf_event__fprintf(event, stdout); |
1660 | ret = 0; | 1777 | ret = 0; |
1661 | out: | 1778 | out: |
@@ -1688,7 +1805,7 @@ static int process_fork_event(struct perf_tool *tool, | |||
1688 | sample->tid = event->fork.tid; | 1805 | sample->tid = event->fork.tid; |
1689 | sample->pid = event->fork.pid; | 1806 | sample->pid = event->fork.pid; |
1690 | } | 1807 | } |
1691 | print_sample_start(sample, thread, evsel); | 1808 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1692 | perf_event__fprintf(event, stdout); | 1809 | perf_event__fprintf(event, stdout); |
1693 | thread__put(thread); | 1810 | thread__put(thread); |
1694 | 1811 | ||
@@ -1717,7 +1834,7 @@ static int process_exit_event(struct perf_tool *tool, | |||
1717 | sample->tid = event->fork.tid; | 1834 | sample->tid = event->fork.tid; |
1718 | sample->pid = event->fork.pid; | 1835 | sample->pid = event->fork.pid; |
1719 | } | 1836 | } |
1720 | print_sample_start(sample, thread, evsel); | 1837 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1721 | perf_event__fprintf(event, stdout); | 1838 | perf_event__fprintf(event, stdout); |
1722 | 1839 | ||
1723 | if (perf_event__process_exit(tool, event, sample, machine) < 0) | 1840 | if (perf_event__process_exit(tool, event, sample, machine) < 0) |
@@ -1752,7 +1869,7 @@ static int process_mmap_event(struct perf_tool *tool, | |||
1752 | sample->tid = event->mmap.tid; | 1869 | sample->tid = event->mmap.tid; |
1753 | sample->pid = event->mmap.pid; | 1870 | sample->pid = event->mmap.pid; |
1754 | } | 1871 | } |
1755 | print_sample_start(sample, thread, evsel); | 1872 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1756 | perf_event__fprintf(event, stdout); | 1873 | perf_event__fprintf(event, stdout); |
1757 | thread__put(thread); | 1874 | thread__put(thread); |
1758 | return 0; | 1875 | return 0; |
@@ -1783,7 +1900,7 @@ static int process_mmap2_event(struct perf_tool *tool, | |||
1783 | sample->tid = event->mmap2.tid; | 1900 | sample->tid = event->mmap2.tid; |
1784 | sample->pid = event->mmap2.pid; | 1901 | sample->pid = event->mmap2.pid; |
1785 | } | 1902 | } |
1786 | print_sample_start(sample, thread, evsel); | 1903 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1787 | perf_event__fprintf(event, stdout); | 1904 | perf_event__fprintf(event, stdout); |
1788 | thread__put(thread); | 1905 | thread__put(thread); |
1789 | return 0; | 1906 | return 0; |
@@ -1809,7 +1926,7 @@ static int process_switch_event(struct perf_tool *tool, | |||
1809 | return -1; | 1926 | return -1; |
1810 | } | 1927 | } |
1811 | 1928 | ||
1812 | print_sample_start(sample, thread, evsel); | 1929 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1813 | perf_event__fprintf(event, stdout); | 1930 | perf_event__fprintf(event, stdout); |
1814 | thread__put(thread); | 1931 | thread__put(thread); |
1815 | return 0; | 1932 | return 0; |
@@ -1820,6 +1937,65 @@ static void sig_handler(int sig __maybe_unused) | |||
1820 | session_done = 1; | 1937 | session_done = 1; |
1821 | } | 1938 | } |
1822 | 1939 | ||
1940 | static void perf_script__fclose_per_event_dump(struct perf_script *script) | ||
1941 | { | ||
1942 | struct perf_evlist *evlist = script->session->evlist; | ||
1943 | struct perf_evsel *evsel; | ||
1944 | |||
1945 | evlist__for_each_entry(evlist, evsel) { | ||
1946 | if (!evsel->priv) | ||
1947 | break; | ||
1948 | perf_evsel_script__delete(evsel->priv); | ||
1949 | evsel->priv = NULL; | ||
1950 | } | ||
1951 | } | ||
1952 | |||
1953 | static int perf_script__fopen_per_event_dump(struct perf_script *script) | ||
1954 | { | ||
1955 | struct perf_evsel *evsel; | ||
1956 | |||
1957 | evlist__for_each_entry(script->session->evlist, evsel) { | ||
1958 | evsel->priv = perf_evsel_script__new(evsel, script->session->data); | ||
1959 | if (evsel->priv == NULL) | ||
1960 | goto out_err_fclose; | ||
1961 | } | ||
1962 | |||
1963 | return 0; | ||
1964 | |||
1965 | out_err_fclose: | ||
1966 | perf_script__fclose_per_event_dump(script); | ||
1967 | return -1; | ||
1968 | } | ||
1969 | |||
1970 | static int perf_script__setup_per_event_dump(struct perf_script *script) | ||
1971 | { | ||
1972 | struct perf_evsel *evsel; | ||
1973 | static struct perf_evsel_script es_stdout; | ||
1974 | |||
1975 | if (script->per_event_dump) | ||
1976 | return perf_script__fopen_per_event_dump(script); | ||
1977 | |||
1978 | es_stdout.fp = stdout; | ||
1979 | |||
1980 | evlist__for_each_entry(script->session->evlist, evsel) | ||
1981 | evsel->priv = &es_stdout; | ||
1982 | |||
1983 | return 0; | ||
1984 | } | ||
1985 | |||
1986 | static void perf_script__exit_per_event_dump_stats(struct perf_script *script) | ||
1987 | { | ||
1988 | struct perf_evsel *evsel; | ||
1989 | |||
1990 | evlist__for_each_entry(script->session->evlist, evsel) { | ||
1991 | struct perf_evsel_script *es = evsel->priv; | ||
1992 | |||
1993 | perf_evsel_script__fprintf(es, stdout); | ||
1994 | perf_evsel_script__delete(es); | ||
1995 | evsel->priv = NULL; | ||
1996 | } | ||
1997 | } | ||
1998 | |||
1823 | static int __cmd_script(struct perf_script *script) | 1999 | static int __cmd_script(struct perf_script *script) |
1824 | { | 2000 | { |
1825 | int ret; | 2001 | int ret; |
@@ -1841,8 +2017,16 @@ static int __cmd_script(struct perf_script *script) | |||
1841 | if (script->show_namespace_events) | 2017 | if (script->show_namespace_events) |
1842 | script->tool.namespaces = process_namespaces_event; | 2018 | script->tool.namespaces = process_namespaces_event; |
1843 | 2019 | ||
2020 | if (perf_script__setup_per_event_dump(script)) { | ||
2021 | pr_err("Couldn't create the per event dump files\n"); | ||
2022 | return -1; | ||
2023 | } | ||
2024 | |||
1844 | ret = perf_session__process_events(script->session); | 2025 | ret = perf_session__process_events(script->session); |
1845 | 2026 | ||
2027 | if (script->per_event_dump) | ||
2028 | perf_script__exit_per_event_dump_stats(script); | ||
2029 | |||
1846 | if (debug_mode) | 2030 | if (debug_mode) |
1847 | pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); | 2031 | pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); |
1848 | 2032 | ||
@@ -2199,16 +2383,11 @@ static struct script_desc *script_desc__findnew(const char *name) | |||
2199 | 2383 | ||
2200 | s = script_desc__new(name); | 2384 | s = script_desc__new(name); |
2201 | if (!s) | 2385 | if (!s) |
2202 | goto out_delete_desc; | 2386 | return NULL; |
2203 | 2387 | ||
2204 | script_desc__add(s); | 2388 | script_desc__add(s); |
2205 | 2389 | ||
2206 | return s; | 2390 | return s; |
2207 | |||
2208 | out_delete_desc: | ||
2209 | script_desc__delete(s); | ||
2210 | |||
2211 | return NULL; | ||
2212 | } | 2391 | } |
2213 | 2392 | ||
2214 | static const char *ends_with(const char *str, const char *suffix) | 2393 | static const char *ends_with(const char *str, const char *suffix) |
@@ -2412,14 +2591,16 @@ int find_scripts(char **scripts_array, char **scripts_path_array) | |||
2412 | char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; | 2591 | char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; |
2413 | DIR *scripts_dir, *lang_dir; | 2592 | DIR *scripts_dir, *lang_dir; |
2414 | struct perf_session *session; | 2593 | struct perf_session *session; |
2415 | struct perf_data_file file = { | 2594 | struct perf_data data = { |
2416 | .path = input_name, | 2595 | .file = { |
2417 | .mode = PERF_DATA_MODE_READ, | 2596 | .path = input_name, |
2597 | }, | ||
2598 | .mode = PERF_DATA_MODE_READ, | ||
2418 | }; | 2599 | }; |
2419 | char *temp; | 2600 | char *temp; |
2420 | int i = 0; | 2601 | int i = 0; |
2421 | 2602 | ||
2422 | session = perf_session__new(&file, false, NULL); | 2603 | session = perf_session__new(&data, false, NULL); |
2423 | if (!session) | 2604 | if (!session) |
2424 | return -1; | 2605 | return -1; |
2425 | 2606 | ||
@@ -2682,6 +2863,7 @@ int cmd_script(int argc, const char **argv) | |||
2682 | .attr = process_attr, | 2863 | .attr = process_attr, |
2683 | .event_update = perf_event__process_event_update, | 2864 | .event_update = perf_event__process_event_update, |
2684 | .tracing_data = perf_event__process_tracing_data, | 2865 | .tracing_data = perf_event__process_tracing_data, |
2866 | .feature = perf_event__process_feature, | ||
2685 | .build_id = perf_event__process_build_id, | 2867 | .build_id = perf_event__process_build_id, |
2686 | .id_index = perf_event__process_id_index, | 2868 | .id_index = perf_event__process_id_index, |
2687 | .auxtrace_info = perf_event__process_auxtrace_info, | 2869 | .auxtrace_info = perf_event__process_auxtrace_info, |
@@ -2696,7 +2878,7 @@ int cmd_script(int argc, const char **argv) | |||
2696 | .ordering_requires_timestamps = true, | 2878 | .ordering_requires_timestamps = true, |
2697 | }, | 2879 | }, |
2698 | }; | 2880 | }; |
2699 | struct perf_data_file file = { | 2881 | struct perf_data data = { |
2700 | .mode = PERF_DATA_MODE_READ, | 2882 | .mode = PERF_DATA_MODE_READ, |
2701 | }; | 2883 | }; |
2702 | const struct option options[] = { | 2884 | const struct option options[] = { |
@@ -2732,8 +2914,8 @@ int cmd_script(int argc, const char **argv) | |||
2732 | "+field to add and -field to remove." | 2914 | "+field to add and -field to remove." |
2733 | "Valid types: hw,sw,trace,raw,synth. " | 2915 | "Valid types: hw,sw,trace,raw,synth. " |
2734 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," | 2916 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," |
2735 | "addr,symoff,period,iregs,brstack,brstacksym,flags," | 2917 | "addr,symoff,period,iregs,uregs,brstack,brstacksym,flags," |
2736 | "bpf-output,callindent,insn,insnlen,brstackinsn,synth", | 2918 | "bpf-output,callindent,insn,insnlen,brstackinsn,synth,phys_addr", |
2737 | parse_output_fields), | 2919 | parse_output_fields), |
2738 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 2920 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
2739 | "system-wide collection from all CPUs"), | 2921 | "system-wide collection from all CPUs"), |
@@ -2764,6 +2946,8 @@ int cmd_script(int argc, const char **argv) | |||
2764 | "Show context switch events (if recorded)"), | 2946 | "Show context switch events (if recorded)"), |
2765 | OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events, | 2947 | OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events, |
2766 | "Show namespace events (if recorded)"), | 2948 | "Show namespace events (if recorded)"), |
2949 | OPT_BOOLEAN('\0', "per-event-dump", &script.per_event_dump, | ||
2950 | "Dump trace output to files named by the monitored events"), | ||
2767 | OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), | 2951 | OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), |
2768 | OPT_INTEGER(0, "max-blocks", &max_blocks, | 2952 | OPT_INTEGER(0, "max-blocks", &max_blocks, |
2769 | "Maximum number of code blocks to dump with brstackinsn"), | 2953 | "Maximum number of code blocks to dump with brstackinsn"), |
@@ -2794,13 +2978,15 @@ int cmd_script(int argc, const char **argv) | |||
2794 | NULL | 2978 | NULL |
2795 | }; | 2979 | }; |
2796 | 2980 | ||
2981 | perf_set_singlethreaded(); | ||
2982 | |||
2797 | setup_scripting(); | 2983 | setup_scripting(); |
2798 | 2984 | ||
2799 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, | 2985 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, |
2800 | PARSE_OPT_STOP_AT_NON_OPTION); | 2986 | PARSE_OPT_STOP_AT_NON_OPTION); |
2801 | 2987 | ||
2802 | file.path = input_name; | 2988 | data.file.path = input_name; |
2803 | file.force = symbol_conf.force; | 2989 | data.force = symbol_conf.force; |
2804 | 2990 | ||
2805 | if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { | 2991 | if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { |
2806 | rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); | 2992 | rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); |
@@ -2967,15 +3153,18 @@ int cmd_script(int argc, const char **argv) | |||
2967 | if (!script_name) | 3153 | if (!script_name) |
2968 | setup_pager(); | 3154 | setup_pager(); |
2969 | 3155 | ||
2970 | session = perf_session__new(&file, false, &script.tool); | 3156 | session = perf_session__new(&data, false, &script.tool); |
2971 | if (session == NULL) | 3157 | if (session == NULL) |
2972 | return -1; | 3158 | return -1; |
2973 | 3159 | ||
2974 | if (header || header_only) { | 3160 | if (header || header_only) { |
3161 | script.tool.show_feat_hdr = SHOW_FEAT_HEADER; | ||
2975 | perf_session__fprintf_info(session, stdout, show_full_info); | 3162 | perf_session__fprintf_info(session, stdout, show_full_info); |
2976 | if (header_only) | 3163 | if (header_only) |
2977 | goto out_delete; | 3164 | goto out_delete; |
2978 | } | 3165 | } |
3166 | if (show_full_info) | ||
3167 | script.tool.show_feat_hdr = SHOW_FEAT_HEADER_FULL_INFO; | ||
2979 | 3168 | ||
2980 | if (symbol__init(&session->header.env) < 0) | 3169 | if (symbol__init(&session->header.env) < 0) |
2981 | goto out_delete; | 3170 | goto out_delete; |
@@ -3005,7 +3194,8 @@ int cmd_script(int argc, const char **argv) | |||
3005 | machine__resolve_kernel_addr, | 3194 | machine__resolve_kernel_addr, |
3006 | &session->machines.host) < 0) { | 3195 | &session->machines.host) < 0) { |
3007 | pr_err("%s: failed to set libtraceevent function resolver\n", __func__); | 3196 | pr_err("%s: failed to set libtraceevent function resolver\n", __func__); |
3008 | return -1; | 3197 | err = -1; |
3198 | goto out_delete; | ||
3009 | } | 3199 | } |
3010 | 3200 | ||
3011 | if (generate_script_lang) { | 3201 | if (generate_script_lang) { |
@@ -3019,7 +3209,7 @@ int cmd_script(int argc, const char **argv) | |||
3019 | goto out_delete; | 3209 | goto out_delete; |
3020 | } | 3210 | } |
3021 | 3211 | ||
3022 | input = open(file.path, O_RDONLY); /* input_name */ | 3212 | input = open(data.file.path, O_RDONLY); /* input_name */ |
3023 | if (input < 0) { | 3213 | if (input < 0) { |
3024 | err = -errno; | 3214 | err = -errno; |
3025 | perror("failed to open file"); | 3215 | perror("failed to open file"); |
@@ -3065,7 +3255,8 @@ int cmd_script(int argc, const char **argv) | |||
3065 | /* needs to be parsed after looking up reference time */ | 3255 | /* needs to be parsed after looking up reference time */ |
3066 | if (perf_time__parse_str(&script.ptime, script.time_str) != 0) { | 3256 | if (perf_time__parse_str(&script.ptime, script.time_str) != 0) { |
3067 | pr_err("Invalid time string\n"); | 3257 | pr_err("Invalid time string\n"); |
3068 | return -EINVAL; | 3258 | err = -EINVAL; |
3259 | goto out_delete; | ||
3069 | } | 3260 | } |
3070 | 3261 | ||
3071 | err = __cmd_script(&script); | 3262 | err = __cmd_script(&script); |