aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/Documentation/perf-report.txt3
-rw-r--r--tools/perf/builtin-record.c81
-rw-r--r--tools/perf/builtin-trace.c248
-rw-r--r--tools/perf/util/evlist.c34
-rw-r--r--tools/perf/util/evlist.h4
-rw-r--r--tools/perf/util/evsel.c13
-rw-r--r--tools/perf/util/evsel.h1
-rw-r--r--tools/perf/util/hist.c9
-rw-r--r--tools/perf/util/hist.h2
-rw-r--r--tools/perf/util/sort.c84
-rw-r--r--tools/perf/util/sort.h2
-rw-r--r--tools/perf/util/symbol.h2
12 files changed, 319 insertions, 164 deletions
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 496d42cdf02b..9cbddc290aff 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -103,12 +103,13 @@ OPTIONS
103 103
104 If --branch-stack option is used, following sort keys are also 104 If --branch-stack option is used, following sort keys are also
105 available: 105 available:
106 dso_from, dso_to, symbol_from, symbol_to, mispredict.
107 106
108 - dso_from: name of library or module branched from 107 - dso_from: name of library or module branched from
109 - dso_to: name of library or module branched to 108 - dso_to: name of library or module branched to
110 - symbol_from: name of function branched from 109 - symbol_from: name of function branched from
111 - symbol_to: name of function branched to 110 - symbol_to: name of function branched to
111 - srcline_from: source file and line branched from
112 - srcline_to: source file and line branched to
112 - mispredict: "N" for predicted branch, "Y" for mispredicted branch 113 - mispredict: "N" for predicted branch, "Y" for mispredicted branch
113 - in_tx: branch in TSX transaction 114 - in_tx: branch in TSX transaction
114 - abort: TSX transaction abort. 115 - abort: TSX transaction abort.
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f3679c44d3f3..dc3fcb597e4c 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -40,6 +40,7 @@
40#include <unistd.h> 40#include <unistd.h>
41#include <sched.h> 41#include <sched.h>
42#include <sys/mman.h> 42#include <sys/mman.h>
43#include <asm/bug.h>
43 44
44 45
45struct record { 46struct record {
@@ -82,27 +83,87 @@ static int process_synthesized_event(struct perf_tool *tool,
82 return record__write(rec, event, event->header.size); 83 return record__write(rec, event, event->header.size);
83} 84}
84 85
86static int
87backward_rb_find_range(void *buf, int mask, u64 head, u64 *start, u64 *end)
88{
89 struct perf_event_header *pheader;
90 u64 evt_head = head;
91 int size = mask + 1;
92
93 pr_debug2("backward_rb_find_range: buf=%p, head=%"PRIx64"\n", buf, head);
94 pheader = (struct perf_event_header *)(buf + (head & mask));
95 *start = head;
96 while (true) {
97 if (evt_head - head >= (unsigned int)size) {
98 pr_debug("Finshed reading backward ring buffer: rewind\n");
99 if (evt_head - head > (unsigned int)size)
100 evt_head -= pheader->size;
101 *end = evt_head;
102 return 0;
103 }
104
105 pheader = (struct perf_event_header *)(buf + (evt_head & mask));
106
107 if (pheader->size == 0) {
108 pr_debug("Finshed reading backward ring buffer: get start\n");
109 *end = evt_head;
110 return 0;
111 }
112
113 evt_head += pheader->size;
114 pr_debug3("move evt_head: %"PRIx64"\n", evt_head);
115 }
116 WARN_ONCE(1, "Shouldn't get here\n");
117 return -1;
118}
119
120static int
121rb_find_range(struct perf_evlist *evlist,
122 void *data, int mask, u64 head, u64 old,
123 u64 *start, u64 *end)
124{
125 if (!evlist->backward) {
126 *start = old;
127 *end = head;
128 return 0;
129 }
130
131 return backward_rb_find_range(data, mask, head, start, end);
132}
133
85static int record__mmap_read(struct record *rec, int idx) 134static int record__mmap_read(struct record *rec, int idx)
86{ 135{
87 struct perf_mmap *md = &rec->evlist->mmap[idx]; 136 struct perf_mmap *md = &rec->evlist->mmap[idx];
88 u64 head = perf_mmap__read_head(md); 137 u64 head = perf_mmap__read_head(md);
89 u64 old = md->prev; 138 u64 old = md->prev;
139 u64 end = head, start = old;
90 unsigned char *data = md->base + page_size; 140 unsigned char *data = md->base + page_size;
91 unsigned long size; 141 unsigned long size;
92 void *buf; 142 void *buf;
93 int rc = 0; 143 int rc = 0;
94 144
95 if (old == head) 145 if (rb_find_range(rec->evlist, data, md->mask, head,
146 old, &start, &end))
147 return -1;
148
149 if (start == end)
96 return 0; 150 return 0;
97 151
98 rec->samples++; 152 rec->samples++;
99 153
100 size = head - old; 154 size = end - start;
155 if (size > (unsigned long)(md->mask) + 1) {
156 WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n");
157
158 md->prev = head;
159 perf_evlist__mmap_consume(rec->evlist, idx);
160 return 0;
161 }
101 162
102 if ((old & md->mask) + size != (head & md->mask)) { 163 if ((start & md->mask) + size != (end & md->mask)) {
103 buf = &data[old & md->mask]; 164 buf = &data[start & md->mask];
104 size = md->mask + 1 - (old & md->mask); 165 size = md->mask + 1 - (start & md->mask);
105 old += size; 166 start += size;
106 167
107 if (record__write(rec, buf, size) < 0) { 168 if (record__write(rec, buf, size) < 0) {
108 rc = -1; 169 rc = -1;
@@ -110,16 +171,16 @@ static int record__mmap_read(struct record *rec, int idx)
110 } 171 }
111 } 172 }
112 173
113 buf = &data[old & md->mask]; 174 buf = &data[start & md->mask];
114 size = head - old; 175 size = end - start;
115 old += size; 176 start += size;
116 177
117 if (record__write(rec, buf, size) < 0) { 178 if (record__write(rec, buf, size) < 0) {
118 rc = -1; 179 rc = -1;
119 goto out; 180 goto out;
120 } 181 }
121 182
122 md->prev = old; 183 md->prev = head;
123 perf_evlist__mmap_consume(rec->evlist, idx); 184 perf_evlist__mmap_consume(rec->evlist, idx);
124out: 185out:
125 return rc; 186 return rc;
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 487c10401d46..5c50fe70d6b3 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -576,84 +576,54 @@ static struct syscall_fmt {
576 bool hexret; 576 bool hexret;
577} syscall_fmts[] = { 577} syscall_fmts[] = {
578 { .name = "access", .errmsg = true, 578 { .name = "access", .errmsg = true,
579 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ 579 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
580 [1] = SCA_ACCMODE, /* mode */ }, },
581 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, 580 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
582 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), }, 581 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
583 { .name = "brk", .hexret = true, 582 { .name = "brk", .hexret = true,
584 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, 583 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
585 { .name = "chdir", .errmsg = true, 584 { .name = "chdir", .errmsg = true, },
586 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, 585 { .name = "chmod", .errmsg = true, },
587 { .name = "chmod", .errmsg = true, 586 { .name = "chroot", .errmsg = true, },
588 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
589 { .name = "chroot", .errmsg = true,
590 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
591 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), }, 587 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
592 { .name = "clone", .errpid = true, }, 588 { .name = "clone", .errpid = true, },
593 { .name = "close", .errmsg = true, 589 { .name = "close", .errmsg = true,
594 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, }, 590 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
595 { .name = "connect", .errmsg = true, }, 591 { .name = "connect", .errmsg = true, },
596 { .name = "creat", .errmsg = true, 592 { .name = "creat", .errmsg = true, },
597 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, 593 { .name = "dup", .errmsg = true, },
598 { .name = "dup", .errmsg = true, 594 { .name = "dup2", .errmsg = true, },
599 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 595 { .name = "dup3", .errmsg = true, },
600 { .name = "dup2", .errmsg = true,
601 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
602 { .name = "dup3", .errmsg = true,
603 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
604 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), }, 596 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
605 { .name = "eventfd2", .errmsg = true, 597 { .name = "eventfd2", .errmsg = true,
606 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, }, 598 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
607 { .name = "faccessat", .errmsg = true, 599 { .name = "faccessat", .errmsg = true, },
608 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ 600 { .name = "fadvise64", .errmsg = true, },
609 [1] = SCA_FILENAME, /* filename */ }, }, 601 { .name = "fallocate", .errmsg = true, },
610 { .name = "fadvise64", .errmsg = true, 602 { .name = "fchdir", .errmsg = true, },
611 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 603 { .name = "fchmod", .errmsg = true, },
612 { .name = "fallocate", .errmsg = true,
613 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
614 { .name = "fchdir", .errmsg = true,
615 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
616 { .name = "fchmod", .errmsg = true,
617 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
618 { .name = "fchmodat", .errmsg = true, 604 { .name = "fchmodat", .errmsg = true,
619 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ 605 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
620 [1] = SCA_FILENAME, /* filename */ }, }, 606 { .name = "fchown", .errmsg = true, },
621 { .name = "fchown", .errmsg = true,
622 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
623 { .name = "fchownat", .errmsg = true, 607 { .name = "fchownat", .errmsg = true,
624 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ 608 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
625 [1] = SCA_FILENAME, /* filename */ }, },
626 { .name = "fcntl", .errmsg = true, 609 { .name = "fcntl", .errmsg = true,
627 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 610 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
628 [1] = SCA_STRARRAY, /* cmd */ },
629 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, }, 611 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
630 { .name = "fdatasync", .errmsg = true, 612 { .name = "fdatasync", .errmsg = true, },
631 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
632 { .name = "flock", .errmsg = true, 613 { .name = "flock", .errmsg = true,
633 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 614 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
634 [1] = SCA_FLOCK, /* cmd */ }, }, 615 { .name = "fsetxattr", .errmsg = true, },
635 { .name = "fsetxattr", .errmsg = true, 616 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
636 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 617 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
637 { .name = "fstat", .errmsg = true, .alias = "newfstat", 618 { .name = "fstatfs", .errmsg = true, },
638 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 619 { .name = "fsync", .errmsg = true, },
639 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", 620 { .name = "ftruncate", .errmsg = true, },
640 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
641 [1] = SCA_FILENAME, /* filename */ }, },
642 { .name = "fstatfs", .errmsg = true,
643 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
644 { .name = "fsync", .errmsg = true,
645 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
646 { .name = "ftruncate", .errmsg = true,
647 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
648 { .name = "futex", .errmsg = true, 621 { .name = "futex", .errmsg = true,
649 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, }, 622 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
650 { .name = "futimesat", .errmsg = true, 623 { .name = "futimesat", .errmsg = true,
651 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ 624 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
652 [1] = SCA_FILENAME, /* filename */ }, }, 625 { .name = "getdents", .errmsg = true, },
653 { .name = "getdents", .errmsg = true, 626 { .name = "getdents64", .errmsg = true, },
654 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
655 { .name = "getdents64", .errmsg = true,
656 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
657 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, 627 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
658 { .name = "getpid", .errpid = true, }, 628 { .name = "getpid", .errpid = true, },
659 { .name = "getpgid", .errpid = true, }, 629 { .name = "getpgid", .errpid = true, },
@@ -661,12 +631,10 @@ static struct syscall_fmt {
661 { .name = "getrandom", .errmsg = true, 631 { .name = "getrandom", .errmsg = true,
662 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, }, 632 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
663 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, 633 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
664 { .name = "getxattr", .errmsg = true, 634 { .name = "getxattr", .errmsg = true, },
665 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, 635 { .name = "inotify_add_watch", .errmsg = true, },
666 { .name = "inotify_add_watch", .errmsg = true,
667 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
668 { .name = "ioctl", .errmsg = true, 636 { .name = "ioctl", .errmsg = true,
669 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 637 .arg_scnprintf = {
670#if defined(__i386__) || defined(__x86_64__) 638#if defined(__i386__) || defined(__x86_64__)
671/* 639/*
672 * FIXME: Make this available to all arches. 640 * FIXME: Make this available to all arches.
@@ -680,41 +648,28 @@ static struct syscall_fmt {
680 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), }, 648 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
681 { .name = "kill", .errmsg = true, 649 { .name = "kill", .errmsg = true,
682 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, 650 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
683 { .name = "lchown", .errmsg = true, 651 { .name = "lchown", .errmsg = true, },
684 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, 652 { .name = "lgetxattr", .errmsg = true, },
685 { .name = "lgetxattr", .errmsg = true,
686 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
687 { .name = "linkat", .errmsg = true, 653 { .name = "linkat", .errmsg = true,
688 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, 654 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
689 { .name = "listxattr", .errmsg = true, 655 { .name = "listxattr", .errmsg = true, },
690 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, 656 { .name = "llistxattr", .errmsg = true, },
691 { .name = "llistxattr", .errmsg = true, 657 { .name = "lremovexattr", .errmsg = true, },
692 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
693 { .name = "lremovexattr", .errmsg = true,
694 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
695 { .name = "lseek", .errmsg = true, 658 { .name = "lseek", .errmsg = true,
696 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 659 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
697 [2] = SCA_STRARRAY, /* whence */ },
698 .arg_parm = { [2] = &strarray__whences, /* whence */ }, }, 660 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
699 { .name = "lsetxattr", .errmsg = true, 661 { .name = "lsetxattr", .errmsg = true, },
700 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, 662 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
701 { .name = "lstat", .errmsg = true, .alias = "newlstat", 663 { .name = "lsxattr", .errmsg = true, },
702 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
703 { .name = "lsxattr", .errmsg = true,
704 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
705 { .name = "madvise", .errmsg = true, 664 { .name = "madvise", .errmsg = true,
706 .arg_scnprintf = { [0] = SCA_HEX, /* start */ 665 .arg_scnprintf = { [0] = SCA_HEX, /* start */
707 [2] = SCA_MADV_BHV, /* behavior */ }, }, 666 [2] = SCA_MADV_BHV, /* behavior */ }, },
708 { .name = "mkdir", .errmsg = true, 667 { .name = "mkdir", .errmsg = true, },
709 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
710 { .name = "mkdirat", .errmsg = true, 668 { .name = "mkdirat", .errmsg = true,
711 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ 669 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
712 [1] = SCA_FILENAME, /* pathname */ }, }, 670 { .name = "mknod", .errmsg = true, },
713 { .name = "mknod", .errmsg = true,
714 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
715 { .name = "mknodat", .errmsg = true, 671 { .name = "mknodat", .errmsg = true,
716 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ 672 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
717 [1] = SCA_FILENAME, /* filename */ }, },
718 { .name = "mlock", .errmsg = true, 673 { .name = "mlock", .errmsg = true,
719 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, 674 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
720 { .name = "mlockall", .errmsg = true, 675 { .name = "mlockall", .errmsg = true,
@@ -722,8 +677,7 @@ static struct syscall_fmt {
722 { .name = "mmap", .hexret = true, 677 { .name = "mmap", .hexret = true,
723 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ 678 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
724 [2] = SCA_MMAP_PROT, /* prot */ 679 [2] = SCA_MMAP_PROT, /* prot */
725 [3] = SCA_MMAP_FLAGS, /* flags */ 680 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
726 [4] = SCA_FD, /* fd */ }, },
727 { .name = "mprotect", .errmsg = true, 681 { .name = "mprotect", .errmsg = true,
728 .arg_scnprintf = { [0] = SCA_HEX, /* start */ 682 .arg_scnprintf = { [0] = SCA_HEX, /* start */
729 [2] = SCA_MMAP_PROT, /* prot */ }, }, 683 [2] = SCA_MMAP_PROT, /* prot */ }, },
@@ -740,17 +694,14 @@ static struct syscall_fmt {
740 { .name = "name_to_handle_at", .errmsg = true, 694 { .name = "name_to_handle_at", .errmsg = true,
741 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 695 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
742 { .name = "newfstatat", .errmsg = true, 696 { .name = "newfstatat", .errmsg = true,
743 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ 697 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
744 [1] = SCA_FILENAME, /* filename */ }, },
745 { .name = "open", .errmsg = true, 698 { .name = "open", .errmsg = true,
746 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ 699 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
747 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
748 { .name = "open_by_handle_at", .errmsg = true, 700 { .name = "open_by_handle_at", .errmsg = true,
749 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ 701 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
750 [2] = SCA_OPEN_FLAGS, /* flags */ }, }, 702 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
751 { .name = "openat", .errmsg = true, 703 { .name = "openat", .errmsg = true,
752 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ 704 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
753 [1] = SCA_FILENAME, /* filename */
754 [2] = SCA_OPEN_FLAGS, /* flags */ }, }, 705 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
755 { .name = "perf_event_open", .errmsg = true, 706 { .name = "perf_event_open", .errmsg = true,
756 .arg_scnprintf = { [2] = SCA_INT, /* cpu */ 707 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
@@ -760,39 +711,26 @@ static struct syscall_fmt {
760 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, }, 711 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
761 { .name = "poll", .errmsg = true, .timeout = true, }, 712 { .name = "poll", .errmsg = true, .timeout = true, },
762 { .name = "ppoll", .errmsg = true, .timeout = true, }, 713 { .name = "ppoll", .errmsg = true, .timeout = true, },
763 { .name = "pread", .errmsg = true, .alias = "pread64", 714 { .name = "pread", .errmsg = true, .alias = "pread64", },
764 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 715 { .name = "preadv", .errmsg = true, .alias = "pread", },
765 { .name = "preadv", .errmsg = true, .alias = "pread",
766 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
767 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), }, 716 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
768 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", 717 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
769 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 718 { .name = "pwritev", .errmsg = true, },
770 { .name = "pwritev", .errmsg = true, 719 { .name = "read", .errmsg = true, },
771 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 720 { .name = "readlink", .errmsg = true, },
772 { .name = "read", .errmsg = true,
773 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
774 { .name = "readlink", .errmsg = true,
775 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
776 { .name = "readlinkat", .errmsg = true, 721 { .name = "readlinkat", .errmsg = true,
777 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ 722 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
778 [1] = SCA_FILENAME, /* pathname */ }, }, 723 { .name = "readv", .errmsg = true, },
779 { .name = "readv", .errmsg = true,
780 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
781 { .name = "recvfrom", .errmsg = true, 724 { .name = "recvfrom", .errmsg = true,
782 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 725 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
783 [3] = SCA_MSG_FLAGS, /* flags */ }, },
784 { .name = "recvmmsg", .errmsg = true, 726 { .name = "recvmmsg", .errmsg = true,
785 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 727 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
786 [3] = SCA_MSG_FLAGS, /* flags */ }, },
787 { .name = "recvmsg", .errmsg = true, 728 { .name = "recvmsg", .errmsg = true,
788 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 729 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
789 [2] = SCA_MSG_FLAGS, /* flags */ }, }, 730 { .name = "removexattr", .errmsg = true, },
790 { .name = "removexattr", .errmsg = true,
791 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
792 { .name = "renameat", .errmsg = true, 731 { .name = "renameat", .errmsg = true,
793 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, 732 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
794 { .name = "rmdir", .errmsg = true, 733 { .name = "rmdir", .errmsg = true, },
795 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
796 { .name = "rt_sigaction", .errmsg = true, 734 { .name = "rt_sigaction", .errmsg = true,
797 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, }, 735 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
798 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), }, 736 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
@@ -807,22 +745,17 @@ static struct syscall_fmt {
807 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, }, 745 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
808 { .name = "select", .errmsg = true, .timeout = true, }, 746 { .name = "select", .errmsg = true, .timeout = true, },
809 { .name = "sendmmsg", .errmsg = true, 747 { .name = "sendmmsg", .errmsg = true,
810 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 748 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
811 [3] = SCA_MSG_FLAGS, /* flags */ }, },
812 { .name = "sendmsg", .errmsg = true, 749 { .name = "sendmsg", .errmsg = true,
813 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 750 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
814 [2] = SCA_MSG_FLAGS, /* flags */ }, },
815 { .name = "sendto", .errmsg = true, 751 { .name = "sendto", .errmsg = true,
816 .arg_scnprintf = { [0] = SCA_FD, /* fd */ 752 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
817 [3] = SCA_MSG_FLAGS, /* flags */ }, },
818 { .name = "set_tid_address", .errpid = true, }, 753 { .name = "set_tid_address", .errpid = true, },
819 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), }, 754 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
820 { .name = "setpgid", .errmsg = true, }, 755 { .name = "setpgid", .errmsg = true, },
821 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, 756 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
822 { .name = "setxattr", .errmsg = true, 757 { .name = "setxattr", .errmsg = true, },
823 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, 758 { .name = "shutdown", .errmsg = true, },
824 { .name = "shutdown", .errmsg = true,
825 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
826 { .name = "socket", .errmsg = true, 759 { .name = "socket", .errmsg = true,
827 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */ 760 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
828 [1] = SCA_SK_TYPE, /* type */ }, 761 [1] = SCA_SK_TYPE, /* type */ },
@@ -831,10 +764,8 @@ static struct syscall_fmt {
831 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */ 764 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
832 [1] = SCA_SK_TYPE, /* type */ }, 765 [1] = SCA_SK_TYPE, /* type */ },
833 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, }, 766 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
834 { .name = "stat", .errmsg = true, .alias = "newstat", 767 { .name = "stat", .errmsg = true, .alias = "newstat", },
835 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, 768 { .name = "statfs", .errmsg = true, },
836 { .name = "statfs", .errmsg = true,
837 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
838 { .name = "swapoff", .errmsg = true, 769 { .name = "swapoff", .errmsg = true,
839 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, }, 770 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
840 { .name = "swapon", .errmsg = true, 771 { .name = "swapon", .errmsg = true,
@@ -845,29 +776,21 @@ static struct syscall_fmt {
845 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, 776 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
846 { .name = "tkill", .errmsg = true, 777 { .name = "tkill", .errmsg = true,
847 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, 778 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
848 { .name = "truncate", .errmsg = true, 779 { .name = "truncate", .errmsg = true, },
849 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
850 { .name = "uname", .errmsg = true, .alias = "newuname", }, 780 { .name = "uname", .errmsg = true, .alias = "newuname", },
851 { .name = "unlinkat", .errmsg = true, 781 { .name = "unlinkat", .errmsg = true,
852 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ 782 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
853 [1] = SCA_FILENAME, /* pathname */ }, }, 783 { .name = "utime", .errmsg = true, },
854 { .name = "utime", .errmsg = true,
855 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
856 { .name = "utimensat", .errmsg = true, 784 { .name = "utimensat", .errmsg = true,
857 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ 785 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
858 [1] = SCA_FILENAME, /* filename */ }, }, 786 { .name = "utimes", .errmsg = true, },
859 { .name = "utimes", .errmsg = true, 787 { .name = "vmsplice", .errmsg = true, },
860 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
861 { .name = "vmsplice", .errmsg = true,
862 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
863 { .name = "wait4", .errpid = true, 788 { .name = "wait4", .errpid = true,
864 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, }, 789 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
865 { .name = "waitid", .errpid = true, 790 { .name = "waitid", .errpid = true,
866 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, }, 791 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
867 { .name = "write", .errmsg = true, 792 { .name = "write", .errmsg = true, },
868 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, 793 { .name = "writev", .errmsg = true, },
869 { .name = "writev", .errmsg = true,
870 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
871}; 794};
872 795
873static int syscall_fmt__cmp(const void *name, const void *fmtp) 796static int syscall_fmt__cmp(const void *name, const void *fmtp)
@@ -1204,7 +1127,7 @@ static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1204static int syscall__set_arg_fmts(struct syscall *sc) 1127static int syscall__set_arg_fmts(struct syscall *sc)
1205{ 1128{
1206 struct format_field *field; 1129 struct format_field *field;
1207 int idx = 0; 1130 int idx = 0, len;
1208 1131
1209 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *)); 1132 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
1210 if (sc->arg_scnprintf == NULL) 1133 if (sc->arg_scnprintf == NULL)
@@ -1216,12 +1139,31 @@ static int syscall__set_arg_fmts(struct syscall *sc)
1216 for (field = sc->args; field; field = field->next) { 1139 for (field = sc->args; field; field = field->next) {
1217 if (sc->fmt && sc->fmt->arg_scnprintf[idx]) 1140 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1218 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; 1141 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1142 else if (strcmp(field->type, "const char *") == 0 &&
1143 (strcmp(field->name, "filename") == 0 ||
1144 strcmp(field->name, "path") == 0 ||
1145 strcmp(field->name, "pathname") == 0))
1146 sc->arg_scnprintf[idx] = SCA_FILENAME;
1219 else if (field->flags & FIELD_IS_POINTER) 1147 else if (field->flags & FIELD_IS_POINTER)
1220 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex; 1148 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1221 else if (strcmp(field->type, "pid_t") == 0) 1149 else if (strcmp(field->type, "pid_t") == 0)
1222 sc->arg_scnprintf[idx] = SCA_PID; 1150 sc->arg_scnprintf[idx] = SCA_PID;
1223 else if (strcmp(field->type, "umode_t") == 0) 1151 else if (strcmp(field->type, "umode_t") == 0)
1224 sc->arg_scnprintf[idx] = SCA_MODE_T; 1152 sc->arg_scnprintf[idx] = SCA_MODE_T;
1153 else if ((strcmp(field->type, "int") == 0 ||
1154 strcmp(field->type, "unsigned int") == 0 ||
1155 strcmp(field->type, "long") == 0) &&
1156 (len = strlen(field->name)) >= 2 &&
1157 strcmp(field->name + len - 2, "fd") == 0) {
1158 /*
1159 * /sys/kernel/tracing/events/syscalls/sys_enter*
1160 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1161 * 65 int
1162 * 23 unsigned int
1163 * 7 unsigned long
1164 */
1165 sc->arg_scnprintf[idx] = SCA_FD;
1166 }
1225 ++idx; 1167 ++idx;
1226 } 1168 }
1227 1169
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index c4bfe11479a0..e82ba90cc969 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -44,6 +44,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
44 perf_evlist__set_maps(evlist, cpus, threads); 44 perf_evlist__set_maps(evlist, cpus, threads);
45 fdarray__init(&evlist->pollfd, 64); 45 fdarray__init(&evlist->pollfd, 64);
46 evlist->workload.pid = -1; 46 evlist->workload.pid = -1;
47 evlist->backward = false;
47} 48}
48 49
49struct perf_evlist *perf_evlist__new(void) 50struct perf_evlist *perf_evlist__new(void)
@@ -679,6 +680,33 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist,
679 return NULL; 680 return NULL;
680} 681}
681 682
683static int perf_evlist__set_paused(struct perf_evlist *evlist, bool value)
684{
685 int i;
686
687 for (i = 0; i < evlist->nr_mmaps; i++) {
688 int fd = evlist->mmap[i].fd;
689 int err;
690
691 if (fd < 0)
692 continue;
693 err = ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, value ? 1 : 0);
694 if (err)
695 return err;
696 }
697 return 0;
698}
699
700int perf_evlist__pause(struct perf_evlist *evlist)
701{
702 return perf_evlist__set_paused(evlist, true);
703}
704
705int perf_evlist__resume(struct perf_evlist *evlist)
706{
707 return perf_evlist__set_paused(evlist, false);
708}
709
682/* When check_messup is true, 'end' must points to a good entry */ 710/* When check_messup is true, 'end' must points to a good entry */
683static union perf_event * 711static union perf_event *
684perf_mmap__read(struct perf_mmap *md, bool check_messup, u64 start, 712perf_mmap__read(struct perf_mmap *md, bool check_messup, u64 start,
@@ -881,6 +909,7 @@ static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
881 if (evlist->mmap[idx].base != NULL) { 909 if (evlist->mmap[idx].base != NULL) {
882 munmap(evlist->mmap[idx].base, evlist->mmap_len); 910 munmap(evlist->mmap[idx].base, evlist->mmap_len);
883 evlist->mmap[idx].base = NULL; 911 evlist->mmap[idx].base = NULL;
912 evlist->mmap[idx].fd = -1;
884 atomic_set(&evlist->mmap[idx].refcnt, 0); 913 atomic_set(&evlist->mmap[idx].refcnt, 0);
885 } 914 }
886 auxtrace_mmap__munmap(&evlist->mmap[idx].auxtrace_mmap); 915 auxtrace_mmap__munmap(&evlist->mmap[idx].auxtrace_mmap);
@@ -901,10 +930,14 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
901 930
902static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) 931static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
903{ 932{
933 int i;
934
904 evlist->nr_mmaps = cpu_map__nr(evlist->cpus); 935 evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
905 if (cpu_map__empty(evlist->cpus)) 936 if (cpu_map__empty(evlist->cpus))
906 evlist->nr_mmaps = thread_map__nr(evlist->threads); 937 evlist->nr_mmaps = thread_map__nr(evlist->threads);
907 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); 938 evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
939 for (i = 0; i < evlist->nr_mmaps; i++)
940 evlist->mmap[i].fd = -1;
908 return evlist->mmap != NULL ? 0 : -ENOMEM; 941 return evlist->mmap != NULL ? 0 : -ENOMEM;
909} 942}
910 943
@@ -941,6 +974,7 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
941 evlist->mmap[idx].base = NULL; 974 evlist->mmap[idx].base = NULL;
942 return -1; 975 return -1;
943 } 976 }
977 evlist->mmap[idx].fd = fd;
944 978
945 if (auxtrace_mmap__mmap(&evlist->mmap[idx].auxtrace_mmap, 979 if (auxtrace_mmap__mmap(&evlist->mmap[idx].auxtrace_mmap,
946 &mp->auxtrace_mp, evlist->mmap[idx].base, fd)) 980 &mp->auxtrace_mp, evlist->mmap[idx].base, fd))
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 85d1b59802e8..d740fb877ab6 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -28,6 +28,7 @@ struct record_opts;
28struct perf_mmap { 28struct perf_mmap {
29 void *base; 29 void *base;
30 int mask; 30 int mask;
31 int fd;
31 atomic_t refcnt; 32 atomic_t refcnt;
32 u64 prev; 33 u64 prev;
33 struct auxtrace_mmap auxtrace_mmap; 34 struct auxtrace_mmap auxtrace_mmap;
@@ -43,6 +44,7 @@ struct perf_evlist {
43 bool overwrite; 44 bool overwrite;
44 bool enabled; 45 bool enabled;
45 bool has_user_cpus; 46 bool has_user_cpus;
47 bool backward;
46 size_t mmap_len; 48 size_t mmap_len;
47 int id_pos; 49 int id_pos;
48 int is_pos; 50 int is_pos;
@@ -135,6 +137,8 @@ void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx);
135 137
136void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); 138void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx);
137 139
140int perf_evlist__pause(struct perf_evlist *evlist);
141int perf_evlist__resume(struct perf_evlist *evlist);
138int perf_evlist__open(struct perf_evlist *evlist); 142int perf_evlist__open(struct perf_evlist *evlist);
139void perf_evlist__close(struct perf_evlist *evlist); 143void perf_evlist__close(struct perf_evlist *evlist);
140 144
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 964c7c3602c0..02c177d14c8d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -37,6 +37,7 @@ static struct {
37 bool clockid; 37 bool clockid;
38 bool clockid_wrong; 38 bool clockid_wrong;
39 bool lbr_flags; 39 bool lbr_flags;
40 bool write_backward;
40} perf_missing_features; 41} perf_missing_features;
41 42
42static clockid_t clockid; 43static clockid_t clockid;
@@ -1376,6 +1377,8 @@ fallback_missing_features:
1376 if (perf_missing_features.lbr_flags) 1377 if (perf_missing_features.lbr_flags)
1377 evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | 1378 evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS |
1378 PERF_SAMPLE_BRANCH_NO_CYCLES); 1379 PERF_SAMPLE_BRANCH_NO_CYCLES);
1380 if (perf_missing_features.write_backward)
1381 evsel->attr.write_backward = false;
1379retry_sample_id: 1382retry_sample_id:
1380 if (perf_missing_features.sample_id_all) 1383 if (perf_missing_features.sample_id_all)
1381 evsel->attr.sample_id_all = 0; 1384 evsel->attr.sample_id_all = 0;
@@ -1438,6 +1441,12 @@ retry_open:
1438 err = -EINVAL; 1441 err = -EINVAL;
1439 goto out_close; 1442 goto out_close;
1440 } 1443 }
1444
1445 if (evsel->overwrite &&
1446 perf_missing_features.write_backward) {
1447 err = -EINVAL;
1448 goto out_close;
1449 }
1441 } 1450 }
1442 } 1451 }
1443 1452
@@ -1500,6 +1509,10 @@ try_fallback:
1500 PERF_SAMPLE_BRANCH_NO_FLAGS))) { 1509 PERF_SAMPLE_BRANCH_NO_FLAGS))) {
1501 perf_missing_features.lbr_flags = true; 1510 perf_missing_features.lbr_flags = true;
1502 goto fallback_missing_features; 1511 goto fallback_missing_features;
1512 } else if (!perf_missing_features.write_backward &&
1513 evsel->attr.write_backward) {
1514 perf_missing_features.write_backward = true;
1515 goto fallback_missing_features;
1503 } 1516 }
1504 1517
1505out_close: 1518out_close:
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 8a644fef452c..c1f10159804c 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -112,6 +112,7 @@ struct perf_evsel {
112 bool tracking; 112 bool tracking;
113 bool per_pkg; 113 bool per_pkg;
114 bool precise_max; 114 bool precise_max;
115 bool overwrite;
115 /* parse modifier helper */ 116 /* parse modifier helper */
116 int exclude_GH; 117 int exclude_GH;
117 int nr_members; 118 int nr_members;
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index cfab531437c7..d1f19e0012d4 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -117,6 +117,13 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
117 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen); 117 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
118 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO); 118 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
119 } 119 }
120
121 if (h->branch_info->srcline_from)
122 hists__new_col_len(hists, HISTC_SRCLINE_FROM,
123 strlen(h->branch_info->srcline_from));
124 if (h->branch_info->srcline_to)
125 hists__new_col_len(hists, HISTC_SRCLINE_TO,
126 strlen(h->branch_info->srcline_to));
120 } 127 }
121 128
122 if (h->mem_info) { 129 if (h->mem_info) {
@@ -1042,6 +1049,8 @@ void hist_entry__delete(struct hist_entry *he)
1042 if (he->branch_info) { 1049 if (he->branch_info) {
1043 map__zput(he->branch_info->from.map); 1050 map__zput(he->branch_info->from.map);
1044 map__zput(he->branch_info->to.map); 1051 map__zput(he->branch_info->to.map);
1052 free_srcline(he->branch_info->srcline_from);
1053 free_srcline(he->branch_info->srcline_to);
1045 zfree(&he->branch_info); 1054 zfree(&he->branch_info);
1046 } 1055 }
1047 1056
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 0f84bfb42bb1..7b54ccf1b737 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -52,6 +52,8 @@ enum hist_column {
52 HISTC_MEM_IADDR_SYMBOL, 52 HISTC_MEM_IADDR_SYMBOL,
53 HISTC_TRANSACTION, 53 HISTC_TRANSACTION,
54 HISTC_CYCLES, 54 HISTC_CYCLES,
55 HISTC_SRCLINE_FROM,
56 HISTC_SRCLINE_TO,
55 HISTC_TRACE, 57 HISTC_TRACE,
56 HISTC_NR_COLS, /* Last entry */ 58 HISTC_NR_COLS, /* Last entry */
57}; 59};
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 20e69edd5006..c4e9bd70723c 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -353,6 +353,88 @@ struct sort_entry sort_srcline = {
353 .se_width_idx = HISTC_SRCLINE, 353 .se_width_idx = HISTC_SRCLINE,
354}; 354};
355 355
356/* --sort srcline_from */
357
358static int64_t
359sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
360{
361 if (!left->branch_info->srcline_from) {
362 struct map *map = left->branch_info->from.map;
363 if (!map)
364 left->branch_info->srcline_from = SRCLINE_UNKNOWN;
365 else
366 left->branch_info->srcline_from = get_srcline(map->dso,
367 map__rip_2objdump(map,
368 left->branch_info->from.al_addr),
369 left->branch_info->from.sym, true);
370 }
371 if (!right->branch_info->srcline_from) {
372 struct map *map = right->branch_info->from.map;
373 if (!map)
374 right->branch_info->srcline_from = SRCLINE_UNKNOWN;
375 else
376 right->branch_info->srcline_from = get_srcline(map->dso,
377 map__rip_2objdump(map,
378 right->branch_info->from.al_addr),
379 right->branch_info->from.sym, true);
380 }
381 return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from);
382}
383
384static int hist_entry__srcline_from_snprintf(struct hist_entry *he, char *bf,
385 size_t size, unsigned int width)
386{
387 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_from);
388}
389
390struct sort_entry sort_srcline_from = {
391 .se_header = "From Source:Line",
392 .se_cmp = sort__srcline_from_cmp,
393 .se_snprintf = hist_entry__srcline_from_snprintf,
394 .se_width_idx = HISTC_SRCLINE_FROM,
395};
396
397/* --sort srcline_to */
398
399static int64_t
400sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
401{
402 if (!left->branch_info->srcline_to) {
403 struct map *map = left->branch_info->to.map;
404 if (!map)
405 left->branch_info->srcline_to = SRCLINE_UNKNOWN;
406 else
407 left->branch_info->srcline_to = get_srcline(map->dso,
408 map__rip_2objdump(map,
409 left->branch_info->to.al_addr),
410 left->branch_info->from.sym, true);
411 }
412 if (!right->branch_info->srcline_to) {
413 struct map *map = right->branch_info->to.map;
414 if (!map)
415 right->branch_info->srcline_to = SRCLINE_UNKNOWN;
416 else
417 right->branch_info->srcline_to = get_srcline(map->dso,
418 map__rip_2objdump(map,
419 right->branch_info->to.al_addr),
420 right->branch_info->to.sym, true);
421 }
422 return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to);
423}
424
425static int hist_entry__srcline_to_snprintf(struct hist_entry *he, char *bf,
426 size_t size, unsigned int width)
427{
428 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_to);
429}
430
431struct sort_entry sort_srcline_to = {
432 .se_header = "To Source:Line",
433 .se_cmp = sort__srcline_to_cmp,
434 .se_snprintf = hist_entry__srcline_to_snprintf,
435 .se_width_idx = HISTC_SRCLINE_TO,
436};
437
356/* --sort srcfile */ 438/* --sort srcfile */
357 439
358static char no_srcfile[1]; 440static char no_srcfile[1];
@@ -1347,6 +1429,8 @@ static struct sort_dimension bstack_sort_dimensions[] = {
1347 DIM(SORT_IN_TX, "in_tx", sort_in_tx), 1429 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1348 DIM(SORT_ABORT, "abort", sort_abort), 1430 DIM(SORT_ABORT, "abort", sort_abort),
1349 DIM(SORT_CYCLES, "cycles", sort_cycles), 1431 DIM(SORT_CYCLES, "cycles", sort_cycles),
1432 DIM(SORT_SRCLINE_FROM, "srcline_from", sort_srcline_from),
1433 DIM(SORT_SRCLINE_TO, "srcline_to", sort_srcline_to),
1350}; 1434};
1351 1435
1352#undef DIM 1436#undef DIM
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 42927f448bcb..ebb59cacd092 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -215,6 +215,8 @@ enum sort_type {
215 SORT_ABORT, 215 SORT_ABORT,
216 SORT_IN_TX, 216 SORT_IN_TX,
217 SORT_CYCLES, 217 SORT_CYCLES,
218 SORT_SRCLINE_FROM,
219 SORT_SRCLINE_TO,
218 220
219 /* memory mode specific sort keys */ 221 /* memory mode specific sort keys */
220 __SORT_MEMORY_MODE, 222 __SORT_MEMORY_MODE,
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index fa415347dbf9..b10d558a8803 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -186,6 +186,8 @@ struct branch_info {
186 struct addr_map_symbol from; 186 struct addr_map_symbol from;
187 struct addr_map_symbol to; 187 struct addr_map_symbol to;
188 struct branch_flags flags; 188 struct branch_flags flags;
189 char *srcline_from;
190 char *srcline_to;
189}; 191};
190 192
191struct mem_info { 193struct mem_info {