diff options
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r-- | tools/perf/builtin-script.c | 714 |
1 files changed, 447 insertions, 267 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 0fe02758de7d..68f36dc0344f 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -89,6 +89,7 @@ enum perf_output_field { | |||
89 | PERF_OUTPUT_BRSTACKOFF = 1U << 24, | 89 | PERF_OUTPUT_BRSTACKOFF = 1U << 24, |
90 | PERF_OUTPUT_SYNTH = 1U << 25, | 90 | PERF_OUTPUT_SYNTH = 1U << 25, |
91 | PERF_OUTPUT_PHYS_ADDR = 1U << 26, | 91 | PERF_OUTPUT_PHYS_ADDR = 1U << 26, |
92 | PERF_OUTPUT_UREGS = 1U << 27, | ||
92 | }; | 93 | }; |
93 | 94 | ||
94 | struct output_option { | 95 | struct output_option { |
@@ -110,6 +111,7 @@ struct output_option { | |||
110 | {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, | 111 | {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, |
111 | {.str = "period", .field = PERF_OUTPUT_PERIOD}, | 112 | {.str = "period", .field = PERF_OUTPUT_PERIOD}, |
112 | {.str = "iregs", .field = PERF_OUTPUT_IREGS}, | 113 | {.str = "iregs", .field = PERF_OUTPUT_IREGS}, |
114 | {.str = "uregs", .field = PERF_OUTPUT_UREGS}, | ||
113 | {.str = "brstack", .field = PERF_OUTPUT_BRSTACK}, | 115 | {.str = "brstack", .field = PERF_OUTPUT_BRSTACK}, |
114 | {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, | 116 | {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, |
115 | {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC}, | 117 | {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC}, |
@@ -209,6 +211,51 @@ static struct { | |||
209 | }, | 211 | }, |
210 | }; | 212 | }; |
211 | 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 | |||
212 | static inline int output_type(unsigned int type) | 259 | static inline int output_type(unsigned int type) |
213 | { | 260 | { |
214 | switch (type) { | 261 | switch (type) { |
@@ -386,6 +433,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
386 | PERF_OUTPUT_IREGS)) | 433 | PERF_OUTPUT_IREGS)) |
387 | return -EINVAL; | 434 | return -EINVAL; |
388 | 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 | |||
389 | if (PRINT_FIELD(PHYS_ADDR) && | 441 | if (PRINT_FIELD(PHYS_ADDR) && |
390 | perf_evsel__check_stype(evsel, PERF_SAMPLE_PHYS_ADDR, "PHYS_ADDR", | 442 | perf_evsel__check_stype(evsel, PERF_SAMPLE_PHYS_ADDR, "PHYS_ADDR", |
391 | PERF_OUTPUT_PHYS_ADDR)) | 443 | PERF_OUTPUT_PHYS_ADDR)) |
@@ -494,51 +546,76 @@ out: | |||
494 | return 0; | 546 | return 0; |
495 | } | 547 | } |
496 | 548 | ||
497 | static void print_sample_iregs(struct perf_sample *sample, | 549 | static int perf_sample__fprintf_iregs(struct perf_sample *sample, |
498 | struct perf_event_attr *attr) | 550 | struct perf_event_attr *attr, FILE *fp) |
499 | { | 551 | { |
500 | struct regs_dump *regs = &sample->intr_regs; | 552 | struct regs_dump *regs = &sample->intr_regs; |
501 | uint64_t mask = attr->sample_regs_intr; | 553 | uint64_t mask = attr->sample_regs_intr; |
502 | unsigned i = 0, r; | 554 | unsigned i = 0, r; |
555 | int printed = 0; | ||
503 | 556 | ||
504 | if (!regs) | 557 | if (!regs) |
505 | return; | 558 | return 0; |
506 | 559 | ||
507 | for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { | 560 | for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { |
508 | u64 val = regs->regs[i++]; | 561 | u64 val = regs->regs[i++]; |
509 | printf("%5s:0x%"PRIx64" ", perf_reg_name(r), val); | 562 | printed += fprintf(fp, "%5s:0x%"PRIx64" ", perf_reg_name(r), val); |
510 | } | 563 | } |
564 | |||
565 | return printed; | ||
511 | } | 566 | } |
512 | 567 | ||
513 | static void print_sample_start(struct perf_sample *sample, | 568 | static int perf_sample__fprintf_uregs(struct perf_sample *sample, |
514 | struct thread *thread, | 569 | struct perf_event_attr *attr, FILE *fp) |
515 | struct perf_evsel *evsel) | 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); | ||
580 | |||
581 | for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { | ||
582 | u64 val = regs->regs[i++]; | ||
583 | printed += fprintf(fp, "%5s:0x%"PRIx64" ", perf_reg_name(r), val); | ||
584 | } | ||
585 | |||
586 | return printed; | ||
587 | } | ||
588 | |||
589 | static int perf_sample__fprintf_start(struct perf_sample *sample, | ||
590 | struct thread *thread, | ||
591 | struct perf_evsel *evsel, FILE *fp) | ||
516 | { | 592 | { |
517 | struct perf_event_attr *attr = &evsel->attr; | 593 | struct perf_event_attr *attr = &evsel->attr; |
518 | unsigned long secs; | 594 | unsigned long secs; |
519 | unsigned long long nsecs; | 595 | unsigned long long nsecs; |
596 | int printed = 0; | ||
520 | 597 | ||
521 | if (PRINT_FIELD(COMM)) { | 598 | if (PRINT_FIELD(COMM)) { |
522 | if (latency_format) | 599 | if (latency_format) |
523 | printf("%8.8s ", thread__comm_str(thread)); | 600 | printed += fprintf(fp, "%8.8s ", thread__comm_str(thread)); |
524 | else if (PRINT_FIELD(IP) && symbol_conf.use_callchain) | 601 | else if (PRINT_FIELD(IP) && symbol_conf.use_callchain) |
525 | printf("%s ", thread__comm_str(thread)); | 602 | printed += fprintf(fp, "%s ", thread__comm_str(thread)); |
526 | else | 603 | else |
527 | printf("%16s ", thread__comm_str(thread)); | 604 | printed += fprintf(fp, "%16s ", thread__comm_str(thread)); |
528 | } | 605 | } |
529 | 606 | ||
530 | if (PRINT_FIELD(PID) && PRINT_FIELD(TID)) | 607 | if (PRINT_FIELD(PID) && PRINT_FIELD(TID)) |
531 | printf("%5d/%-5d ", sample->pid, sample->tid); | 608 | printed += fprintf(fp, "%5d/%-5d ", sample->pid, sample->tid); |
532 | else if (PRINT_FIELD(PID)) | 609 | else if (PRINT_FIELD(PID)) |
533 | printf("%5d ", sample->pid); | 610 | printed += fprintf(fp, "%5d ", sample->pid); |
534 | else if (PRINT_FIELD(TID)) | 611 | else if (PRINT_FIELD(TID)) |
535 | printf("%5d ", sample->tid); | 612 | printed += fprintf(fp, "%5d ", sample->tid); |
536 | 613 | ||
537 | if (PRINT_FIELD(CPU)) { | 614 | if (PRINT_FIELD(CPU)) { |
538 | if (latency_format) | 615 | if (latency_format) |
539 | printf("%3d ", sample->cpu); | 616 | printed += fprintf(fp, "%3d ", sample->cpu); |
540 | else | 617 | else |
541 | printf("[%03d] ", sample->cpu); | 618 | printed += fprintf(fp, "[%03d] ", sample->cpu); |
542 | } | 619 | } |
543 | 620 | ||
544 | if (PRINT_FIELD(TIME)) { | 621 | if (PRINT_FIELD(TIME)) { |
@@ -547,13 +624,15 @@ static void print_sample_start(struct perf_sample *sample, | |||
547 | nsecs -= secs * NSEC_PER_SEC; | 624 | nsecs -= secs * NSEC_PER_SEC; |
548 | 625 | ||
549 | if (nanosecs) | 626 | if (nanosecs) |
550 | printf("%5lu.%09llu: ", secs, nsecs); | 627 | printed += fprintf(fp, "%5lu.%09llu: ", secs, nsecs); |
551 | else { | 628 | else { |
552 | char sample_time[32]; | 629 | char sample_time[32]; |
553 | timestamp__scnprintf_usec(sample->time, sample_time, sizeof(sample_time)); | 630 | timestamp__scnprintf_usec(sample->time, sample_time, sizeof(sample_time)); |
554 | printf("%12s: ", sample_time); | 631 | printed += fprintf(fp, "%12s: ", sample_time); |
555 | } | 632 | } |
556 | } | 633 | } |
634 | |||
635 | return printed; | ||
557 | } | 636 | } |
558 | 637 | ||
559 | static inline char | 638 | static inline char |
@@ -565,16 +644,17 @@ mispred_str(struct branch_entry *br) | |||
565 | return br->flags.predicted ? 'P' : 'M'; | 644 | return br->flags.predicted ? 'P' : 'M'; |
566 | } | 645 | } |
567 | 646 | ||
568 | static void print_sample_brstack(struct perf_sample *sample, | 647 | static int perf_sample__fprintf_brstack(struct perf_sample *sample, |
569 | struct thread *thread, | 648 | struct thread *thread, |
570 | struct perf_event_attr *attr) | 649 | struct perf_event_attr *attr, FILE *fp) |
571 | { | 650 | { |
572 | struct branch_stack *br = sample->branch_stack; | 651 | struct branch_stack *br = sample->branch_stack; |
573 | struct addr_location alf, alt; | 652 | struct addr_location alf, alt; |
574 | u64 i, from, to; | 653 | u64 i, from, to; |
654 | int printed = 0; | ||
575 | 655 | ||
576 | if (!(br && br->nr)) | 656 | if (!(br && br->nr)) |
577 | return; | 657 | return 0; |
578 | 658 | ||
579 | for (i = 0; i < br->nr; i++) { | 659 | for (i = 0; i < br->nr; i++) { |
580 | from = br->entries[i].from; | 660 | from = br->entries[i].from; |
@@ -587,38 +667,41 @@ static void print_sample_brstack(struct perf_sample *sample, | |||
587 | thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt); | 667 | thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt); |
588 | } | 668 | } |
589 | 669 | ||
590 | printf(" 0x%"PRIx64, from); | 670 | printed += fprintf(fp, " 0x%"PRIx64, from); |
591 | if (PRINT_FIELD(DSO)) { | 671 | if (PRINT_FIELD(DSO)) { |
592 | printf("("); | 672 | printed += fprintf(fp, "("); |
593 | map__fprintf_dsoname(alf.map, stdout); | 673 | printed += map__fprintf_dsoname(alf.map, fp); |
594 | printf(")"); | 674 | printed += fprintf(fp, ")"); |
595 | } | 675 | } |
596 | 676 | ||
597 | printf("/0x%"PRIx64, to); | 677 | printed += fprintf(fp, "/0x%"PRIx64, to); |
598 | if (PRINT_FIELD(DSO)) { | 678 | if (PRINT_FIELD(DSO)) { |
599 | printf("("); | 679 | printed += fprintf(fp, "("); |
600 | map__fprintf_dsoname(alt.map, stdout); | 680 | printed += map__fprintf_dsoname(alt.map, fp); |
601 | printf(")"); | 681 | printed += fprintf(fp, ")"); |
602 | } | 682 | } |
603 | 683 | ||
604 | printf("/%c/%c/%c/%d ", | 684 | printed += fprintf(fp, "/%c/%c/%c/%d ", |
605 | mispred_str( br->entries + i), | 685 | mispred_str( br->entries + i), |
606 | br->entries[i].flags.in_tx? 'X' : '-', | 686 | br->entries[i].flags.in_tx? 'X' : '-', |
607 | br->entries[i].flags.abort? 'A' : '-', | 687 | br->entries[i].flags.abort? 'A' : '-', |
608 | br->entries[i].flags.cycles); | 688 | br->entries[i].flags.cycles); |
609 | } | 689 | } |
690 | |||
691 | return printed; | ||
610 | } | 692 | } |
611 | 693 | ||
612 | static void print_sample_brstacksym(struct perf_sample *sample, | 694 | static int perf_sample__fprintf_brstacksym(struct perf_sample *sample, |
613 | struct thread *thread, | 695 | struct thread *thread, |
614 | struct perf_event_attr *attr) | 696 | struct perf_event_attr *attr, FILE *fp) |
615 | { | 697 | { |
616 | struct branch_stack *br = sample->branch_stack; | 698 | struct branch_stack *br = sample->branch_stack; |
617 | struct addr_location alf, alt; | 699 | struct addr_location alf, alt; |
618 | u64 i, from, to; | 700 | u64 i, from, to; |
701 | int printed = 0; | ||
619 | 702 | ||
620 | if (!(br && br->nr)) | 703 | if (!(br && br->nr)) |
621 | return; | 704 | return 0; |
622 | 705 | ||
623 | for (i = 0; i < br->nr; i++) { | 706 | for (i = 0; i < br->nr; i++) { |
624 | 707 | ||
@@ -635,37 +718,40 @@ static void print_sample_brstacksym(struct perf_sample *sample, | |||
635 | if (alt.map) | 718 | if (alt.map) |
636 | alt.sym = map__find_symbol(alt.map, alt.addr); | 719 | alt.sym = map__find_symbol(alt.map, alt.addr); |
637 | 720 | ||
638 | symbol__fprintf_symname_offs(alf.sym, &alf, stdout); | 721 | printed += symbol__fprintf_symname_offs(alf.sym, &alf, fp); |
639 | if (PRINT_FIELD(DSO)) { | 722 | if (PRINT_FIELD(DSO)) { |
640 | printf("("); | 723 | printed += fprintf(fp, "("); |
641 | map__fprintf_dsoname(alf.map, stdout); | 724 | printed += map__fprintf_dsoname(alf.map, fp); |
642 | printf(")"); | 725 | printed += fprintf(fp, ")"); |
643 | } | 726 | } |
644 | putchar('/'); | 727 | printed += fprintf(fp, "%c", '/'); |
645 | symbol__fprintf_symname_offs(alt.sym, &alt, stdout); | 728 | printed += symbol__fprintf_symname_offs(alt.sym, &alt, fp); |
646 | if (PRINT_FIELD(DSO)) { | 729 | if (PRINT_FIELD(DSO)) { |
647 | printf("("); | 730 | printed += fprintf(fp, "("); |
648 | map__fprintf_dsoname(alt.map, stdout); | 731 | printed += map__fprintf_dsoname(alt.map, fp); |
649 | printf(")"); | 732 | printed += fprintf(fp, ")"); |
650 | } | 733 | } |
651 | printf("/%c/%c/%c/%d ", | 734 | printed += fprintf(fp, "/%c/%c/%c/%d ", |
652 | mispred_str( br->entries + i), | 735 | mispred_str( br->entries + i), |
653 | br->entries[i].flags.in_tx? 'X' : '-', | 736 | br->entries[i].flags.in_tx? 'X' : '-', |
654 | br->entries[i].flags.abort? 'A' : '-', | 737 | br->entries[i].flags.abort? 'A' : '-', |
655 | br->entries[i].flags.cycles); | 738 | br->entries[i].flags.cycles); |
656 | } | 739 | } |
740 | |||
741 | return printed; | ||
657 | } | 742 | } |
658 | 743 | ||
659 | static void print_sample_brstackoff(struct perf_sample *sample, | 744 | static int perf_sample__fprintf_brstackoff(struct perf_sample *sample, |
660 | struct thread *thread, | 745 | struct thread *thread, |
661 | struct perf_event_attr *attr) | 746 | struct perf_event_attr *attr, FILE *fp) |
662 | { | 747 | { |
663 | struct branch_stack *br = sample->branch_stack; | 748 | struct branch_stack *br = sample->branch_stack; |
664 | struct addr_location alf, alt; | 749 | struct addr_location alf, alt; |
665 | u64 i, from, to; | 750 | u64 i, from, to; |
751 | int printed = 0; | ||
666 | 752 | ||
667 | if (!(br && br->nr)) | 753 | if (!(br && br->nr)) |
668 | return; | 754 | return 0; |
669 | 755 | ||
670 | for (i = 0; i < br->nr; i++) { | 756 | for (i = 0; i < br->nr; i++) { |
671 | 757 | ||
@@ -682,24 +768,26 @@ static void print_sample_brstackoff(struct perf_sample *sample, | |||
682 | if (alt.map && !alt.map->dso->adjust_symbols) | 768 | if (alt.map && !alt.map->dso->adjust_symbols) |
683 | to = map__map_ip(alt.map, to); | 769 | to = map__map_ip(alt.map, to); |
684 | 770 | ||
685 | printf(" 0x%"PRIx64, from); | 771 | printed += fprintf(fp, " 0x%"PRIx64, from); |
686 | if (PRINT_FIELD(DSO)) { | 772 | if (PRINT_FIELD(DSO)) { |
687 | printf("("); | 773 | printed += fprintf(fp, "("); |
688 | map__fprintf_dsoname(alf.map, stdout); | 774 | printed += map__fprintf_dsoname(alf.map, fp); |
689 | printf(")"); | 775 | printed += fprintf(fp, ")"); |
690 | } | 776 | } |
691 | printf("/0x%"PRIx64, to); | 777 | printed += fprintf(fp, "/0x%"PRIx64, to); |
692 | if (PRINT_FIELD(DSO)) { | 778 | if (PRINT_FIELD(DSO)) { |
693 | printf("("); | 779 | printed += fprintf(fp, "("); |
694 | map__fprintf_dsoname(alt.map, stdout); | 780 | printed += map__fprintf_dsoname(alt.map, fp); |
695 | printf(")"); | 781 | printed += fprintf(fp, ")"); |
696 | } | 782 | } |
697 | printf("/%c/%c/%c/%d ", | 783 | printed += fprintf(fp, "/%c/%c/%c/%d ", |
698 | mispred_str(br->entries + i), | 784 | mispred_str(br->entries + i), |
699 | br->entries[i].flags.in_tx ? 'X' : '-', | 785 | br->entries[i].flags.in_tx ? 'X' : '-', |
700 | br->entries[i].flags.abort ? 'A' : '-', | 786 | br->entries[i].flags.abort ? 'A' : '-', |
701 | br->entries[i].flags.cycles); | 787 | br->entries[i].flags.cycles); |
702 | } | 788 | } |
789 | |||
790 | return printed; | ||
703 | } | 791 | } |
704 | #define MAXBB 16384UL | 792 | #define MAXBB 16384UL |
705 | 793 | ||
@@ -727,27 +815,26 @@ static int grab_bb(u8 *buffer, u64 start, u64 end, | |||
727 | * but the exit is not. Let the caller patch it up. | 815 | * but the exit is not. Let the caller patch it up. |
728 | */ | 816 | */ |
729 | if (kernel != machine__kernel_ip(machine, end)) { | 817 | if (kernel != machine__kernel_ip(machine, end)) { |
730 | printf("\tblock %" PRIx64 "-%" PRIx64 " transfers between kernel and user\n", | 818 | pr_debug("\tblock %" PRIx64 "-%" PRIx64 " transfers between kernel and user\n", start, end); |
731 | start, end); | ||
732 | return -ENXIO; | 819 | return -ENXIO; |
733 | } | 820 | } |
734 | 821 | ||
735 | memset(&al, 0, sizeof(al)); | 822 | memset(&al, 0, sizeof(al)); |
736 | if (end - start > MAXBB - MAXINSN) { | 823 | if (end - start > MAXBB - MAXINSN) { |
737 | if (last) | 824 | if (last) |
738 | 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); |
739 | else | 826 | else |
740 | 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); |
741 | return 0; | 828 | return 0; |
742 | } | 829 | } |
743 | 830 | ||
744 | thread__find_addr_map(thread, *cpumode, MAP__FUNCTION, start, &al); | 831 | thread__find_addr_map(thread, *cpumode, MAP__FUNCTION, start, &al); |
745 | if (!al.map || !al.map->dso) { | 832 | if (!al.map || !al.map->dso) { |
746 | printf("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end); | 833 | pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end); |
747 | return 0; | 834 | return 0; |
748 | } | 835 | } |
749 | if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR) { | 836 | if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR) { |
750 | printf("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end); | 837 | pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end); |
751 | return 0; | 838 | return 0; |
752 | } | 839 | } |
753 | 840 | ||
@@ -760,36 +847,35 @@ static int grab_bb(u8 *buffer, u64 start, u64 end, | |||
760 | 847 | ||
761 | *is64bit = al.map->dso->is_64_bit; | 848 | *is64bit = al.map->dso->is_64_bit; |
762 | if (len <= 0) | 849 | if (len <= 0) |
763 | printf("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n", | 850 | pr_debug("\tcannot fetch code for block at %" PRIx64 "-%" PRIx64 "\n", |
764 | start, end); | 851 | start, end); |
765 | return len; | 852 | return len; |
766 | } | 853 | } |
767 | 854 | ||
768 | static void print_jump(uint64_t ip, struct branch_entry *en, | 855 | static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en, |
769 | struct perf_insn *x, u8 *inbuf, int len, | 856 | struct perf_insn *x, u8 *inbuf, int len, |
770 | int insn) | 857 | int insn, FILE *fp) |
771 | { | 858 | { |
772 | 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, |
773 | ip, | 860 | dump_insn(x, ip, inbuf, len, NULL), |
774 | dump_insn(x, ip, inbuf, len, NULL), | 861 | en->flags.predicted ? " PRED" : "", |
775 | en->flags.predicted ? " PRED" : "", | 862 | en->flags.mispred ? " MISPRED" : "", |
776 | en->flags.mispred ? " MISPRED" : "", | 863 | en->flags.in_tx ? " INTX" : "", |
777 | en->flags.in_tx ? " INTX" : "", | 864 | en->flags.abort ? " ABORT" : ""); |
778 | en->flags.abort ? " ABORT" : ""); | ||
779 | if (en->flags.cycles) { | 865 | if (en->flags.cycles) { |
780 | printf(" %d cycles", en->flags.cycles); | 866 | printed += fprintf(fp, " %d cycles", en->flags.cycles); |
781 | if (insn) | 867 | if (insn) |
782 | printf(" %.2f IPC", (float)insn / en->flags.cycles); | 868 | printed += fprintf(fp, " %.2f IPC", (float)insn / en->flags.cycles); |
783 | } | 869 | } |
784 | putchar('\n'); | 870 | return printed + fprintf(fp, "\n"); |
785 | } | 871 | } |
786 | 872 | ||
787 | static void print_ip_sym(struct thread *thread, u8 cpumode, int cpu, | 873 | static int ip__fprintf_sym(uint64_t addr, struct thread *thread, |
788 | uint64_t addr, struct symbol **lastsym, | 874 | u8 cpumode, int cpu, struct symbol **lastsym, |
789 | struct perf_event_attr *attr) | 875 | struct perf_event_attr *attr, FILE *fp) |
790 | { | 876 | { |
791 | struct addr_location al; | 877 | struct addr_location al; |
792 | int off; | 878 | int off, printed = 0; |
793 | 879 | ||
794 | memset(&al, 0, sizeof(al)); | 880 | memset(&al, 0, sizeof(al)); |
795 | 881 | ||
@@ -798,7 +884,7 @@ static void print_ip_sym(struct thread *thread, u8 cpumode, int cpu, | |||
798 | thread__find_addr_map(thread, cpumode, MAP__VARIABLE, | 884 | thread__find_addr_map(thread, cpumode, MAP__VARIABLE, |
799 | addr, &al); | 885 | addr, &al); |
800 | if ((*lastsym) && al.addr >= (*lastsym)->start && al.addr < (*lastsym)->end) | 886 | if ((*lastsym) && al.addr >= (*lastsym)->start && al.addr < (*lastsym)->end) |
801 | return; | 887 | return 0; |
802 | 888 | ||
803 | al.cpu = cpu; | 889 | al.cpu = cpu; |
804 | al.sym = NULL; | 890 | al.sym = NULL; |
@@ -806,37 +892,39 @@ static void print_ip_sym(struct thread *thread, u8 cpumode, int cpu, | |||
806 | al.sym = map__find_symbol(al.map, al.addr); | 892 | al.sym = map__find_symbol(al.map, al.addr); |
807 | 893 | ||
808 | if (!al.sym) | 894 | if (!al.sym) |
809 | return; | 895 | return 0; |
810 | 896 | ||
811 | if (al.addr < al.sym->end) | 897 | if (al.addr < al.sym->end) |
812 | off = al.addr - al.sym->start; | 898 | off = al.addr - al.sym->start; |
813 | else | 899 | else |
814 | off = al.addr - al.map->start - al.sym->start; | 900 | off = al.addr - al.map->start - al.sym->start; |
815 | printf("\t%s", al.sym->name); | 901 | printed += fprintf(fp, "\t%s", al.sym->name); |
816 | if (off) | 902 | if (off) |
817 | printf("%+d", off); | 903 | printed += fprintf(fp, "%+d", off); |
818 | putchar(':'); | 904 | printed += fprintf(fp, ":"); |
819 | if (PRINT_FIELD(SRCLINE)) | 905 | if (PRINT_FIELD(SRCLINE)) |
820 | map__fprintf_srcline(al.map, al.addr, "\t", stdout); | 906 | printed += map__fprintf_srcline(al.map, al.addr, "\t", fp); |
821 | putchar('\n'); | 907 | printed += fprintf(fp, "\n"); |
822 | *lastsym = al.sym; | 908 | *lastsym = al.sym; |
909 | |||
910 | return printed; | ||
823 | } | 911 | } |
824 | 912 | ||
825 | static void print_sample_brstackinsn(struct perf_sample *sample, | 913 | static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample, |
826 | struct thread *thread, | 914 | struct thread *thread, |
827 | struct perf_event_attr *attr, | 915 | struct perf_event_attr *attr, |
828 | struct machine *machine) | 916 | struct machine *machine, FILE *fp) |
829 | { | 917 | { |
830 | struct branch_stack *br = sample->branch_stack; | 918 | struct branch_stack *br = sample->branch_stack; |
831 | u64 start, end; | 919 | u64 start, end; |
832 | int i, insn, len, nr, ilen; | 920 | int i, insn, len, nr, ilen, printed = 0; |
833 | struct perf_insn x; | 921 | struct perf_insn x; |
834 | u8 buffer[MAXBB]; | 922 | u8 buffer[MAXBB]; |
835 | unsigned off; | 923 | unsigned off; |
836 | struct symbol *lastsym = NULL; | 924 | struct symbol *lastsym = NULL; |
837 | 925 | ||
838 | if (!(br && br->nr)) | 926 | if (!(br && br->nr)) |
839 | return; | 927 | return 0; |
840 | nr = br->nr; | 928 | nr = br->nr; |
841 | if (max_blocks && nr > max_blocks + 1) | 929 | if (max_blocks && nr > max_blocks + 1) |
842 | nr = max_blocks + 1; | 930 | nr = max_blocks + 1; |
@@ -844,17 +932,17 @@ static void print_sample_brstackinsn(struct perf_sample *sample, | |||
844 | x.thread = thread; | 932 | x.thread = thread; |
845 | x.cpu = sample->cpu; | 933 | x.cpu = sample->cpu; |
846 | 934 | ||
847 | putchar('\n'); | 935 | printed += fprintf(fp, "%c", '\n'); |
848 | 936 | ||
849 | /* 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. */ |
850 | len = grab_bb(buffer, br->entries[nr-1].from, | 938 | len = grab_bb(buffer, br->entries[nr-1].from, |
851 | br->entries[nr-1].from, | 939 | br->entries[nr-1].from, |
852 | machine, thread, &x.is64bit, &x.cpumode, false); | 940 | machine, thread, &x.is64bit, &x.cpumode, false); |
853 | if (len > 0) { | 941 | if (len > 0) { |
854 | print_ip_sym(thread, x.cpumode, x.cpu, | 942 | printed += ip__fprintf_sym(br->entries[nr - 1].from, thread, |
855 | br->entries[nr - 1].from, &lastsym, attr); | 943 | x.cpumode, x.cpu, &lastsym, attr, fp); |
856 | 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], |
857 | &x, buffer, len, 0); | 945 | &x, buffer, len, 0, fp); |
858 | } | 946 | } |
859 | 947 | ||
860 | /* Print all blocks */ | 948 | /* Print all blocks */ |
@@ -880,13 +968,13 @@ static void print_sample_brstackinsn(struct perf_sample *sample, | |||
880 | for (off = 0;; off += ilen) { | 968 | for (off = 0;; off += ilen) { |
881 | uint64_t ip = start + off; | 969 | uint64_t ip = start + off; |
882 | 970 | ||
883 | 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); |
884 | if (ip == end) { | 972 | if (ip == end) { |
885 | 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); |
886 | break; | 974 | break; |
887 | } else { | 975 | } else { |
888 | printf("\t%016" PRIx64 "\t%s\n", ip, | 976 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", ip, |
889 | dump_insn(&x, ip, buffer + off, len - off, &ilen)); | 977 | dump_insn(&x, ip, buffer + off, len - off, &ilen)); |
890 | if (ilen == 0) | 978 | if (ilen == 0) |
891 | break; | 979 | break; |
892 | insn++; | 980 | insn++; |
@@ -899,9 +987,9 @@ static void print_sample_brstackinsn(struct perf_sample *sample, | |||
899 | * has not been executed yet. | 987 | * has not been executed yet. |
900 | */ | 988 | */ |
901 | if (br->entries[0].from == sample->ip) | 989 | if (br->entries[0].from == sample->ip) |
902 | return; | 990 | goto out; |
903 | if (br->entries[0].flags.abort) | 991 | if (br->entries[0].flags.abort) |
904 | return; | 992 | goto out; |
905 | 993 | ||
906 | /* | 994 | /* |
907 | * Print final block upto sample | 995 | * Print final block upto sample |
@@ -909,58 +997,61 @@ static void print_sample_brstackinsn(struct perf_sample *sample, | |||
909 | start = br->entries[0].to; | 997 | start = br->entries[0].to; |
910 | end = sample->ip; | 998 | end = sample->ip; |
911 | 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); |
912 | 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); |
913 | if (len <= 0) { | 1001 | if (len <= 0) { |
914 | /* Print at least last IP if basic block did not work */ | 1002 | /* Print at least last IP if basic block did not work */ |
915 | len = grab_bb(buffer, sample->ip, sample->ip, | 1003 | len = grab_bb(buffer, sample->ip, sample->ip, |
916 | machine, thread, &x.is64bit, &x.cpumode, false); | 1004 | machine, thread, &x.is64bit, &x.cpumode, false); |
917 | if (len <= 0) | 1005 | if (len <= 0) |
918 | return; | 1006 | goto out; |
919 | 1007 | ||
920 | printf("\t%016" PRIx64 "\t%s\n", sample->ip, | 1008 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", sample->ip, |
921 | dump_insn(&x, sample->ip, buffer, len, NULL)); | 1009 | dump_insn(&x, sample->ip, buffer, len, NULL)); |
922 | return; | 1010 | goto out; |
923 | } | 1011 | } |
924 | for (off = 0; off <= end - start; off += ilen) { | 1012 | for (off = 0; off <= end - start; off += ilen) { |
925 | printf("\t%016" PRIx64 "\t%s\n", start + off, | 1013 | printed += fprintf(fp, "\t%016" PRIx64 "\t%s\n", start + off, |
926 | dump_insn(&x, start + off, buffer + off, len - off, &ilen)); | 1014 | dump_insn(&x, start + off, buffer + off, len - off, &ilen)); |
927 | if (ilen == 0) | 1015 | if (ilen == 0) |
928 | break; | 1016 | break; |
929 | } | 1017 | } |
1018 | out: | ||
1019 | return printed; | ||
930 | } | 1020 | } |
931 | 1021 | ||
932 | static void print_sample_addr(struct perf_sample *sample, | 1022 | static int perf_sample__fprintf_addr(struct perf_sample *sample, |
933 | struct thread *thread, | 1023 | struct thread *thread, |
934 | struct perf_event_attr *attr) | 1024 | struct perf_event_attr *attr, FILE *fp) |
935 | { | 1025 | { |
936 | struct addr_location al; | 1026 | struct addr_location al; |
937 | 1027 | int printed = fprintf(fp, "%16" PRIx64, sample->addr); | |
938 | printf("%16" PRIx64, sample->addr); | ||
939 | 1028 | ||
940 | if (!sample_addr_correlates_sym(attr)) | 1029 | if (!sample_addr_correlates_sym(attr)) |
941 | return; | 1030 | goto out; |
942 | 1031 | ||
943 | thread__resolve(thread, &al, sample); | 1032 | thread__resolve(thread, &al, sample); |
944 | 1033 | ||
945 | if (PRINT_FIELD(SYM)) { | 1034 | if (PRINT_FIELD(SYM)) { |
946 | printf(" "); | 1035 | printed += fprintf(fp, " "); |
947 | if (PRINT_FIELD(SYMOFFSET)) | 1036 | if (PRINT_FIELD(SYMOFFSET)) |
948 | symbol__fprintf_symname_offs(al.sym, &al, stdout); | 1037 | printed += symbol__fprintf_symname_offs(al.sym, &al, fp); |
949 | else | 1038 | else |
950 | symbol__fprintf_symname(al.sym, stdout); | 1039 | printed += symbol__fprintf_symname(al.sym, fp); |
951 | } | 1040 | } |
952 | 1041 | ||
953 | if (PRINT_FIELD(DSO)) { | 1042 | if (PRINT_FIELD(DSO)) { |
954 | printf(" ("); | 1043 | printed += fprintf(fp, " ("); |
955 | map__fprintf_dsoname(al.map, stdout); | 1044 | printed += map__fprintf_dsoname(al.map, fp); |
956 | printf(")"); | 1045 | printed += fprintf(fp, ")"); |
957 | } | 1046 | } |
1047 | out: | ||
1048 | return printed; | ||
958 | } | 1049 | } |
959 | 1050 | ||
960 | static void print_sample_callindent(struct perf_sample *sample, | 1051 | static int perf_sample__fprintf_callindent(struct perf_sample *sample, |
961 | struct perf_evsel *evsel, | 1052 | struct perf_evsel *evsel, |
962 | struct thread *thread, | 1053 | struct thread *thread, |
963 | struct addr_location *al) | 1054 | struct addr_location *al, FILE *fp) |
964 | { | 1055 | { |
965 | struct perf_event_attr *attr = &evsel->attr; | 1056 | struct perf_event_attr *attr = &evsel->attr; |
966 | size_t depth = thread_stack__depth(thread); | 1057 | size_t depth = thread_stack__depth(thread); |
@@ -995,12 +1086,12 @@ static void print_sample_callindent(struct perf_sample *sample, | |||
995 | } | 1086 | } |
996 | 1087 | ||
997 | if (name) | 1088 | if (name) |
998 | len = printf("%*s%s", (int)depth * 4, "", name); | 1089 | len = fprintf(fp, "%*s%s", (int)depth * 4, "", name); |
999 | else if (ip) | 1090 | else if (ip) |
1000 | len = printf("%*s%16" PRIx64, (int)depth * 4, "", ip); | 1091 | len = fprintf(fp, "%*s%16" PRIx64, (int)depth * 4, "", ip); |
1001 | 1092 | ||
1002 | if (len < 0) | 1093 | if (len < 0) |
1003 | return; | 1094 | return len; |
1004 | 1095 | ||
1005 | /* | 1096 | /* |
1006 | * 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 |
@@ -1010,39 +1101,46 @@ static void print_sample_callindent(struct perf_sample *sample, | |||
1010 | spacing = round_up(len + 4, 32); | 1101 | spacing = round_up(len + 4, 32); |
1011 | 1102 | ||
1012 | if (len < spacing) | 1103 | if (len < spacing) |
1013 | printf("%*s", spacing - len, ""); | 1104 | len += fprintf(fp, "%*s", spacing - len, ""); |
1105 | |||
1106 | return len; | ||
1014 | } | 1107 | } |
1015 | 1108 | ||
1016 | static void print_insn(struct perf_sample *sample, | 1109 | static int perf_sample__fprintf_insn(struct perf_sample *sample, |
1017 | struct perf_event_attr *attr, | 1110 | struct perf_event_attr *attr, |
1018 | struct thread *thread, | 1111 | struct thread *thread, |
1019 | struct machine *machine) | 1112 | struct machine *machine, FILE *fp) |
1020 | { | 1113 | { |
1114 | int printed = 0; | ||
1115 | |||
1021 | if (PRINT_FIELD(INSNLEN)) | 1116 | if (PRINT_FIELD(INSNLEN)) |
1022 | printf(" ilen: %d", sample->insn_len); | 1117 | printed += fprintf(fp, " ilen: %d", sample->insn_len); |
1023 | if (PRINT_FIELD(INSN)) { | 1118 | if (PRINT_FIELD(INSN)) { |
1024 | int i; | 1119 | int i; |
1025 | 1120 | ||
1026 | printf(" insn:"); | 1121 | printed += fprintf(fp, " insn:"); |
1027 | for (i = 0; i < sample->insn_len; i++) | 1122 | for (i = 0; i < sample->insn_len; i++) |
1028 | printf(" %02x", (unsigned char)sample->insn[i]); | 1123 | printed += fprintf(fp, " %02x", (unsigned char)sample->insn[i]); |
1029 | } | 1124 | } |
1030 | if (PRINT_FIELD(BRSTACKINSN)) | 1125 | if (PRINT_FIELD(BRSTACKINSN)) |
1031 | print_sample_brstackinsn(sample, thread, attr, machine); | 1126 | printed += perf_sample__fprintf_brstackinsn(sample, thread, attr, machine, fp); |
1127 | |||
1128 | return printed; | ||
1032 | } | 1129 | } |
1033 | 1130 | ||
1034 | static void print_sample_bts(struct perf_sample *sample, | 1131 | static int perf_sample__fprintf_bts(struct perf_sample *sample, |
1035 | struct perf_evsel *evsel, | 1132 | struct perf_evsel *evsel, |
1036 | struct thread *thread, | 1133 | struct thread *thread, |
1037 | struct addr_location *al, | 1134 | struct addr_location *al, |
1038 | struct machine *machine) | 1135 | struct machine *machine, FILE *fp) |
1039 | { | 1136 | { |
1040 | struct perf_event_attr *attr = &evsel->attr; | 1137 | struct perf_event_attr *attr = &evsel->attr; |
1041 | unsigned int type = output_type(attr->type); | 1138 | unsigned int type = output_type(attr->type); |
1042 | bool print_srcline_last = false; | 1139 | bool print_srcline_last = false; |
1140 | int printed = 0; | ||
1043 | 1141 | ||
1044 | if (PRINT_FIELD(CALLINDENT)) | 1142 | if (PRINT_FIELD(CALLINDENT)) |
1045 | print_sample_callindent(sample, evsel, thread, al); | 1143 | printed += perf_sample__fprintf_callindent(sample, evsel, thread, al, fp); |
1046 | 1144 | ||
1047 | /* print branch_from information */ | 1145 | /* print branch_from information */ |
1048 | if (PRINT_FIELD(IP)) { | 1146 | if (PRINT_FIELD(IP)) { |
@@ -1055,31 +1153,30 @@ static void print_sample_bts(struct perf_sample *sample, | |||
1055 | cursor = &callchain_cursor; | 1153 | cursor = &callchain_cursor; |
1056 | 1154 | ||
1057 | if (cursor == NULL) { | 1155 | if (cursor == NULL) { |
1058 | putchar(' '); | 1156 | printed += fprintf(fp, " "); |
1059 | if (print_opts & EVSEL__PRINT_SRCLINE) { | 1157 | if (print_opts & EVSEL__PRINT_SRCLINE) { |
1060 | print_srcline_last = true; | 1158 | print_srcline_last = true; |
1061 | print_opts &= ~EVSEL__PRINT_SRCLINE; | 1159 | print_opts &= ~EVSEL__PRINT_SRCLINE; |
1062 | } | 1160 | } |
1063 | } else | 1161 | } else |
1064 | putchar('\n'); | 1162 | printed += fprintf(fp, "\n"); |
1065 | 1163 | ||
1066 | sample__fprintf_sym(sample, al, 0, print_opts, cursor, stdout); | 1164 | printed += sample__fprintf_sym(sample, al, 0, print_opts, cursor, fp); |
1067 | } | 1165 | } |
1068 | 1166 | ||
1069 | /* print branch_to information */ | 1167 | /* print branch_to information */ |
1070 | if (PRINT_FIELD(ADDR) || | 1168 | if (PRINT_FIELD(ADDR) || |
1071 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && | 1169 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && |
1072 | !output[type].user_set)) { | 1170 | !output[type].user_set)) { |
1073 | printf(" => "); | 1171 | printed += fprintf(fp, " => "); |
1074 | print_sample_addr(sample, thread, attr); | 1172 | printed += perf_sample__fprintf_addr(sample, thread, attr, fp); |
1075 | } | 1173 | } |
1076 | 1174 | ||
1077 | if (print_srcline_last) | 1175 | if (print_srcline_last) |
1078 | map__fprintf_srcline(al->map, al->addr, "\n ", stdout); | 1176 | printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); |
1079 | |||
1080 | print_insn(sample, attr, thread, machine); | ||
1081 | 1177 | ||
1082 | printf("\n"); | 1178 | printed += perf_sample__fprintf_insn(sample, attr, thread, machine, fp); |
1179 | return printed + fprintf(fp, "\n"); | ||
1083 | } | 1180 | } |
1084 | 1181 | ||
1085 | static struct { | 1182 | static struct { |
@@ -1102,7 +1199,7 @@ static struct { | |||
1102 | {0, NULL} | 1199 | {0, NULL} |
1103 | }; | 1200 | }; |
1104 | 1201 | ||
1105 | static void print_sample_flags(u32 flags) | 1202 | static int perf_sample__fprintf_flags(u32 flags, FILE *fp) |
1106 | { | 1203 | { |
1107 | const char *chars = PERF_IP_FLAG_CHARS; | 1204 | const char *chars = PERF_IP_FLAG_CHARS; |
1108 | const int n = strlen(PERF_IP_FLAG_CHARS); | 1205 | const int n = strlen(PERF_IP_FLAG_CHARS); |
@@ -1129,9 +1226,9 @@ static void print_sample_flags(u32 flags) | |||
1129 | str[pos] = 0; | 1226 | str[pos] = 0; |
1130 | 1227 | ||
1131 | if (name) | 1228 | if (name) |
1132 | printf(" %-7s%4s ", name, in_tx ? "(x)" : ""); | 1229 | return fprintf(fp, " %-7s%4s ", name, in_tx ? "(x)" : ""); |
1133 | else | 1230 | |
1134 | printf(" %-11s ", str); | 1231 | return fprintf(fp, " %-11s ", str); |
1135 | } | 1232 | } |
1136 | 1233 | ||
1137 | struct printer_data { | 1234 | struct printer_data { |
@@ -1140,40 +1237,40 @@ struct printer_data { | |||
1140 | bool is_printable; | 1237 | bool is_printable; |
1141 | }; | 1238 | }; |
1142 | 1239 | ||
1143 | static void | 1240 | static int sample__fprintf_bpf_output(enum binary_printer_ops op, |
1144 | print_sample_bpf_output_printer(enum binary_printer_ops op, | 1241 | unsigned int val, |
1145 | unsigned int val, | 1242 | void *extra, FILE *fp) |
1146 | void *extra) | ||
1147 | { | 1243 | { |
1148 | unsigned char ch = (unsigned char)val; | 1244 | unsigned char ch = (unsigned char)val; |
1149 | struct printer_data *printer_data = extra; | 1245 | struct printer_data *printer_data = extra; |
1246 | int printed = 0; | ||
1150 | 1247 | ||
1151 | switch (op) { | 1248 | switch (op) { |
1152 | case BINARY_PRINT_DATA_BEGIN: | 1249 | case BINARY_PRINT_DATA_BEGIN: |
1153 | printf("\n"); | 1250 | printed += fprintf(fp, "\n"); |
1154 | break; | 1251 | break; |
1155 | case BINARY_PRINT_LINE_BEGIN: | 1252 | case BINARY_PRINT_LINE_BEGIN: |
1156 | printf("%17s", !printer_data->line_no ? "BPF output:" : | 1253 | printed += fprintf(fp, "%17s", !printer_data->line_no ? "BPF output:" : |
1157 | " "); | 1254 | " "); |
1158 | break; | 1255 | break; |
1159 | case BINARY_PRINT_ADDR: | 1256 | case BINARY_PRINT_ADDR: |
1160 | printf(" %04x:", val); | 1257 | printed += fprintf(fp, " %04x:", val); |
1161 | break; | 1258 | break; |
1162 | case BINARY_PRINT_NUM_DATA: | 1259 | case BINARY_PRINT_NUM_DATA: |
1163 | printf(" %02x", val); | 1260 | printed += fprintf(fp, " %02x", val); |
1164 | break; | 1261 | break; |
1165 | case BINARY_PRINT_NUM_PAD: | 1262 | case BINARY_PRINT_NUM_PAD: |
1166 | printf(" "); | 1263 | printed += fprintf(fp, " "); |
1167 | break; | 1264 | break; |
1168 | case BINARY_PRINT_SEP: | 1265 | case BINARY_PRINT_SEP: |
1169 | printf(" "); | 1266 | printed += fprintf(fp, " "); |
1170 | break; | 1267 | break; |
1171 | case BINARY_PRINT_CHAR_DATA: | 1268 | case BINARY_PRINT_CHAR_DATA: |
1172 | if (printer_data->hit_nul && ch) | 1269 | if (printer_data->hit_nul && ch) |
1173 | printer_data->is_printable = false; | 1270 | printer_data->is_printable = false; |
1174 | 1271 | ||
1175 | if (!isprint(ch)) { | 1272 | if (!isprint(ch)) { |
1176 | printf("%c", '.'); | 1273 | printed += fprintf(fp, "%c", '.'); |
1177 | 1274 | ||
1178 | if (!printer_data->is_printable) | 1275 | if (!printer_data->is_printable) |
1179 | break; | 1276 | break; |
@@ -1183,154 +1280,154 @@ print_sample_bpf_output_printer(enum binary_printer_ops op, | |||
1183 | else | 1280 | else |
1184 | printer_data->is_printable = false; | 1281 | printer_data->is_printable = false; |
1185 | } else { | 1282 | } else { |
1186 | printf("%c", ch); | 1283 | printed += fprintf(fp, "%c", ch); |
1187 | } | 1284 | } |
1188 | break; | 1285 | break; |
1189 | case BINARY_PRINT_CHAR_PAD: | 1286 | case BINARY_PRINT_CHAR_PAD: |
1190 | printf(" "); | 1287 | printed += fprintf(fp, " "); |
1191 | break; | 1288 | break; |
1192 | case BINARY_PRINT_LINE_END: | 1289 | case BINARY_PRINT_LINE_END: |
1193 | printf("\n"); | 1290 | printed += fprintf(fp, "\n"); |
1194 | printer_data->line_no++; | 1291 | printer_data->line_no++; |
1195 | break; | 1292 | break; |
1196 | case BINARY_PRINT_DATA_END: | 1293 | case BINARY_PRINT_DATA_END: |
1197 | default: | 1294 | default: |
1198 | break; | 1295 | break; |
1199 | } | 1296 | } |
1297 | |||
1298 | return printed; | ||
1200 | } | 1299 | } |
1201 | 1300 | ||
1202 | static void print_sample_bpf_output(struct perf_sample *sample) | 1301 | static int perf_sample__fprintf_bpf_output(struct perf_sample *sample, FILE *fp) |
1203 | { | 1302 | { |
1204 | unsigned int nr_bytes = sample->raw_size; | 1303 | unsigned int nr_bytes = sample->raw_size; |
1205 | struct printer_data printer_data = {0, false, true}; | 1304 | struct printer_data printer_data = {0, false, true}; |
1206 | 1305 | int printed = binary__fprintf(sample->raw_data, nr_bytes, 8, | |
1207 | print_binary(sample->raw_data, nr_bytes, 8, | 1306 | sample__fprintf_bpf_output, &printer_data, fp); |
1208 | print_sample_bpf_output_printer, &printer_data); | ||
1209 | 1307 | ||
1210 | if (printer_data.is_printable && printer_data.hit_nul) | 1308 | if (printer_data.is_printable && printer_data.hit_nul) |
1211 | printf("%17s \"%s\"\n", "BPF string:", | 1309 | printed += fprintf(fp, "%17s \"%s\"\n", "BPF string:", (char *)(sample->raw_data)); |
1212 | (char *)(sample->raw_data)); | 1310 | |
1311 | return printed; | ||
1213 | } | 1312 | } |
1214 | 1313 | ||
1215 | static void print_sample_spacing(int len, int spacing) | 1314 | static int perf_sample__fprintf_spacing(int len, int spacing, FILE *fp) |
1216 | { | 1315 | { |
1217 | if (len > 0 && len < spacing) | 1316 | if (len > 0 && len < spacing) |
1218 | printf("%*s", spacing - len, ""); | 1317 | return fprintf(fp, "%*s", spacing - len, ""); |
1318 | |||
1319 | return 0; | ||
1219 | } | 1320 | } |
1220 | 1321 | ||
1221 | static void print_sample_pt_spacing(int len) | 1322 | static int perf_sample__fprintf_pt_spacing(int len, FILE *fp) |
1222 | { | 1323 | { |
1223 | print_sample_spacing(len, 34); | 1324 | return perf_sample__fprintf_spacing(len, 34, fp); |
1224 | } | 1325 | } |
1225 | 1326 | ||
1226 | static void print_sample_synth_ptwrite(struct perf_sample *sample) | 1327 | static int perf_sample__fprintf_synth_ptwrite(struct perf_sample *sample, FILE *fp) |
1227 | { | 1328 | { |
1228 | struct perf_synth_intel_ptwrite *data = perf_sample__synth_ptr(sample); | 1329 | struct perf_synth_intel_ptwrite *data = perf_sample__synth_ptr(sample); |
1229 | int len; | 1330 | int len; |
1230 | 1331 | ||
1231 | if (perf_sample__bad_synth_size(sample, *data)) | 1332 | if (perf_sample__bad_synth_size(sample, *data)) |
1232 | return; | 1333 | return 0; |
1233 | 1334 | ||
1234 | len = printf(" IP: %u payload: %#" PRIx64 " ", | 1335 | len = fprintf(fp, " IP: %u payload: %#" PRIx64 " ", |
1235 | data->ip, le64_to_cpu(data->payload)); | 1336 | data->ip, le64_to_cpu(data->payload)); |
1236 | print_sample_pt_spacing(len); | 1337 | return len + perf_sample__fprintf_pt_spacing(len, fp); |
1237 | } | 1338 | } |
1238 | 1339 | ||
1239 | static void print_sample_synth_mwait(struct perf_sample *sample) | 1340 | static int perf_sample__fprintf_synth_mwait(struct perf_sample *sample, FILE *fp) |
1240 | { | 1341 | { |
1241 | struct perf_synth_intel_mwait *data = perf_sample__synth_ptr(sample); | 1342 | struct perf_synth_intel_mwait *data = perf_sample__synth_ptr(sample); |
1242 | int len; | 1343 | int len; |
1243 | 1344 | ||
1244 | if (perf_sample__bad_synth_size(sample, *data)) | 1345 | if (perf_sample__bad_synth_size(sample, *data)) |
1245 | return; | 1346 | return 0; |
1246 | 1347 | ||
1247 | len = printf(" hints: %#x extensions: %#x ", | 1348 | len = fprintf(fp, " hints: %#x extensions: %#x ", |
1248 | data->hints, data->extensions); | 1349 | data->hints, data->extensions); |
1249 | print_sample_pt_spacing(len); | 1350 | return len + perf_sample__fprintf_pt_spacing(len, fp); |
1250 | } | 1351 | } |
1251 | 1352 | ||
1252 | static void print_sample_synth_pwre(struct perf_sample *sample) | 1353 | static int perf_sample__fprintf_synth_pwre(struct perf_sample *sample, FILE *fp) |
1253 | { | 1354 | { |
1254 | struct perf_synth_intel_pwre *data = perf_sample__synth_ptr(sample); | 1355 | struct perf_synth_intel_pwre *data = perf_sample__synth_ptr(sample); |
1255 | int len; | 1356 | int len; |
1256 | 1357 | ||
1257 | if (perf_sample__bad_synth_size(sample, *data)) | 1358 | if (perf_sample__bad_synth_size(sample, *data)) |
1258 | return; | 1359 | return 0; |
1259 | 1360 | ||
1260 | len = printf(" hw: %u cstate: %u sub-cstate: %u ", | 1361 | len = fprintf(fp, " hw: %u cstate: %u sub-cstate: %u ", |
1261 | data->hw, data->cstate, data->subcstate); | 1362 | data->hw, data->cstate, data->subcstate); |
1262 | print_sample_pt_spacing(len); | 1363 | return len + perf_sample__fprintf_pt_spacing(len, fp); |
1263 | } | 1364 | } |
1264 | 1365 | ||
1265 | static void print_sample_synth_exstop(struct perf_sample *sample) | 1366 | static int perf_sample__fprintf_synth_exstop(struct perf_sample *sample, FILE *fp) |
1266 | { | 1367 | { |
1267 | struct perf_synth_intel_exstop *data = perf_sample__synth_ptr(sample); | 1368 | struct perf_synth_intel_exstop *data = perf_sample__synth_ptr(sample); |
1268 | int len; | 1369 | int len; |
1269 | 1370 | ||
1270 | if (perf_sample__bad_synth_size(sample, *data)) | 1371 | if (perf_sample__bad_synth_size(sample, *data)) |
1271 | return; | 1372 | return 0; |
1272 | 1373 | ||
1273 | len = printf(" IP: %u ", data->ip); | 1374 | len = fprintf(fp, " IP: %u ", data->ip); |
1274 | print_sample_pt_spacing(len); | 1375 | return len + perf_sample__fprintf_pt_spacing(len, fp); |
1275 | } | 1376 | } |
1276 | 1377 | ||
1277 | static void print_sample_synth_pwrx(struct perf_sample *sample) | 1378 | static int perf_sample__fprintf_synth_pwrx(struct perf_sample *sample, FILE *fp) |
1278 | { | 1379 | { |
1279 | struct perf_synth_intel_pwrx *data = perf_sample__synth_ptr(sample); | 1380 | struct perf_synth_intel_pwrx *data = perf_sample__synth_ptr(sample); |
1280 | int len; | 1381 | int len; |
1281 | 1382 | ||
1282 | if (perf_sample__bad_synth_size(sample, *data)) | 1383 | if (perf_sample__bad_synth_size(sample, *data)) |
1283 | return; | 1384 | return 0; |
1284 | 1385 | ||
1285 | len = printf(" deepest cstate: %u last cstate: %u wake reason: %#x ", | 1386 | len = fprintf(fp, " deepest cstate: %u last cstate: %u wake reason: %#x ", |
1286 | data->deepest_cstate, data->last_cstate, | 1387 | data->deepest_cstate, data->last_cstate, |
1287 | data->wake_reason); | 1388 | data->wake_reason); |
1288 | print_sample_pt_spacing(len); | 1389 | return len + perf_sample__fprintf_pt_spacing(len, fp); |
1289 | } | 1390 | } |
1290 | 1391 | ||
1291 | static void print_sample_synth_cbr(struct perf_sample *sample) | 1392 | static int perf_sample__fprintf_synth_cbr(struct perf_sample *sample, FILE *fp) |
1292 | { | 1393 | { |
1293 | struct perf_synth_intel_cbr *data = perf_sample__synth_ptr(sample); | 1394 | struct perf_synth_intel_cbr *data = perf_sample__synth_ptr(sample); |
1294 | unsigned int percent, freq; | 1395 | unsigned int percent, freq; |
1295 | int len; | 1396 | int len; |
1296 | 1397 | ||
1297 | if (perf_sample__bad_synth_size(sample, *data)) | 1398 | if (perf_sample__bad_synth_size(sample, *data)) |
1298 | return; | 1399 | return 0; |
1299 | 1400 | ||
1300 | freq = (le32_to_cpu(data->freq) + 500) / 1000; | 1401 | freq = (le32_to_cpu(data->freq) + 500) / 1000; |
1301 | len = printf(" cbr: %2u freq: %4u MHz ", data->cbr, freq); | 1402 | len = fprintf(fp, " cbr: %2u freq: %4u MHz ", data->cbr, freq); |
1302 | if (data->max_nonturbo) { | 1403 | if (data->max_nonturbo) { |
1303 | percent = (5 + (1000 * data->cbr) / data->max_nonturbo) / 10; | 1404 | percent = (5 + (1000 * data->cbr) / data->max_nonturbo) / 10; |
1304 | len += printf("(%3u%%) ", percent); | 1405 | len += fprintf(fp, "(%3u%%) ", percent); |
1305 | } | 1406 | } |
1306 | print_sample_pt_spacing(len); | 1407 | return len + perf_sample__fprintf_pt_spacing(len, fp); |
1307 | } | 1408 | } |
1308 | 1409 | ||
1309 | static void print_sample_synth(struct perf_sample *sample, | 1410 | static int perf_sample__fprintf_synth(struct perf_sample *sample, |
1310 | struct perf_evsel *evsel) | 1411 | struct perf_evsel *evsel, FILE *fp) |
1311 | { | 1412 | { |
1312 | switch (evsel->attr.config) { | 1413 | switch (evsel->attr.config) { |
1313 | case PERF_SYNTH_INTEL_PTWRITE: | 1414 | case PERF_SYNTH_INTEL_PTWRITE: |
1314 | print_sample_synth_ptwrite(sample); | 1415 | return perf_sample__fprintf_synth_ptwrite(sample, fp); |
1315 | break; | ||
1316 | case PERF_SYNTH_INTEL_MWAIT: | 1416 | case PERF_SYNTH_INTEL_MWAIT: |
1317 | print_sample_synth_mwait(sample); | 1417 | return perf_sample__fprintf_synth_mwait(sample, fp); |
1318 | break; | ||
1319 | case PERF_SYNTH_INTEL_PWRE: | 1418 | case PERF_SYNTH_INTEL_PWRE: |
1320 | print_sample_synth_pwre(sample); | 1419 | return perf_sample__fprintf_synth_pwre(sample, fp); |
1321 | break; | ||
1322 | case PERF_SYNTH_INTEL_EXSTOP: | 1420 | case PERF_SYNTH_INTEL_EXSTOP: |
1323 | print_sample_synth_exstop(sample); | 1421 | return perf_sample__fprintf_synth_exstop(sample, fp); |
1324 | break; | ||
1325 | case PERF_SYNTH_INTEL_PWRX: | 1422 | case PERF_SYNTH_INTEL_PWRX: |
1326 | print_sample_synth_pwrx(sample); | 1423 | return perf_sample__fprintf_synth_pwrx(sample, fp); |
1327 | break; | ||
1328 | case PERF_SYNTH_INTEL_CBR: | 1424 | case PERF_SYNTH_INTEL_CBR: |
1329 | print_sample_synth_cbr(sample); | 1425 | return perf_sample__fprintf_synth_cbr(sample, fp); |
1330 | break; | ||
1331 | default: | 1426 | default: |
1332 | break; | 1427 | break; |
1333 | } | 1428 | } |
1429 | |||
1430 | return 0; | ||
1334 | } | 1431 | } |
1335 | 1432 | ||
1336 | struct perf_script { | 1433 | struct perf_script { |
@@ -1341,6 +1438,7 @@ struct perf_script { | |||
1341 | bool show_switch_events; | 1438 | bool show_switch_events; |
1342 | bool show_namespace_events; | 1439 | bool show_namespace_events; |
1343 | bool allocated; | 1440 | bool allocated; |
1441 | bool per_event_dump; | ||
1344 | struct cpu_map *cpus; | 1442 | struct cpu_map *cpus; |
1345 | struct thread_map *threads; | 1443 | struct thread_map *threads; |
1346 | int name_width; | 1444 | int name_width; |
@@ -1362,7 +1460,7 @@ static int perf_evlist__max_name_len(struct perf_evlist *evlist) | |||
1362 | return max; | 1460 | return max; |
1363 | } | 1461 | } |
1364 | 1462 | ||
1365 | static size_t data_src__printf(u64 data_src) | 1463 | static int data_src__fprintf(u64 data_src, FILE *fp) |
1366 | { | 1464 | { |
1367 | struct mem_info mi = { .data_src.val = data_src }; | 1465 | struct mem_info mi = { .data_src.val = data_src }; |
1368 | char decode[100]; | 1466 | char decode[100]; |
@@ -1376,7 +1474,7 @@ static size_t data_src__printf(u64 data_src) | |||
1376 | if (maxlen < len) | 1474 | if (maxlen < len) |
1377 | maxlen = len; | 1475 | maxlen = len; |
1378 | 1476 | ||
1379 | return printf("%-*s", maxlen, out); | 1477 | return fprintf(fp, "%-*s", maxlen, out); |
1380 | } | 1478 | } |
1381 | 1479 | ||
1382 | static void process_event(struct perf_script *script, | 1480 | static void process_event(struct perf_script *script, |
@@ -1387,14 +1485,18 @@ static void process_event(struct perf_script *script, | |||
1387 | struct thread *thread = al->thread; | 1485 | struct thread *thread = al->thread; |
1388 | struct perf_event_attr *attr = &evsel->attr; | 1486 | struct perf_event_attr *attr = &evsel->attr; |
1389 | 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; | ||
1390 | 1490 | ||
1391 | if (output[type].fields == 0) | 1491 | if (output[type].fields == 0) |
1392 | return; | 1492 | return; |
1393 | 1493 | ||
1394 | print_sample_start(sample, thread, evsel); | 1494 | ++es->samples; |
1495 | |||
1496 | perf_sample__fprintf_start(sample, thread, evsel, fp); | ||
1395 | 1497 | ||
1396 | if (PRINT_FIELD(PERIOD)) | 1498 | if (PRINT_FIELD(PERIOD)) |
1397 | printf("%10" PRIu64 " ", sample->period); | 1499 | fprintf(fp, "%10" PRIu64 " ", sample->period); |
1398 | 1500 | ||
1399 | if (PRINT_FIELD(EVNAME)) { | 1501 | if (PRINT_FIELD(EVNAME)) { |
1400 | const char *evname = perf_evsel__name(evsel); | 1502 | const char *evname = perf_evsel__name(evsel); |
@@ -1402,33 +1504,33 @@ static void process_event(struct perf_script *script, | |||
1402 | if (!script->name_width) | 1504 | if (!script->name_width) |
1403 | script->name_width = perf_evlist__max_name_len(script->session->evlist); | 1505 | script->name_width = perf_evlist__max_name_len(script->session->evlist); |
1404 | 1506 | ||
1405 | printf("%*s: ", script->name_width, | 1507 | fprintf(fp, "%*s: ", script->name_width, evname ?: "[unknown]"); |
1406 | evname ? evname : "[unknown]"); | ||
1407 | } | 1508 | } |
1408 | 1509 | ||
1409 | if (print_flags) | 1510 | if (print_flags) |
1410 | print_sample_flags(sample->flags); | 1511 | perf_sample__fprintf_flags(sample->flags, fp); |
1411 | 1512 | ||
1412 | if (is_bts_event(attr)) { | 1513 | if (is_bts_event(attr)) { |
1413 | print_sample_bts(sample, evsel, thread, al, machine); | 1514 | perf_sample__fprintf_bts(sample, evsel, thread, al, machine, fp); |
1414 | return; | 1515 | return; |
1415 | } | 1516 | } |
1416 | 1517 | ||
1417 | if (PRINT_FIELD(TRACE)) | 1518 | if (PRINT_FIELD(TRACE)) { |
1418 | event_format__print(evsel->tp_format, sample->cpu, | 1519 | event_format__fprintf(evsel->tp_format, sample->cpu, |
1419 | sample->raw_data, sample->raw_size); | 1520 | sample->raw_data, sample->raw_size, fp); |
1521 | } | ||
1420 | 1522 | ||
1421 | if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH)) | 1523 | if (attr->type == PERF_TYPE_SYNTH && PRINT_FIELD(SYNTH)) |
1422 | print_sample_synth(sample, evsel); | 1524 | perf_sample__fprintf_synth(sample, evsel, fp); |
1423 | 1525 | ||
1424 | if (PRINT_FIELD(ADDR)) | 1526 | if (PRINT_FIELD(ADDR)) |
1425 | print_sample_addr(sample, thread, attr); | 1527 | perf_sample__fprintf_addr(sample, thread, attr, fp); |
1426 | 1528 | ||
1427 | if (PRINT_FIELD(DATA_SRC)) | 1529 | if (PRINT_FIELD(DATA_SRC)) |
1428 | data_src__printf(sample->data_src); | 1530 | data_src__fprintf(sample->data_src, fp); |
1429 | 1531 | ||
1430 | if (PRINT_FIELD(WEIGHT)) | 1532 | if (PRINT_FIELD(WEIGHT)) |
1431 | printf("%16" PRIu64, sample->weight); | 1533 | fprintf(fp, "%16" PRIu64, sample->weight); |
1432 | 1534 | ||
1433 | if (PRINT_FIELD(IP)) { | 1535 | if (PRINT_FIELD(IP)) { |
1434 | struct callchain_cursor *cursor = NULL; | 1536 | struct callchain_cursor *cursor = NULL; |
@@ -1438,27 +1540,30 @@ static void process_event(struct perf_script *script, | |||
1438 | sample, NULL, NULL, scripting_max_stack) == 0) | 1540 | sample, NULL, NULL, scripting_max_stack) == 0) |
1439 | cursor = &callchain_cursor; | 1541 | cursor = &callchain_cursor; |
1440 | 1542 | ||
1441 | putchar(cursor ? '\n' : ' '); | 1543 | fputc(cursor ? '\n' : ' ', fp); |
1442 | 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); |
1443 | } | 1545 | } |
1444 | 1546 | ||
1445 | if (PRINT_FIELD(IREGS)) | 1547 | if (PRINT_FIELD(IREGS)) |
1446 | 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); | ||
1447 | 1552 | ||
1448 | if (PRINT_FIELD(BRSTACK)) | 1553 | if (PRINT_FIELD(BRSTACK)) |
1449 | print_sample_brstack(sample, thread, attr); | 1554 | perf_sample__fprintf_brstack(sample, thread, attr, fp); |
1450 | else if (PRINT_FIELD(BRSTACKSYM)) | 1555 | else if (PRINT_FIELD(BRSTACKSYM)) |
1451 | print_sample_brstacksym(sample, thread, attr); | 1556 | perf_sample__fprintf_brstacksym(sample, thread, attr, fp); |
1452 | else if (PRINT_FIELD(BRSTACKOFF)) | 1557 | else if (PRINT_FIELD(BRSTACKOFF)) |
1453 | print_sample_brstackoff(sample, thread, attr); | 1558 | perf_sample__fprintf_brstackoff(sample, thread, attr, fp); |
1454 | 1559 | ||
1455 | if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) | 1560 | if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) |
1456 | print_sample_bpf_output(sample); | 1561 | perf_sample__fprintf_bpf_output(sample, fp); |
1457 | print_insn(sample, attr, thread, machine); | 1562 | perf_sample__fprintf_insn(sample, attr, thread, machine, fp); |
1458 | 1563 | ||
1459 | if (PRINT_FIELD(PHYS_ADDR)) | 1564 | if (PRINT_FIELD(PHYS_ADDR)) |
1460 | printf("%16" PRIx64, sample->phys_addr); | 1565 | fprintf(fp, "%16" PRIx64, sample->phys_addr); |
1461 | printf("\n"); | 1566 | fprintf(fp, "\n"); |
1462 | } | 1567 | } |
1463 | 1568 | ||
1464 | static struct scripting_ops *scripting_ops; | 1569 | static struct scripting_ops *scripting_ops; |
@@ -1632,7 +1737,7 @@ static int process_comm_event(struct perf_tool *tool, | |||
1632 | sample->tid = event->comm.tid; | 1737 | sample->tid = event->comm.tid; |
1633 | sample->pid = event->comm.pid; | 1738 | sample->pid = event->comm.pid; |
1634 | } | 1739 | } |
1635 | print_sample_start(sample, thread, evsel); | 1740 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1636 | perf_event__fprintf(event, stdout); | 1741 | perf_event__fprintf(event, stdout); |
1637 | ret = 0; | 1742 | ret = 0; |
1638 | out: | 1743 | out: |
@@ -1667,7 +1772,7 @@ static int process_namespaces_event(struct perf_tool *tool, | |||
1667 | sample->tid = event->namespaces.tid; | 1772 | sample->tid = event->namespaces.tid; |
1668 | sample->pid = event->namespaces.pid; | 1773 | sample->pid = event->namespaces.pid; |
1669 | } | 1774 | } |
1670 | print_sample_start(sample, thread, evsel); | 1775 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1671 | perf_event__fprintf(event, stdout); | 1776 | perf_event__fprintf(event, stdout); |
1672 | ret = 0; | 1777 | ret = 0; |
1673 | out: | 1778 | out: |
@@ -1700,7 +1805,7 @@ static int process_fork_event(struct perf_tool *tool, | |||
1700 | sample->tid = event->fork.tid; | 1805 | sample->tid = event->fork.tid; |
1701 | sample->pid = event->fork.pid; | 1806 | sample->pid = event->fork.pid; |
1702 | } | 1807 | } |
1703 | print_sample_start(sample, thread, evsel); | 1808 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1704 | perf_event__fprintf(event, stdout); | 1809 | perf_event__fprintf(event, stdout); |
1705 | thread__put(thread); | 1810 | thread__put(thread); |
1706 | 1811 | ||
@@ -1729,7 +1834,7 @@ static int process_exit_event(struct perf_tool *tool, | |||
1729 | sample->tid = event->fork.tid; | 1834 | sample->tid = event->fork.tid; |
1730 | sample->pid = event->fork.pid; | 1835 | sample->pid = event->fork.pid; |
1731 | } | 1836 | } |
1732 | print_sample_start(sample, thread, evsel); | 1837 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1733 | perf_event__fprintf(event, stdout); | 1838 | perf_event__fprintf(event, stdout); |
1734 | 1839 | ||
1735 | if (perf_event__process_exit(tool, event, sample, machine) < 0) | 1840 | if (perf_event__process_exit(tool, event, sample, machine) < 0) |
@@ -1764,7 +1869,7 @@ static int process_mmap_event(struct perf_tool *tool, | |||
1764 | sample->tid = event->mmap.tid; | 1869 | sample->tid = event->mmap.tid; |
1765 | sample->pid = event->mmap.pid; | 1870 | sample->pid = event->mmap.pid; |
1766 | } | 1871 | } |
1767 | print_sample_start(sample, thread, evsel); | 1872 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1768 | perf_event__fprintf(event, stdout); | 1873 | perf_event__fprintf(event, stdout); |
1769 | thread__put(thread); | 1874 | thread__put(thread); |
1770 | return 0; | 1875 | return 0; |
@@ -1795,7 +1900,7 @@ static int process_mmap2_event(struct perf_tool *tool, | |||
1795 | sample->tid = event->mmap2.tid; | 1900 | sample->tid = event->mmap2.tid; |
1796 | sample->pid = event->mmap2.pid; | 1901 | sample->pid = event->mmap2.pid; |
1797 | } | 1902 | } |
1798 | print_sample_start(sample, thread, evsel); | 1903 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1799 | perf_event__fprintf(event, stdout); | 1904 | perf_event__fprintf(event, stdout); |
1800 | thread__put(thread); | 1905 | thread__put(thread); |
1801 | return 0; | 1906 | return 0; |
@@ -1821,7 +1926,7 @@ static int process_switch_event(struct perf_tool *tool, | |||
1821 | return -1; | 1926 | return -1; |
1822 | } | 1927 | } |
1823 | 1928 | ||
1824 | print_sample_start(sample, thread, evsel); | 1929 | perf_sample__fprintf_start(sample, thread, evsel, stdout); |
1825 | perf_event__fprintf(event, stdout); | 1930 | perf_event__fprintf(event, stdout); |
1826 | thread__put(thread); | 1931 | thread__put(thread); |
1827 | return 0; | 1932 | return 0; |
@@ -1832,6 +1937,65 @@ static void sig_handler(int sig __maybe_unused) | |||
1832 | session_done = 1; | 1937 | session_done = 1; |
1833 | } | 1938 | } |
1834 | 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 | |||
1835 | static int __cmd_script(struct perf_script *script) | 1999 | static int __cmd_script(struct perf_script *script) |
1836 | { | 2000 | { |
1837 | int ret; | 2001 | int ret; |
@@ -1853,8 +2017,16 @@ static int __cmd_script(struct perf_script *script) | |||
1853 | if (script->show_namespace_events) | 2017 | if (script->show_namespace_events) |
1854 | script->tool.namespaces = process_namespaces_event; | 2018 | script->tool.namespaces = process_namespaces_event; |
1855 | 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 | |||
1856 | ret = perf_session__process_events(script->session); | 2025 | ret = perf_session__process_events(script->session); |
1857 | 2026 | ||
2027 | if (script->per_event_dump) | ||
2028 | perf_script__exit_per_event_dump_stats(script); | ||
2029 | |||
1858 | if (debug_mode) | 2030 | if (debug_mode) |
1859 | pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); | 2031 | pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); |
1860 | 2032 | ||
@@ -2419,14 +2591,16 @@ int find_scripts(char **scripts_array, char **scripts_path_array) | |||
2419 | char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; | 2591 | char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; |
2420 | DIR *scripts_dir, *lang_dir; | 2592 | DIR *scripts_dir, *lang_dir; |
2421 | struct perf_session *session; | 2593 | struct perf_session *session; |
2422 | struct perf_data_file file = { | 2594 | struct perf_data data = { |
2423 | .path = input_name, | 2595 | .file = { |
2424 | .mode = PERF_DATA_MODE_READ, | 2596 | .path = input_name, |
2597 | }, | ||
2598 | .mode = PERF_DATA_MODE_READ, | ||
2425 | }; | 2599 | }; |
2426 | char *temp; | 2600 | char *temp; |
2427 | int i = 0; | 2601 | int i = 0; |
2428 | 2602 | ||
2429 | session = perf_session__new(&file, false, NULL); | 2603 | session = perf_session__new(&data, false, NULL); |
2430 | if (!session) | 2604 | if (!session) |
2431 | return -1; | 2605 | return -1; |
2432 | 2606 | ||
@@ -2704,7 +2878,7 @@ int cmd_script(int argc, const char **argv) | |||
2704 | .ordering_requires_timestamps = true, | 2878 | .ordering_requires_timestamps = true, |
2705 | }, | 2879 | }, |
2706 | }; | 2880 | }; |
2707 | struct perf_data_file file = { | 2881 | struct perf_data data = { |
2708 | .mode = PERF_DATA_MODE_READ, | 2882 | .mode = PERF_DATA_MODE_READ, |
2709 | }; | 2883 | }; |
2710 | const struct option options[] = { | 2884 | const struct option options[] = { |
@@ -2740,7 +2914,7 @@ int cmd_script(int argc, const char **argv) | |||
2740 | "+field to add and -field to remove." | 2914 | "+field to add and -field to remove." |
2741 | "Valid types: hw,sw,trace,raw,synth. " | 2915 | "Valid types: hw,sw,trace,raw,synth. " |
2742 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," | 2916 | "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," |
2743 | "addr,symoff,period,iregs,brstack,brstacksym,flags," | 2917 | "addr,symoff,period,iregs,uregs,brstack,brstacksym,flags," |
2744 | "bpf-output,callindent,insn,insnlen,brstackinsn,synth,phys_addr", | 2918 | "bpf-output,callindent,insn,insnlen,brstackinsn,synth,phys_addr", |
2745 | parse_output_fields), | 2919 | parse_output_fields), |
2746 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 2920 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
@@ -2772,6 +2946,8 @@ int cmd_script(int argc, const char **argv) | |||
2772 | "Show context switch events (if recorded)"), | 2946 | "Show context switch events (if recorded)"), |
2773 | OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events, | 2947 | OPT_BOOLEAN('\0', "show-namespace-events", &script.show_namespace_events, |
2774 | "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"), | ||
2775 | 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"), |
2776 | OPT_INTEGER(0, "max-blocks", &max_blocks, | 2952 | OPT_INTEGER(0, "max-blocks", &max_blocks, |
2777 | "Maximum number of code blocks to dump with brstackinsn"), | 2953 | "Maximum number of code blocks to dump with brstackinsn"), |
@@ -2802,13 +2978,15 @@ int cmd_script(int argc, const char **argv) | |||
2802 | NULL | 2978 | NULL |
2803 | }; | 2979 | }; |
2804 | 2980 | ||
2981 | perf_set_singlethreaded(); | ||
2982 | |||
2805 | setup_scripting(); | 2983 | setup_scripting(); |
2806 | 2984 | ||
2807 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, | 2985 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, |
2808 | PARSE_OPT_STOP_AT_NON_OPTION); | 2986 | PARSE_OPT_STOP_AT_NON_OPTION); |
2809 | 2987 | ||
2810 | file.path = input_name; | 2988 | data.file.path = input_name; |
2811 | file.force = symbol_conf.force; | 2989 | data.force = symbol_conf.force; |
2812 | 2990 | ||
2813 | if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { | 2991 | if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { |
2814 | rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); | 2992 | rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); |
@@ -2975,7 +3153,7 @@ int cmd_script(int argc, const char **argv) | |||
2975 | if (!script_name) | 3153 | if (!script_name) |
2976 | setup_pager(); | 3154 | setup_pager(); |
2977 | 3155 | ||
2978 | session = perf_session__new(&file, false, &script.tool); | 3156 | session = perf_session__new(&data, false, &script.tool); |
2979 | if (session == NULL) | 3157 | if (session == NULL) |
2980 | return -1; | 3158 | return -1; |
2981 | 3159 | ||
@@ -3016,7 +3194,8 @@ int cmd_script(int argc, const char **argv) | |||
3016 | machine__resolve_kernel_addr, | 3194 | machine__resolve_kernel_addr, |
3017 | &session->machines.host) < 0) { | 3195 | &session->machines.host) < 0) { |
3018 | pr_err("%s: failed to set libtraceevent function resolver\n", __func__); | 3196 | pr_err("%s: failed to set libtraceevent function resolver\n", __func__); |
3019 | return -1; | 3197 | err = -1; |
3198 | goto out_delete; | ||
3020 | } | 3199 | } |
3021 | 3200 | ||
3022 | if (generate_script_lang) { | 3201 | if (generate_script_lang) { |
@@ -3030,7 +3209,7 @@ int cmd_script(int argc, const char **argv) | |||
3030 | goto out_delete; | 3209 | goto out_delete; |
3031 | } | 3210 | } |
3032 | 3211 | ||
3033 | input = open(file.path, O_RDONLY); /* input_name */ | 3212 | input = open(data.file.path, O_RDONLY); /* input_name */ |
3034 | if (input < 0) { | 3213 | if (input < 0) { |
3035 | err = -errno; | 3214 | err = -errno; |
3036 | perror("failed to open file"); | 3215 | perror("failed to open file"); |
@@ -3076,7 +3255,8 @@ int cmd_script(int argc, const char **argv) | |||
3076 | /* needs to be parsed after looking up reference time */ | 3255 | /* needs to be parsed after looking up reference time */ |
3077 | if (perf_time__parse_str(&script.ptime, script.time_str) != 0) { | 3256 | if (perf_time__parse_str(&script.ptime, script.time_str) != 0) { |
3078 | pr_err("Invalid time string\n"); | 3257 | pr_err("Invalid time string\n"); |
3079 | return -EINVAL; | 3258 | err = -EINVAL; |
3259 | goto out_delete; | ||
3080 | } | 3260 | } |
3081 | 3261 | ||
3082 | err = __cmd_script(&script); | 3262 | err = __cmd_script(&script); |