aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/annotate.c163
-rw-r--r--tools/perf/util/annotate.h1
-rw-r--r--tools/perf/util/archinsn.h12
-rw-r--r--tools/perf/util/bpf-event.c425
-rw-r--r--tools/perf/util/bpf-event.h42
-rw-r--r--tools/perf/util/build-id.c1
-rw-r--r--tools/perf/util/config.c3
-rw-r--r--tools/perf/util/cs-etm-decoder/cs-etm-decoder.c1
-rw-r--r--tools/perf/util/data.c107
-rw-r--r--tools/perf/util/data.h14
-rw-r--r--tools/perf/util/dso.c43
-rw-r--r--tools/perf/util/dso.h8
-rw-r--r--tools/perf/util/env.c155
-rw-r--r--tools/perf/util/env.h24
-rw-r--r--tools/perf/util/evlist.c148
-rw-r--r--tools/perf/util/evlist.h14
-rw-r--r--tools/perf/util/evsel.c80
-rw-r--r--tools/perf/util/evsel.h6
-rw-r--r--tools/perf/util/header.c295
-rw-r--r--tools/perf/util/header.h7
-rw-r--r--tools/perf/util/hist.c54
-rw-r--r--tools/perf/util/hist.h31
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-decoder.c20
-rw-r--r--tools/perf/util/machine.c32
-rw-r--r--tools/perf/util/map.c18
-rw-r--r--tools/perf/util/ordered-events.c2
-rw-r--r--tools/perf/util/parse-events.c2
-rw-r--r--tools/perf/util/pmu.c10
-rw-r--r--tools/perf/util/probe-event.c6
-rw-r--r--tools/perf/util/session.c28
-rw-r--r--tools/perf/util/sort.c91
-rw-r--r--tools/perf/util/sort.h12
-rw-r--r--tools/perf/util/stat.c12
-rw-r--r--tools/perf/util/symbol.c5
-rw-r--r--tools/perf/util/symbol_conf.h3
-rw-r--r--tools/perf/util/time-utils.c8
-rw-r--r--tools/perf/util/time-utils.h1
37 files changed, 1652 insertions, 232 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 5f6dbbf5d749..c8b01176c9e1 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -10,6 +10,10 @@
10#include <errno.h> 10#include <errno.h>
11#include <inttypes.h> 11#include <inttypes.h>
12#include <libgen.h> 12#include <libgen.h>
13#include <bpf/bpf.h>
14#include <bpf/btf.h>
15#include <bpf/libbpf.h>
16#include <linux/btf.h>
13#include "util.h" 17#include "util.h"
14#include "ui/ui.h" 18#include "ui/ui.h"
15#include "sort.h" 19#include "sort.h"
@@ -24,6 +28,7 @@
24#include "annotate.h" 28#include "annotate.h"
25#include "evsel.h" 29#include "evsel.h"
26#include "evlist.h" 30#include "evlist.h"
31#include "bpf-event.h"
27#include "block-range.h" 32#include "block-range.h"
28#include "string2.h" 33#include "string2.h"
29#include "arch/common.h" 34#include "arch/common.h"
@@ -31,6 +36,7 @@
31#include <pthread.h> 36#include <pthread.h>
32#include <linux/bitops.h> 37#include <linux/bitops.h>
33#include <linux/kernel.h> 38#include <linux/kernel.h>
39#include <bpf/libbpf.h>
34 40
35/* FIXME: For the HE_COLORSET */ 41/* FIXME: For the HE_COLORSET */
36#include "ui/browser.h" 42#include "ui/browser.h"
@@ -1615,6 +1621,9 @@ int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map *
1615 " --vmlinux vmlinux\n", build_id_msg ?: ""); 1621 " --vmlinux vmlinux\n", build_id_msg ?: "");
1616 } 1622 }
1617 break; 1623 break;
1624 case SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF:
1625 scnprintf(buf, buflen, "Please link with binutils's libopcode to enable BPF annotation");
1626 break;
1618 default: 1627 default:
1619 scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum); 1628 scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum);
1620 break; 1629 break;
@@ -1674,6 +1683,156 @@ fallback:
1674 return 0; 1683 return 0;
1675} 1684}
1676 1685
1686#if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
1687#define PACKAGE "perf"
1688#include <bfd.h>
1689#include <dis-asm.h>
1690
1691static int symbol__disassemble_bpf(struct symbol *sym,
1692 struct annotate_args *args)
1693{
1694 struct annotation *notes = symbol__annotation(sym);
1695 struct annotation_options *opts = args->options;
1696 struct bpf_prog_info_linear *info_linear;
1697 struct bpf_prog_linfo *prog_linfo = NULL;
1698 struct bpf_prog_info_node *info_node;
1699 int len = sym->end - sym->start;
1700 disassembler_ftype disassemble;
1701 struct map *map = args->ms.map;
1702 struct disassemble_info info;
1703 struct dso *dso = map->dso;
1704 int pc = 0, count, sub_id;
1705 struct btf *btf = NULL;
1706 char tpath[PATH_MAX];
1707 size_t buf_size;
1708 int nr_skip = 0;
1709 int ret = -1;
1710 char *buf;
1711 bfd *bfdf;
1712 FILE *s;
1713
1714 if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO)
1715 return -1;
1716
1717 pr_debug("%s: handling sym %s addr %lx len %lx\n", __func__,
1718 sym->name, sym->start, sym->end - sym->start);
1719
1720 memset(tpath, 0, sizeof(tpath));
1721 perf_exe(tpath, sizeof(tpath));
1722
1723 bfdf = bfd_openr(tpath, NULL);
1724 assert(bfdf);
1725 assert(bfd_check_format(bfdf, bfd_object));
1726
1727 s = open_memstream(&buf, &buf_size);
1728 if (!s)
1729 goto out;
1730 init_disassemble_info(&info, s,
1731 (fprintf_ftype) fprintf);
1732
1733 info.arch = bfd_get_arch(bfdf);
1734 info.mach = bfd_get_mach(bfdf);
1735
1736 info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env,
1737 dso->bpf_prog.id);
1738 if (!info_node)
1739 goto out;
1740 info_linear = info_node->info_linear;
1741 sub_id = dso->bpf_prog.sub_id;
1742
1743 info.buffer = (void *)(info_linear->info.jited_prog_insns);
1744 info.buffer_length = info_linear->info.jited_prog_len;
1745
1746 if (info_linear->info.nr_line_info)
1747 prog_linfo = bpf_prog_linfo__new(&info_linear->info);
1748
1749 if (info_linear->info.btf_id) {
1750 struct btf_node *node;
1751
1752 node = perf_env__find_btf(dso->bpf_prog.env,
1753 info_linear->info.btf_id);
1754 if (node)
1755 btf = btf__new((__u8 *)(node->data),
1756 node->data_size);
1757 }
1758
1759 disassemble_init_for_target(&info);
1760
1761#ifdef DISASM_FOUR_ARGS_SIGNATURE
1762 disassemble = disassembler(info.arch,
1763 bfd_big_endian(bfdf),
1764 info.mach,
1765 bfdf);
1766#else
1767 disassemble = disassembler(bfdf);
1768#endif
1769 assert(disassemble);
1770
1771 fflush(s);
1772 do {
1773 const struct bpf_line_info *linfo = NULL;
1774 struct disasm_line *dl;
1775 size_t prev_buf_size;
1776 const char *srcline;
1777 u64 addr;
1778
1779 addr = pc + ((u64 *)(info_linear->info.jited_ksyms))[sub_id];
1780 count = disassemble(pc, &info);
1781
1782 if (prog_linfo)
1783 linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
1784 addr, sub_id,
1785 nr_skip);
1786
1787 if (linfo && btf) {
1788 srcline = btf__name_by_offset(btf, linfo->line_off);
1789 nr_skip++;
1790 } else
1791 srcline = NULL;
1792
1793 fprintf(s, "\n");
1794 prev_buf_size = buf_size;
1795 fflush(s);
1796
1797 if (!opts->hide_src_code && srcline) {
1798 args->offset = -1;
1799 args->line = strdup(srcline);
1800 args->line_nr = 0;
1801 args->ms.sym = sym;
1802 dl = disasm_line__new(args);
1803 if (dl) {
1804 annotation_line__add(&dl->al,
1805 &notes->src->source);
1806 }
1807 }
1808
1809 args->offset = pc;
1810 args->line = buf + prev_buf_size;
1811 args->line_nr = 0;
1812 args->ms.sym = sym;
1813 dl = disasm_line__new(args);
1814 if (dl)
1815 annotation_line__add(&dl->al, &notes->src->source);
1816
1817 pc += count;
1818 } while (count > 0 && pc < len);
1819
1820 ret = 0;
1821out:
1822 free(prog_linfo);
1823 free(btf);
1824 fclose(s);
1825 bfd_close(bfdf);
1826 return ret;
1827}
1828#else // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
1829static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused,
1830 struct annotate_args *args __maybe_unused)
1831{
1832 return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF;
1833}
1834#endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
1835
1677static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) 1836static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
1678{ 1837{
1679 struct annotation_options *opts = args->options; 1838 struct annotation_options *opts = args->options;
@@ -1701,7 +1860,9 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
1701 pr_debug("annotating [%p] %30s : [%p] %30s\n", 1860 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1702 dso, dso->long_name, sym, sym->name); 1861 dso, dso->long_name, sym, sym->name);
1703 1862
1704 if (dso__is_kcore(dso)) { 1863 if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) {
1864 return symbol__disassemble_bpf(sym, args);
1865 } else if (dso__is_kcore(dso)) {
1705 kce.kcore_filename = symfs_filename; 1866 kce.kcore_filename = symfs_filename;
1706 kce.addr = map__rip_2objdump(map, sym->start); 1867 kce.addr = map__rip_2objdump(map, sym->start);
1707 kce.offs = sym->start; 1868 kce.offs = sym->start;
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index df34fe483164..5bc0cf655d37 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -369,6 +369,7 @@ enum symbol_disassemble_errno {
369 __SYMBOL_ANNOTATE_ERRNO__START = -10000, 369 __SYMBOL_ANNOTATE_ERRNO__START = -10000,
370 370
371 SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX = __SYMBOL_ANNOTATE_ERRNO__START, 371 SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX = __SYMBOL_ANNOTATE_ERRNO__START,
372 SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF,
372 373
373 __SYMBOL_ANNOTATE_ERRNO__END, 374 __SYMBOL_ANNOTATE_ERRNO__END,
374}; 375};
diff --git a/tools/perf/util/archinsn.h b/tools/perf/util/archinsn.h
new file mode 100644
index 000000000000..448cbb6b8d7e
--- /dev/null
+++ b/tools/perf/util/archinsn.h
@@ -0,0 +1,12 @@
1#ifndef INSN_H
2#define INSN_H 1
3
4struct perf_sample;
5struct machine;
6struct thread;
7
8void arch_fetch_insn(struct perf_sample *sample,
9 struct thread *thread,
10 struct machine *machine);
11
12#endif
diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c
index 028c8ec1f62a..2a4a0da35632 100644
--- a/tools/perf/util/bpf-event.c
+++ b/tools/perf/util/bpf-event.c
@@ -3,11 +3,17 @@
3#include <stdlib.h> 3#include <stdlib.h>
4#include <bpf/bpf.h> 4#include <bpf/bpf.h>
5#include <bpf/btf.h> 5#include <bpf/btf.h>
6#include <bpf/libbpf.h>
6#include <linux/btf.h> 7#include <linux/btf.h>
8#include <linux/err.h>
7#include "bpf-event.h" 9#include "bpf-event.h"
8#include "debug.h" 10#include "debug.h"
9#include "symbol.h" 11#include "symbol.h"
10#include "machine.h" 12#include "machine.h"
13#include "env.h"
14#include "session.h"
15#include "map.h"
16#include "evlist.h"
11 17
12#define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr)) 18#define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
13 19
@@ -21,15 +27,122 @@ static int snprintf_hex(char *buf, size_t size, unsigned char *data, size_t len)
21 return ret; 27 return ret;
22} 28}
23 29
30static int machine__process_bpf_event_load(struct machine *machine,
31 union perf_event *event,
32 struct perf_sample *sample __maybe_unused)
33{
34 struct bpf_prog_info_linear *info_linear;
35 struct bpf_prog_info_node *info_node;
36 struct perf_env *env = machine->env;
37 int id = event->bpf_event.id;
38 unsigned int i;
39
40 /* perf-record, no need to handle bpf-event */
41 if (env == NULL)
42 return 0;
43
44 info_node = perf_env__find_bpf_prog_info(env, id);
45 if (!info_node)
46 return 0;
47 info_linear = info_node->info_linear;
48
49 for (i = 0; i < info_linear->info.nr_jited_ksyms; i++) {
50 u64 *addrs = (u64 *)(uintptr_t)(info_linear->info.jited_ksyms);
51 u64 addr = addrs[i];
52 struct map *map;
53
54 map = map_groups__find(&machine->kmaps, addr);
55
56 if (map) {
57 map->dso->binary_type = DSO_BINARY_TYPE__BPF_PROG_INFO;
58 map->dso->bpf_prog.id = id;
59 map->dso->bpf_prog.sub_id = i;
60 map->dso->bpf_prog.env = env;
61 }
62 }
63 return 0;
64}
65
24int machine__process_bpf_event(struct machine *machine __maybe_unused, 66int machine__process_bpf_event(struct machine *machine __maybe_unused,
25 union perf_event *event, 67 union perf_event *event,
26 struct perf_sample *sample __maybe_unused) 68 struct perf_sample *sample __maybe_unused)
27{ 69{
28 if (dump_trace) 70 if (dump_trace)
29 perf_event__fprintf_bpf_event(event, stdout); 71 perf_event__fprintf_bpf_event(event, stdout);
72
73 switch (event->bpf_event.type) {
74 case PERF_BPF_EVENT_PROG_LOAD:
75 return machine__process_bpf_event_load(machine, event, sample);
76
77 case PERF_BPF_EVENT_PROG_UNLOAD:
78 /*
79 * Do not free bpf_prog_info and btf of the program here,
80 * as annotation still need them. They will be freed at
81 * the end of the session.
82 */
83 break;
84 default:
85 pr_debug("unexpected bpf_event type of %d\n",
86 event->bpf_event.type);
87 break;
88 }
30 return 0; 89 return 0;
31} 90}
32 91
92static int perf_env__fetch_btf(struct perf_env *env,
93 u32 btf_id,
94 struct btf *btf)
95{
96 struct btf_node *node;
97 u32 data_size;
98 const void *data;
99
100 data = btf__get_raw_data(btf, &data_size);
101
102 node = malloc(data_size + sizeof(struct btf_node));
103 if (!node)
104 return -1;
105
106 node->id = btf_id;
107 node->data_size = data_size;
108 memcpy(node->data, data, data_size);
109
110 perf_env__insert_btf(env, node);
111 return 0;
112}
113
114static int synthesize_bpf_prog_name(char *buf, int size,
115 struct bpf_prog_info *info,
116 struct btf *btf,
117 u32 sub_id)
118{
119 u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(uintptr_t)(info->prog_tags);
120 void *func_infos = (void *)(uintptr_t)(info->func_info);
121 u32 sub_prog_cnt = info->nr_jited_ksyms;
122 const struct bpf_func_info *finfo;
123 const char *short_name = NULL;
124 const struct btf_type *t;
125 int name_len;
126
127 name_len = snprintf(buf, size, "bpf_prog_");
128 name_len += snprintf_hex(buf + name_len, size - name_len,
129 prog_tags[sub_id], BPF_TAG_SIZE);
130 if (btf) {
131 finfo = func_infos + sub_id * info->func_info_rec_size;
132 t = btf__type_by_id(btf, finfo->type_id);
133 short_name = btf__name_by_offset(btf, t->name_off);
134 } else if (sub_id == 0 && sub_prog_cnt == 1) {
135 /* no subprog */
136 if (info->name[0])
137 short_name = info->name;
138 } else
139 short_name = "F";
140 if (short_name)
141 name_len += snprintf(buf + name_len, size - name_len,
142 "_%s", short_name);
143 return name_len;
144}
145
33/* 146/*
34 * Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf 147 * Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf
35 * program. One PERF_RECORD_BPF_EVENT is generated for the program. And 148 * program. One PERF_RECORD_BPF_EVENT is generated for the program. And
@@ -40,7 +153,7 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused,
40 * -1 for failures; 153 * -1 for failures;
41 * -2 for lack of kernel support. 154 * -2 for lack of kernel support.
42 */ 155 */
43static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool, 156static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
44 perf_event__handler_t process, 157 perf_event__handler_t process,
45 struct machine *machine, 158 struct machine *machine,
46 int fd, 159 int fd,
@@ -49,102 +162,71 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
49{ 162{
50 struct ksymbol_event *ksymbol_event = &event->ksymbol_event; 163 struct ksymbol_event *ksymbol_event = &event->ksymbol_event;
51 struct bpf_event *bpf_event = &event->bpf_event; 164 struct bpf_event *bpf_event = &event->bpf_event;
52 u32 sub_prog_cnt, i, func_info_rec_size = 0; 165 struct bpf_prog_info_linear *info_linear;
53 u8 (*prog_tags)[BPF_TAG_SIZE] = NULL; 166 struct perf_tool *tool = session->tool;
54 struct bpf_prog_info info = { .type = 0, }; 167 struct bpf_prog_info_node *info_node;
55 u32 info_len = sizeof(info); 168 struct bpf_prog_info *info;
56 void *func_infos = NULL;
57 u64 *prog_addrs = NULL;
58 struct btf *btf = NULL; 169 struct btf *btf = NULL;
59 u32 *prog_lens = NULL; 170 struct perf_env *env;
60 bool has_btf = false; 171 u32 sub_prog_cnt, i;
61 char errbuf[512];
62 int err = 0; 172 int err = 0;
173 u64 arrays;
174
175 /*
176 * for perf-record and perf-report use header.env;
177 * otherwise, use global perf_env.
178 */
179 env = session->data ? &session->header.env : &perf_env;
63 180
64 /* Call bpf_obj_get_info_by_fd() to get sizes of arrays */ 181 arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS;
65 err = bpf_obj_get_info_by_fd(fd, &info, &info_len); 182 arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
183 arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
184 arrays |= 1UL << BPF_PROG_INFO_PROG_TAGS;
185 arrays |= 1UL << BPF_PROG_INFO_JITED_INSNS;
186 arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
187 arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
66 188
67 if (err) { 189 info_linear = bpf_program__get_prog_info_linear(fd, arrays);
68 pr_debug("%s: failed to get BPF program info: %s, aborting\n", 190 if (IS_ERR_OR_NULL(info_linear)) {
69 __func__, str_error_r(errno, errbuf, sizeof(errbuf))); 191 info_linear = NULL;
192 pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
70 return -1; 193 return -1;
71 } 194 }
72 if (info_len < offsetof(struct bpf_prog_info, prog_tags)) { 195
196 if (info_linear->info_len < offsetof(struct bpf_prog_info, prog_tags)) {
73 pr_debug("%s: the kernel is too old, aborting\n", __func__); 197 pr_debug("%s: the kernel is too old, aborting\n", __func__);
74 return -2; 198 return -2;
75 } 199 }
76 200
201 info = &info_linear->info;
202
77 /* number of ksyms, func_lengths, and tags should match */ 203 /* number of ksyms, func_lengths, and tags should match */
78 sub_prog_cnt = info.nr_jited_ksyms; 204 sub_prog_cnt = info->nr_jited_ksyms;
79 if (sub_prog_cnt != info.nr_prog_tags || 205 if (sub_prog_cnt != info->nr_prog_tags ||
80 sub_prog_cnt != info.nr_jited_func_lens) 206 sub_prog_cnt != info->nr_jited_func_lens)
81 return -1; 207 return -1;
82 208
83 /* check BTF func info support */ 209 /* check BTF func info support */
84 if (info.btf_id && info.nr_func_info && info.func_info_rec_size) { 210 if (info->btf_id && info->nr_func_info && info->func_info_rec_size) {
85 /* btf func info number should be same as sub_prog_cnt */ 211 /* btf func info number should be same as sub_prog_cnt */
86 if (sub_prog_cnt != info.nr_func_info) { 212 if (sub_prog_cnt != info->nr_func_info) {
87 pr_debug("%s: mismatch in BPF sub program count and BTF function info count, aborting\n", __func__); 213 pr_debug("%s: mismatch in BPF sub program count and BTF function info count, aborting\n", __func__);
88 return -1; 214 err = -1;
89 } 215 goto out;
90 if (btf__get_from_id(info.btf_id, &btf)) {
91 pr_debug("%s: failed to get BTF of id %u, aborting\n", __func__, info.btf_id);
92 return -1;
93 } 216 }
94 func_info_rec_size = info.func_info_rec_size; 217 if (btf__get_from_id(info->btf_id, &btf)) {
95 func_infos = calloc(sub_prog_cnt, func_info_rec_size); 218 pr_debug("%s: failed to get BTF of id %u, aborting\n", __func__, info->btf_id);
96 if (!func_infos) { 219 err = -1;
97 pr_debug("%s: failed to allocate memory for func_infos, aborting\n", __func__); 220 btf = NULL;
98 return -1; 221 goto out;
99 } 222 }
100 has_btf = true; 223 perf_env__fetch_btf(env, info->btf_id, btf);
101 }
102
103 /*
104 * We need address, length, and tag for each sub program.
105 * Allocate memory and call bpf_obj_get_info_by_fd() again
106 */
107 prog_addrs = calloc(sub_prog_cnt, sizeof(u64));
108 if (!prog_addrs) {
109 pr_debug("%s: failed to allocate memory for prog_addrs, aborting\n", __func__);
110 goto out;
111 }
112 prog_lens = calloc(sub_prog_cnt, sizeof(u32));
113 if (!prog_lens) {
114 pr_debug("%s: failed to allocate memory for prog_lens, aborting\n", __func__);
115 goto out;
116 }
117 prog_tags = calloc(sub_prog_cnt, BPF_TAG_SIZE);
118 if (!prog_tags) {
119 pr_debug("%s: failed to allocate memory for prog_tags, aborting\n", __func__);
120 goto out;
121 }
122
123 memset(&info, 0, sizeof(info));
124 info.nr_jited_ksyms = sub_prog_cnt;
125 info.nr_jited_func_lens = sub_prog_cnt;
126 info.nr_prog_tags = sub_prog_cnt;
127 info.jited_ksyms = ptr_to_u64(prog_addrs);
128 info.jited_func_lens = ptr_to_u64(prog_lens);
129 info.prog_tags = ptr_to_u64(prog_tags);
130 info_len = sizeof(info);
131 if (has_btf) {
132 info.nr_func_info = sub_prog_cnt;
133 info.func_info_rec_size = func_info_rec_size;
134 info.func_info = ptr_to_u64(func_infos);
135 }
136
137 err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
138 if (err) {
139 pr_debug("%s: failed to get BPF program info, aborting\n", __func__);
140 goto out;
141 } 224 }
142 225
143 /* Synthesize PERF_RECORD_KSYMBOL */ 226 /* Synthesize PERF_RECORD_KSYMBOL */
144 for (i = 0; i < sub_prog_cnt; i++) { 227 for (i = 0; i < sub_prog_cnt; i++) {
145 const struct bpf_func_info *finfo; 228 __u32 *prog_lens = (__u32 *)(uintptr_t)(info->jited_func_lens);
146 const char *short_name = NULL; 229 __u64 *prog_addrs = (__u64 *)(uintptr_t)(info->jited_ksyms);
147 const struct btf_type *t;
148 int name_len; 230 int name_len;
149 231
150 *ksymbol_event = (struct ksymbol_event){ 232 *ksymbol_event = (struct ksymbol_event){
@@ -157,26 +239,9 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
157 .ksym_type = PERF_RECORD_KSYMBOL_TYPE_BPF, 239 .ksym_type = PERF_RECORD_KSYMBOL_TYPE_BPF,
158 .flags = 0, 240 .flags = 0,
159 }; 241 };
160 name_len = snprintf(ksymbol_event->name, KSYM_NAME_LEN,
161 "bpf_prog_");
162 name_len += snprintf_hex(ksymbol_event->name + name_len,
163 KSYM_NAME_LEN - name_len,
164 prog_tags[i], BPF_TAG_SIZE);
165 if (has_btf) {
166 finfo = func_infos + i * info.func_info_rec_size;
167 t = btf__type_by_id(btf, finfo->type_id);
168 short_name = btf__name_by_offset(btf, t->name_off);
169 } else if (i == 0 && sub_prog_cnt == 1) {
170 /* no subprog */
171 if (info.name[0])
172 short_name = info.name;
173 } else
174 short_name = "F";
175 if (short_name)
176 name_len += snprintf(ksymbol_event->name + name_len,
177 KSYM_NAME_LEN - name_len,
178 "_%s", short_name);
179 242
243 name_len = synthesize_bpf_prog_name(ksymbol_event->name,
244 KSYM_NAME_LEN, info, btf, i);
180 ksymbol_event->header.size += PERF_ALIGN(name_len + 1, 245 ksymbol_event->header.size += PERF_ALIGN(name_len + 1,
181 sizeof(u64)); 246 sizeof(u64));
182 247
@@ -186,8 +251,8 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
186 machine, process); 251 machine, process);
187 } 252 }
188 253
189 /* Synthesize PERF_RECORD_BPF_EVENT */ 254 if (!opts->no_bpf_event) {
190 if (opts->bpf_event) { 255 /* Synthesize PERF_RECORD_BPF_EVENT */
191 *bpf_event = (struct bpf_event){ 256 *bpf_event = (struct bpf_event){
192 .header = { 257 .header = {
193 .type = PERF_RECORD_BPF_EVENT, 258 .type = PERF_RECORD_BPF_EVENT,
@@ -195,25 +260,38 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
195 }, 260 },
196 .type = PERF_BPF_EVENT_PROG_LOAD, 261 .type = PERF_BPF_EVENT_PROG_LOAD,
197 .flags = 0, 262 .flags = 0,
198 .id = info.id, 263 .id = info->id,
199 }; 264 };
200 memcpy(bpf_event->tag, prog_tags[i], BPF_TAG_SIZE); 265 memcpy(bpf_event->tag, info->tag, BPF_TAG_SIZE);
201 memset((void *)event + event->header.size, 0, machine->id_hdr_size); 266 memset((void *)event + event->header.size, 0, machine->id_hdr_size);
202 event->header.size += machine->id_hdr_size; 267 event->header.size += machine->id_hdr_size;
268
269 /* save bpf_prog_info to env */
270 info_node = malloc(sizeof(struct bpf_prog_info_node));
271 if (!info_node) {
272 err = -1;
273 goto out;
274 }
275
276 info_node->info_linear = info_linear;
277 perf_env__insert_bpf_prog_info(env, info_node);
278 info_linear = NULL;
279
280 /*
281 * process after saving bpf_prog_info to env, so that
282 * required information is ready for look up
283 */
203 err = perf_tool__process_synth_event(tool, event, 284 err = perf_tool__process_synth_event(tool, event,
204 machine, process); 285 machine, process);
205 } 286 }
206 287
207out: 288out:
208 free(prog_tags); 289 free(info_linear);
209 free(prog_lens);
210 free(prog_addrs);
211 free(func_infos);
212 free(btf); 290 free(btf);
213 return err ? -1 : 0; 291 return err ? -1 : 0;
214} 292}
215 293
216int perf_event__synthesize_bpf_events(struct perf_tool *tool, 294int perf_event__synthesize_bpf_events(struct perf_session *session,
217 perf_event__handler_t process, 295 perf_event__handler_t process,
218 struct machine *machine, 296 struct machine *machine,
219 struct record_opts *opts) 297 struct record_opts *opts)
@@ -247,7 +325,7 @@ int perf_event__synthesize_bpf_events(struct perf_tool *tool,
247 continue; 325 continue;
248 } 326 }
249 327
250 err = perf_event__synthesize_one_bpf_prog(tool, process, 328 err = perf_event__synthesize_one_bpf_prog(session, process,
251 machine, fd, 329 machine, fd,
252 event, opts); 330 event, opts);
253 close(fd); 331 close(fd);
@@ -261,3 +339,142 @@ int perf_event__synthesize_bpf_events(struct perf_tool *tool,
261 free(event); 339 free(event);
262 return err; 340 return err;
263} 341}
342
343static void perf_env__add_bpf_info(struct perf_env *env, u32 id)
344{
345 struct bpf_prog_info_linear *info_linear;
346 struct bpf_prog_info_node *info_node;
347 struct btf *btf = NULL;
348 u64 arrays;
349 u32 btf_id;
350 int fd;
351
352 fd = bpf_prog_get_fd_by_id(id);
353 if (fd < 0)
354 return;
355
356 arrays = 1UL << BPF_PROG_INFO_JITED_KSYMS;
357 arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS;
358 arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO;
359 arrays |= 1UL << BPF_PROG_INFO_PROG_TAGS;
360 arrays |= 1UL << BPF_PROG_INFO_JITED_INSNS;
361 arrays |= 1UL << BPF_PROG_INFO_LINE_INFO;
362 arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO;
363
364 info_linear = bpf_program__get_prog_info_linear(fd, arrays);
365 if (IS_ERR_OR_NULL(info_linear)) {
366 pr_debug("%s: failed to get BPF program info. aborting\n", __func__);
367 goto out;
368 }
369
370 btf_id = info_linear->info.btf_id;
371
372 info_node = malloc(sizeof(struct bpf_prog_info_node));
373 if (info_node) {
374 info_node->info_linear = info_linear;
375 perf_env__insert_bpf_prog_info(env, info_node);
376 } else
377 free(info_linear);
378
379 if (btf_id == 0)
380 goto out;
381
382 if (btf__get_from_id(btf_id, &btf)) {
383 pr_debug("%s: failed to get BTF of id %u, aborting\n",
384 __func__, btf_id);
385 goto out;
386 }
387 perf_env__fetch_btf(env, btf_id, btf);
388
389out:
390 free(btf);
391 close(fd);
392}
393
394static int bpf_event__sb_cb(union perf_event *event, void *data)
395{
396 struct perf_env *env = data;
397
398 if (event->header.type != PERF_RECORD_BPF_EVENT)
399 return -1;
400
401 switch (event->bpf_event.type) {
402 case PERF_BPF_EVENT_PROG_LOAD:
403 perf_env__add_bpf_info(env, event->bpf_event.id);
404
405 case PERF_BPF_EVENT_PROG_UNLOAD:
406 /*
407 * Do not free bpf_prog_info and btf of the program here,
408 * as annotation still need them. They will be freed at
409 * the end of the session.
410 */
411 break;
412 default:
413 pr_debug("unexpected bpf_event type of %d\n",
414 event->bpf_event.type);
415 break;
416 }
417
418 return 0;
419}
420
421int bpf_event__add_sb_event(struct perf_evlist **evlist,
422 struct perf_env *env)
423{
424 struct perf_event_attr attr = {
425 .type = PERF_TYPE_SOFTWARE,
426 .config = PERF_COUNT_SW_DUMMY,
427 .sample_id_all = 1,
428 .watermark = 1,
429 .bpf_event = 1,
430 .size = sizeof(attr), /* to capture ABI version */
431 };
432
433 /*
434 * Older gcc versions don't support designated initializers, like above,
435 * for unnamed union members, such as the following:
436 */
437 attr.wakeup_watermark = 1;
438
439 return perf_evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env);
440}
441
442void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,
443 struct perf_env *env,
444 FILE *fp)
445{
446 __u32 *prog_lens = (__u32 *)(uintptr_t)(info->jited_func_lens);
447 __u64 *prog_addrs = (__u64 *)(uintptr_t)(info->jited_ksyms);
448 char name[KSYM_NAME_LEN];
449 struct btf *btf = NULL;
450 u32 sub_prog_cnt, i;
451
452 sub_prog_cnt = info->nr_jited_ksyms;
453 if (sub_prog_cnt != info->nr_prog_tags ||
454 sub_prog_cnt != info->nr_jited_func_lens)
455 return;
456
457 if (info->btf_id) {
458 struct btf_node *node;
459
460 node = perf_env__find_btf(env, info->btf_id);
461 if (node)
462 btf = btf__new((__u8 *)(node->data),
463 node->data_size);
464 }
465
466 if (sub_prog_cnt == 1) {
467 synthesize_bpf_prog_name(name, KSYM_NAME_LEN, info, btf, 0);
468 fprintf(fp, "# bpf_prog_info %u: %s addr 0x%llx size %u\n",
469 info->id, name, prog_addrs[0], prog_lens[0]);
470 return;
471 }
472
473 fprintf(fp, "# bpf_prog_info %u:\n", info->id);
474 for (i = 0; i < sub_prog_cnt; i++) {
475 synthesize_bpf_prog_name(name, KSYM_NAME_LEN, info, btf, i);
476
477 fprintf(fp, "# \tsub_prog %u: %s addr 0x%llx size %u\n",
478 i, name, prog_addrs[i], prog_lens[i]);
479 }
480}
diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h
index 7890067e1a37..04c33b3bfe28 100644
--- a/tools/perf/util/bpf-event.h
+++ b/tools/perf/util/bpf-event.h
@@ -3,22 +3,45 @@
3#define __PERF_BPF_EVENT_H 3#define __PERF_BPF_EVENT_H
4 4
5#include <linux/compiler.h> 5#include <linux/compiler.h>
6#include <linux/rbtree.h>
7#include <pthread.h>
8#include <api/fd/array.h>
6#include "event.h" 9#include "event.h"
10#include <stdio.h>
7 11
8struct machine; 12struct machine;
9union perf_event; 13union perf_event;
14struct perf_env;
10struct perf_sample; 15struct perf_sample;
11struct perf_tool;
12struct record_opts; 16struct record_opts;
17struct evlist;
18struct target;
19
20struct bpf_prog_info_node {
21 struct bpf_prog_info_linear *info_linear;
22 struct rb_node rb_node;
23};
24
25struct btf_node {
26 struct rb_node rb_node;
27 u32 id;
28 u32 data_size;
29 char data[];
30};
13 31
14#ifdef HAVE_LIBBPF_SUPPORT 32#ifdef HAVE_LIBBPF_SUPPORT
15int machine__process_bpf_event(struct machine *machine, union perf_event *event, 33int machine__process_bpf_event(struct machine *machine, union perf_event *event,
16 struct perf_sample *sample); 34 struct perf_sample *sample);
17 35
18int perf_event__synthesize_bpf_events(struct perf_tool *tool, 36int perf_event__synthesize_bpf_events(struct perf_session *session,
19 perf_event__handler_t process, 37 perf_event__handler_t process,
20 struct machine *machine, 38 struct machine *machine,
21 struct record_opts *opts); 39 struct record_opts *opts);
40int bpf_event__add_sb_event(struct perf_evlist **evlist,
41 struct perf_env *env);
42void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,
43 struct perf_env *env,
44 FILE *fp);
22#else 45#else
23static inline int machine__process_bpf_event(struct machine *machine __maybe_unused, 46static inline int machine__process_bpf_event(struct machine *machine __maybe_unused,
24 union perf_event *event __maybe_unused, 47 union perf_event *event __maybe_unused,
@@ -27,12 +50,25 @@ static inline int machine__process_bpf_event(struct machine *machine __maybe_unu
27 return 0; 50 return 0;
28} 51}
29 52
30static inline int perf_event__synthesize_bpf_events(struct perf_tool *tool __maybe_unused, 53static inline int perf_event__synthesize_bpf_events(struct perf_session *session __maybe_unused,
31 perf_event__handler_t process __maybe_unused, 54 perf_event__handler_t process __maybe_unused,
32 struct machine *machine __maybe_unused, 55 struct machine *machine __maybe_unused,
33 struct record_opts *opts __maybe_unused) 56 struct record_opts *opts __maybe_unused)
34{ 57{
35 return 0; 58 return 0;
36} 59}
60
61static inline int bpf_event__add_sb_event(struct perf_evlist **evlist __maybe_unused,
62 struct perf_env *env __maybe_unused)
63{
64 return 0;
65}
66
67static inline void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info __maybe_unused,
68 struct perf_env *env __maybe_unused,
69 FILE *fp __maybe_unused)
70{
71
72}
37#endif // HAVE_LIBBPF_SUPPORT 73#endif // HAVE_LIBBPF_SUPPORT
38#endif 74#endif
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index bff0d17920ed..0c5517a8d0b7 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -185,6 +185,7 @@ char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size)
185 return bf; 185 return bf;
186} 186}
187 187
188/* The caller is responsible to free the returned buffer. */
188char *build_id_cache__origname(const char *sbuild_id) 189char *build_id_cache__origname(const char *sbuild_id)
189{ 190{
190 char *linkname; 191 char *linkname;
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index fa092511c52b..7e3c1b60120c 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -633,11 +633,10 @@ static int collect_config(const char *var, const char *value,
633 } 633 }
634 634
635 ret = set_value(item, value); 635 ret = set_value(item, value);
636 return ret;
637 636
638out_free: 637out_free:
639 free(key); 638 free(key);
640 return -1; 639 return ret;
641} 640}
642 641
643int perf_config_set__collect(struct perf_config_set *set, const char *file_name, 642int perf_config_set__collect(struct perf_config_set *set, const char *file_name,
diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
index ba4c623cd8de..39fe21e1cf93 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -387,6 +387,7 @@ cs_etm_decoder__buffer_range(struct cs_etm_decoder *decoder,
387 break; 387 break;
388 case OCSD_INSTR_ISB: 388 case OCSD_INSTR_ISB:
389 case OCSD_INSTR_DSB_DMB: 389 case OCSD_INSTR_DSB_DMB:
390 case OCSD_INSTR_WFI_WFE:
390 case OCSD_INSTR_OTHER: 391 case OCSD_INSTR_OTHER:
391 default: 392 default:
392 packet->last_instr_taken_branch = false; 393 packet->last_instr_taken_branch = false;
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index e098e189f93e..6a64f713710d 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -14,6 +14,7 @@
14#include "data.h" 14#include "data.h"
15#include "util.h" 15#include "util.h"
16#include "debug.h" 16#include "debug.h"
17#include "header.h"
17 18
18static void close_dir(struct perf_data_file *files, int nr) 19static void close_dir(struct perf_data_file *files, int nr)
19{ 20{
@@ -34,12 +35,16 @@ int perf_data__create_dir(struct perf_data *data, int nr)
34 struct perf_data_file *files = NULL; 35 struct perf_data_file *files = NULL;
35 int i, ret = -1; 36 int i, ret = -1;
36 37
38 if (WARN_ON(!data->is_dir))
39 return -EINVAL;
40
37 files = zalloc(nr * sizeof(*files)); 41 files = zalloc(nr * sizeof(*files));
38 if (!files) 42 if (!files)
39 return -ENOMEM; 43 return -ENOMEM;
40 44
41 data->dir.files = files; 45 data->dir.version = PERF_DIR_VERSION;
42 data->dir.nr = nr; 46 data->dir.files = files;
47 data->dir.nr = nr;
43 48
44 for (i = 0; i < nr; i++) { 49 for (i = 0; i < nr; i++) {
45 struct perf_data_file *file = &files[i]; 50 struct perf_data_file *file = &files[i];
@@ -69,6 +74,13 @@ int perf_data__open_dir(struct perf_data *data)
69 DIR *dir; 74 DIR *dir;
70 int nr = 0; 75 int nr = 0;
71 76
77 if (WARN_ON(!data->is_dir))
78 return -EINVAL;
79
80 /* The version is provided by DIR_FORMAT feature. */
81 if (WARN_ON(data->dir.version != PERF_DIR_VERSION))
82 return -1;
83
72 dir = opendir(data->path); 84 dir = opendir(data->path);
73 if (!dir) 85 if (!dir)
74 return -EINVAL; 86 return -EINVAL;
@@ -118,6 +130,26 @@ out_err:
118 return ret; 130 return ret;
119} 131}
120 132
133int perf_data__update_dir(struct perf_data *data)
134{
135 int i;
136
137 if (WARN_ON(!data->is_dir))
138 return -EINVAL;
139
140 for (i = 0; i < data->dir.nr; i++) {
141 struct perf_data_file *file = &data->dir.files[i];
142 struct stat st;
143
144 if (fstat(file->fd, &st))
145 return -1;
146
147 file->size = st.st_size;
148 }
149
150 return 0;
151}
152
121static bool check_pipe(struct perf_data *data) 153static bool check_pipe(struct perf_data *data)
122{ 154{
123 struct stat st; 155 struct stat st;
@@ -173,6 +205,16 @@ static int check_backup(struct perf_data *data)
173 return 0; 205 return 0;
174} 206}
175 207
208static bool is_dir(struct perf_data *data)
209{
210 struct stat st;
211
212 if (stat(data->path, &st))
213 return false;
214
215 return (st.st_mode & S_IFMT) == S_IFDIR;
216}
217
176static int open_file_read(struct perf_data *data) 218static int open_file_read(struct perf_data *data)
177{ 219{
178 struct stat st; 220 struct stat st;
@@ -254,6 +296,30 @@ static int open_file_dup(struct perf_data *data)
254 return open_file(data); 296 return open_file(data);
255} 297}
256 298
299static int open_dir(struct perf_data *data)
300{
301 int ret;
302
303 /*
304 * So far we open only the header, so we can read the data version and
305 * layout.
306 */
307 if (asprintf(&data->file.path, "%s/header", data->path) < 0)
308 return -1;
309
310 if (perf_data__is_write(data) &&
311 mkdir(data->path, S_IRWXU) < 0)
312 return -1;
313
314 ret = open_file(data);
315
316 /* Cleanup whatever we managed to create so far. */
317 if (ret && perf_data__is_write(data))
318 rm_rf_perf_data(data->path);
319
320 return ret;
321}
322
257int perf_data__open(struct perf_data *data) 323int perf_data__open(struct perf_data *data)
258{ 324{
259 if (check_pipe(data)) 325 if (check_pipe(data))
@@ -265,11 +331,18 @@ int perf_data__open(struct perf_data *data)
265 if (check_backup(data)) 331 if (check_backup(data))
266 return -1; 332 return -1;
267 333
268 return open_file_dup(data); 334 if (perf_data__is_read(data))
335 data->is_dir = is_dir(data);
336
337 return perf_data__is_dir(data) ?
338 open_dir(data) : open_file_dup(data);
269} 339}
270 340
271void perf_data__close(struct perf_data *data) 341void perf_data__close(struct perf_data *data)
272{ 342{
343 if (perf_data__is_dir(data))
344 perf_data__close_dir(data);
345
273 zfree(&data->file.path); 346 zfree(&data->file.path);
274 close(data->file.fd); 347 close(data->file.fd);
275} 348}
@@ -288,9 +361,9 @@ ssize_t perf_data__write(struct perf_data *data,
288 361
289int perf_data__switch(struct perf_data *data, 362int perf_data__switch(struct perf_data *data,
290 const char *postfix, 363 const char *postfix,
291 size_t pos, bool at_exit) 364 size_t pos, bool at_exit,
365 char **new_filepath)
292{ 366{
293 char *new_filepath;
294 int ret; 367 int ret;
295 368
296 if (check_pipe(data)) 369 if (check_pipe(data))
@@ -298,15 +371,15 @@ int perf_data__switch(struct perf_data *data,
298 if (perf_data__is_read(data)) 371 if (perf_data__is_read(data))
299 return -EINVAL; 372 return -EINVAL;
300 373
301 if (asprintf(&new_filepath, "%s.%s", data->path, postfix) < 0) 374 if (asprintf(new_filepath, "%s.%s", data->path, postfix) < 0)
302 return -ENOMEM; 375 return -ENOMEM;
303 376
304 /* 377 /*
305 * Only fire a warning, don't return error, continue fill 378 * Only fire a warning, don't return error, continue fill
306 * original file. 379 * original file.
307 */ 380 */
308 if (rename(data->path, new_filepath)) 381 if (rename(data->path, *new_filepath))
309 pr_warning("Failed to rename %s to %s\n", data->path, new_filepath); 382 pr_warning("Failed to rename %s to %s\n", data->path, *new_filepath);
310 383
311 if (!at_exit) { 384 if (!at_exit) {
312 close(data->file.fd); 385 close(data->file.fd);
@@ -323,6 +396,22 @@ int perf_data__switch(struct perf_data *data,
323 } 396 }
324 ret = data->file.fd; 397 ret = data->file.fd;
325out: 398out:
326 free(new_filepath);
327 return ret; 399 return ret;
328} 400}
401
402unsigned long perf_data__size(struct perf_data *data)
403{
404 u64 size = data->file.size;
405 int i;
406
407 if (!data->is_dir)
408 return size;
409
410 for (i = 0; i < data->dir.nr; i++) {
411 struct perf_data_file *file = &data->dir.files[i];
412
413 size += file->size;
414 }
415
416 return size;
417}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 14b47be2bd69..259868a39019 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -19,10 +19,12 @@ struct perf_data {
19 const char *path; 19 const char *path;
20 struct perf_data_file file; 20 struct perf_data_file file;
21 bool is_pipe; 21 bool is_pipe;
22 bool is_dir;
22 bool force; 23 bool force;
23 enum perf_data_mode mode; 24 enum perf_data_mode mode;
24 25
25 struct { 26 struct {
27 u64 version;
26 struct perf_data_file *files; 28 struct perf_data_file *files;
27 int nr; 29 int nr;
28 } dir; 30 } dir;
@@ -43,14 +45,14 @@ static inline int perf_data__is_pipe(struct perf_data *data)
43 return data->is_pipe; 45 return data->is_pipe;
44} 46}
45 47
46static inline int perf_data__fd(struct perf_data *data) 48static inline bool perf_data__is_dir(struct perf_data *data)
47{ 49{
48 return data->file.fd; 50 return data->is_dir;
49} 51}
50 52
51static inline unsigned long perf_data__size(struct perf_data *data) 53static inline int perf_data__fd(struct perf_data *data)
52{ 54{
53 return data->file.size; 55 return data->file.fd;
54} 56}
55 57
56int perf_data__open(struct perf_data *data); 58int perf_data__open(struct perf_data *data);
@@ -68,9 +70,11 @@ ssize_t perf_data_file__write(struct perf_data_file *file,
68 */ 70 */
69int perf_data__switch(struct perf_data *data, 71int perf_data__switch(struct perf_data *data,
70 const char *postfix, 72 const char *postfix,
71 size_t pos, bool at_exit); 73 size_t pos, bool at_exit, char **new_filepath);
72 74
73int perf_data__create_dir(struct perf_data *data, int nr); 75int perf_data__create_dir(struct perf_data *data, int nr);
74int perf_data__open_dir(struct perf_data *data); 76int perf_data__open_dir(struct perf_data *data);
75void perf_data__close_dir(struct perf_data *data); 77void perf_data__close_dir(struct perf_data *data);
78int perf_data__update_dir(struct perf_data *data);
79unsigned long perf_data__size(struct perf_data *data);
76#endif /* __PERF_DATA_H */ 80#endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index ba58ba603b69..e059976d9d93 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -184,6 +184,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
184 case DSO_BINARY_TYPE__KALLSYMS: 184 case DSO_BINARY_TYPE__KALLSYMS:
185 case DSO_BINARY_TYPE__GUEST_KALLSYMS: 185 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
186 case DSO_BINARY_TYPE__JAVA_JIT: 186 case DSO_BINARY_TYPE__JAVA_JIT:
187 case DSO_BINARY_TYPE__BPF_PROG_INFO:
187 case DSO_BINARY_TYPE__NOT_FOUND: 188 case DSO_BINARY_TYPE__NOT_FOUND:
188 ret = -1; 189 ret = -1;
189 break; 190 break;
@@ -1141,28 +1142,34 @@ void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
1141 1142
1142static void dso__set_basename(struct dso *dso) 1143static void dso__set_basename(struct dso *dso)
1143{ 1144{
1144 /* 1145 char *base, *lname;
1145 * basename() may modify path buffer, so we must pass 1146 int tid;
1146 * a copy.
1147 */
1148 char *base, *lname = strdup(dso->long_name);
1149 1147
1150 if (!lname) 1148 if (sscanf(dso->long_name, "/tmp/perf-%d.map", &tid) == 1) {
1151 return; 1149 if (asprintf(&base, "[JIT] tid %d", tid) < 0)
1152 1150 return;
1153 /* 1151 } else {
1154 * basename() may return a pointer to internal 1152 /*
1155 * storage which is reused in subsequent calls 1153 * basename() may modify path buffer, so we must pass
1156 * so copy the result. 1154 * a copy.
1157 */ 1155 */
1158 base = strdup(basename(lname)); 1156 lname = strdup(dso->long_name);
1157 if (!lname)
1158 return;
1159 1159
1160 free(lname); 1160 /*
1161 * basename() may return a pointer to internal
1162 * storage which is reused in subsequent calls
1163 * so copy the result.
1164 */
1165 base = strdup(basename(lname));
1161 1166
1162 if (!base) 1167 free(lname);
1163 return;
1164 1168
1165 dso__set_short_name(dso, base, true); 1169 if (!base)
1170 return;
1171 }
1172 dso__set_short_name(dso, base, true);
1166} 1173}
1167 1174
1168int dso__name_len(const struct dso *dso) 1175int dso__name_len(const struct dso *dso)
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index bb417c54c25a..6e3f63781e51 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -14,6 +14,7 @@
14 14
15struct machine; 15struct machine;
16struct map; 16struct map;
17struct perf_env;
17 18
18enum dso_binary_type { 19enum dso_binary_type {
19 DSO_BINARY_TYPE__KALLSYMS = 0, 20 DSO_BINARY_TYPE__KALLSYMS = 0,
@@ -35,6 +36,7 @@ enum dso_binary_type {
35 DSO_BINARY_TYPE__KCORE, 36 DSO_BINARY_TYPE__KCORE,
36 DSO_BINARY_TYPE__GUEST_KCORE, 37 DSO_BINARY_TYPE__GUEST_KCORE,
37 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 38 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
39 DSO_BINARY_TYPE__BPF_PROG_INFO,
38 DSO_BINARY_TYPE__NOT_FOUND, 40 DSO_BINARY_TYPE__NOT_FOUND,
39}; 41};
40 42
@@ -189,6 +191,12 @@ struct dso {
189 u64 debug_frame_offset; 191 u64 debug_frame_offset;
190 u64 eh_frame_hdr_offset; 192 u64 eh_frame_hdr_offset;
191 } data; 193 } data;
194 /* bpf prog information */
195 struct {
196 u32 id;
197 u32 sub_id;
198 struct perf_env *env;
199 } bpf_prog;
192 200
193 union { /* Tool specific area */ 201 union { /* Tool specific area */
194 void *priv; 202 void *priv;
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 4c23779e271a..c6351b557bb0 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -3,15 +3,163 @@
3#include "env.h" 3#include "env.h"
4#include "sane_ctype.h" 4#include "sane_ctype.h"
5#include "util.h" 5#include "util.h"
6#include "bpf-event.h"
6#include <errno.h> 7#include <errno.h>
7#include <sys/utsname.h> 8#include <sys/utsname.h>
9#include <bpf/libbpf.h>
8 10
9struct perf_env perf_env; 11struct perf_env perf_env;
10 12
13void perf_env__insert_bpf_prog_info(struct perf_env *env,
14 struct bpf_prog_info_node *info_node)
15{
16 __u32 prog_id = info_node->info_linear->info.id;
17 struct bpf_prog_info_node *node;
18 struct rb_node *parent = NULL;
19 struct rb_node **p;
20
21 down_write(&env->bpf_progs.lock);
22 p = &env->bpf_progs.infos.rb_node;
23
24 while (*p != NULL) {
25 parent = *p;
26 node = rb_entry(parent, struct bpf_prog_info_node, rb_node);
27 if (prog_id < node->info_linear->info.id) {
28 p = &(*p)->rb_left;
29 } else if (prog_id > node->info_linear->info.id) {
30 p = &(*p)->rb_right;
31 } else {
32 pr_debug("duplicated bpf prog info %u\n", prog_id);
33 goto out;
34 }
35 }
36
37 rb_link_node(&info_node->rb_node, parent, p);
38 rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);
39 env->bpf_progs.infos_cnt++;
40out:
41 up_write(&env->bpf_progs.lock);
42}
43
44struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
45 __u32 prog_id)
46{
47 struct bpf_prog_info_node *node = NULL;
48 struct rb_node *n;
49
50 down_read(&env->bpf_progs.lock);
51 n = env->bpf_progs.infos.rb_node;
52
53 while (n) {
54 node = rb_entry(n, struct bpf_prog_info_node, rb_node);
55 if (prog_id < node->info_linear->info.id)
56 n = n->rb_left;
57 else if (prog_id > node->info_linear->info.id)
58 n = n->rb_right;
59 else
60 break;
61 }
62
63 up_read(&env->bpf_progs.lock);
64 return node;
65}
66
67void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
68{
69 struct rb_node *parent = NULL;
70 __u32 btf_id = btf_node->id;
71 struct btf_node *node;
72 struct rb_node **p;
73
74 down_write(&env->bpf_progs.lock);
75 p = &env->bpf_progs.btfs.rb_node;
76
77 while (*p != NULL) {
78 parent = *p;
79 node = rb_entry(parent, struct btf_node, rb_node);
80 if (btf_id < node->id) {
81 p = &(*p)->rb_left;
82 } else if (btf_id > node->id) {
83 p = &(*p)->rb_right;
84 } else {
85 pr_debug("duplicated btf %u\n", btf_id);
86 goto out;
87 }
88 }
89
90 rb_link_node(&btf_node->rb_node, parent, p);
91 rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);
92 env->bpf_progs.btfs_cnt++;
93out:
94 up_write(&env->bpf_progs.lock);
95}
96
97struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)
98{
99 struct btf_node *node = NULL;
100 struct rb_node *n;
101
102 down_read(&env->bpf_progs.lock);
103 n = env->bpf_progs.btfs.rb_node;
104
105 while (n) {
106 node = rb_entry(n, struct btf_node, rb_node);
107 if (btf_id < node->id)
108 n = n->rb_left;
109 else if (btf_id > node->id)
110 n = n->rb_right;
111 else
112 break;
113 }
114
115 up_read(&env->bpf_progs.lock);
116 return node;
117}
118
119/* purge data in bpf_progs.infos tree */
120static void perf_env__purge_bpf(struct perf_env *env)
121{
122 struct rb_root *root;
123 struct rb_node *next;
124
125 down_write(&env->bpf_progs.lock);
126
127 root = &env->bpf_progs.infos;
128 next = rb_first(root);
129
130 while (next) {
131 struct bpf_prog_info_node *node;
132
133 node = rb_entry(next, struct bpf_prog_info_node, rb_node);
134 next = rb_next(&node->rb_node);
135 rb_erase(&node->rb_node, root);
136 free(node);
137 }
138
139 env->bpf_progs.infos_cnt = 0;
140
141 root = &env->bpf_progs.btfs;
142 next = rb_first(root);
143
144 while (next) {
145 struct btf_node *node;
146
147 node = rb_entry(next, struct btf_node, rb_node);
148 next = rb_next(&node->rb_node);
149 rb_erase(&node->rb_node, root);
150 free(node);
151 }
152
153 env->bpf_progs.btfs_cnt = 0;
154
155 up_write(&env->bpf_progs.lock);
156}
157
11void perf_env__exit(struct perf_env *env) 158void perf_env__exit(struct perf_env *env)
12{ 159{
13 int i; 160 int i;
14 161
162 perf_env__purge_bpf(env);
15 zfree(&env->hostname); 163 zfree(&env->hostname);
16 zfree(&env->os_release); 164 zfree(&env->os_release);
17 zfree(&env->version); 165 zfree(&env->version);
@@ -38,6 +186,13 @@ void perf_env__exit(struct perf_env *env)
38 zfree(&env->memory_nodes); 186 zfree(&env->memory_nodes);
39} 187}
40 188
189void perf_env__init(struct perf_env *env)
190{
191 env->bpf_progs.infos = RB_ROOT;
192 env->bpf_progs.btfs = RB_ROOT;
193 init_rwsem(&env->bpf_progs.lock);
194}
195
41int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) 196int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
42{ 197{
43 int i; 198 int i;
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index d01b8355f4ca..4f8e2b485c01 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -3,7 +3,9 @@
3#define __PERF_ENV_H 3#define __PERF_ENV_H
4 4
5#include <linux/types.h> 5#include <linux/types.h>
6#include <linux/rbtree.h>
6#include "cpumap.h" 7#include "cpumap.h"
8#include "rwsem.h"
7 9
8struct cpu_topology_map { 10struct cpu_topology_map {
9 int socket_id; 11 int socket_id;
@@ -64,8 +66,23 @@ struct perf_env {
64 struct memory_node *memory_nodes; 66 struct memory_node *memory_nodes;
65 unsigned long long memory_bsize; 67 unsigned long long memory_bsize;
66 u64 clockid_res_ns; 68 u64 clockid_res_ns;
69
70 /*
71 * bpf_info_lock protects bpf rbtrees. This is needed because the
72 * trees are accessed by different threads in perf-top
73 */
74 struct {
75 struct rw_semaphore lock;
76 struct rb_root infos;
77 u32 infos_cnt;
78 struct rb_root btfs;
79 u32 btfs_cnt;
80 } bpf_progs;
67}; 81};
68 82
83struct bpf_prog_info_node;
84struct btf_node;
85
69extern struct perf_env perf_env; 86extern struct perf_env perf_env;
70 87
71void perf_env__exit(struct perf_env *env); 88void perf_env__exit(struct perf_env *env);
@@ -80,4 +97,11 @@ const char *perf_env__arch(struct perf_env *env);
80const char *perf_env__raw_arch(struct perf_env *env); 97const char *perf_env__raw_arch(struct perf_env *env);
81int perf_env__nr_cpus_avail(struct perf_env *env); 98int perf_env__nr_cpus_avail(struct perf_env *env);
82 99
100void perf_env__init(struct perf_env *env);
101void perf_env__insert_bpf_prog_info(struct perf_env *env,
102 struct bpf_prog_info_node *info_node);
103struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
104 __u32 prog_id);
105void perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node);
106struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id);
83#endif /* __PERF_ENV_H */ 107#endif /* __PERF_ENV_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index ed20f4379956..6689378ee577 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -19,6 +19,7 @@
19#include "debug.h" 19#include "debug.h"
20#include "units.h" 20#include "units.h"
21#include "asm/bug.h" 21#include "asm/bug.h"
22#include "bpf-event.h"
22#include <signal.h> 23#include <signal.h>
23#include <unistd.h> 24#include <unistd.h>
24 25
@@ -230,35 +231,6 @@ void perf_evlist__set_leader(struct perf_evlist *evlist)
230 } 231 }
231} 232}
232 233
233void perf_event_attr__set_max_precise_ip(struct perf_event_attr *pattr)
234{
235 struct perf_event_attr attr = {
236 .type = PERF_TYPE_HARDWARE,
237 .config = PERF_COUNT_HW_CPU_CYCLES,
238 .exclude_kernel = 1,
239 .precise_ip = 3,
240 };
241
242 event_attr_init(&attr);
243
244 /*
245 * Unnamed union member, not supported as struct member named
246 * initializer in older compilers such as gcc 4.4.7
247 */
248 attr.sample_period = 1;
249
250 while (attr.precise_ip != 0) {
251 int fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
252 if (fd != -1) {
253 close(fd);
254 break;
255 }
256 --attr.precise_ip;
257 }
258
259 pattr->precise_ip = attr.precise_ip;
260}
261
262int __perf_evlist__add_default(struct perf_evlist *evlist, bool precise) 234int __perf_evlist__add_default(struct perf_evlist *evlist, bool precise)
263{ 235{
264 struct perf_evsel *evsel = perf_evsel__new_cycles(precise); 236 struct perf_evsel *evsel = perf_evsel__new_cycles(precise);
@@ -1856,3 +1828,121 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
1856 } 1828 }
1857 return leader; 1829 return leader;
1858} 1830}
1831
1832int perf_evlist__add_sb_event(struct perf_evlist **evlist,
1833 struct perf_event_attr *attr,
1834 perf_evsel__sb_cb_t cb,
1835 void *data)
1836{
1837 struct perf_evsel *evsel;
1838 bool new_evlist = (*evlist) == NULL;
1839
1840 if (*evlist == NULL)
1841 *evlist = perf_evlist__new();
1842 if (*evlist == NULL)
1843 return -1;
1844
1845 if (!attr->sample_id_all) {
1846 pr_warning("enabling sample_id_all for all side band events\n");
1847 attr->sample_id_all = 1;
1848 }
1849
1850 evsel = perf_evsel__new_idx(attr, (*evlist)->nr_entries);
1851 if (!evsel)
1852 goto out_err;
1853
1854 evsel->side_band.cb = cb;
1855 evsel->side_band.data = data;
1856 perf_evlist__add(*evlist, evsel);
1857 return 0;
1858
1859out_err:
1860 if (new_evlist) {
1861 perf_evlist__delete(*evlist);
1862 *evlist = NULL;
1863 }
1864 return -1;
1865}
1866
1867static void *perf_evlist__poll_thread(void *arg)
1868{
1869 struct perf_evlist *evlist = arg;
1870 bool draining = false;
1871 int i;
1872
1873 while (draining || !(evlist->thread.done)) {
1874 if (draining)
1875 draining = false;
1876 else if (evlist->thread.done)
1877 draining = true;
1878
1879 if (!draining)
1880 perf_evlist__poll(evlist, 1000);
1881
1882 for (i = 0; i < evlist->nr_mmaps; i++) {
1883 struct perf_mmap *map = &evlist->mmap[i];
1884 union perf_event *event;
1885
1886 if (perf_mmap__read_init(map))
1887 continue;
1888 while ((event = perf_mmap__read_event(map)) != NULL) {
1889 struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event);
1890
1891 if (evsel && evsel->side_band.cb)
1892 evsel->side_band.cb(event, evsel->side_band.data);
1893 else
1894 pr_warning("cannot locate proper evsel for the side band event\n");
1895
1896 perf_mmap__consume(map);
1897 }
1898 perf_mmap__read_done(map);
1899 }
1900 }
1901 return NULL;
1902}
1903
1904int perf_evlist__start_sb_thread(struct perf_evlist *evlist,
1905 struct target *target)
1906{
1907 struct perf_evsel *counter;
1908
1909 if (!evlist)
1910 return 0;
1911
1912 if (perf_evlist__create_maps(evlist, target))
1913 goto out_delete_evlist;
1914
1915 evlist__for_each_entry(evlist, counter) {
1916 if (perf_evsel__open(counter, evlist->cpus,
1917 evlist->threads) < 0)
1918 goto out_delete_evlist;
1919 }
1920
1921 if (perf_evlist__mmap(evlist, UINT_MAX))
1922 goto out_delete_evlist;
1923
1924 evlist__for_each_entry(evlist, counter) {
1925 if (perf_evsel__enable(counter))
1926 goto out_delete_evlist;
1927 }
1928
1929 evlist->thread.done = 0;
1930 if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
1931 goto out_delete_evlist;
1932
1933 return 0;
1934
1935out_delete_evlist:
1936 perf_evlist__delete(evlist);
1937 evlist = NULL;
1938 return -1;
1939}
1940
1941void perf_evlist__stop_sb_thread(struct perf_evlist *evlist)
1942{
1943 if (!evlist)
1944 return;
1945 evlist->thread.done = 1;
1946 pthread_join(evlist->thread.th, NULL);
1947 perf_evlist__delete(evlist);
1948}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 744906dd4887..6a94785b9100 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -54,6 +54,10 @@ struct perf_evlist {
54 struct perf_sample *sample); 54 struct perf_sample *sample);
55 u64 first_sample_time; 55 u64 first_sample_time;
56 u64 last_sample_time; 56 u64 last_sample_time;
57 struct {
58 pthread_t th;
59 volatile int done;
60 } thread;
57}; 61};
58 62
59struct perf_evsel_str_handler { 63struct perf_evsel_str_handler {
@@ -87,6 +91,14 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
87 91
88int perf_evlist__add_dummy(struct perf_evlist *evlist); 92int perf_evlist__add_dummy(struct perf_evlist *evlist);
89 93
94int perf_evlist__add_sb_event(struct perf_evlist **evlist,
95 struct perf_event_attr *attr,
96 perf_evsel__sb_cb_t cb,
97 void *data);
98int perf_evlist__start_sb_thread(struct perf_evlist *evlist,
99 struct target *target);
100void perf_evlist__stop_sb_thread(struct perf_evlist *evlist);
101
90int perf_evlist__add_newtp(struct perf_evlist *evlist, 102int perf_evlist__add_newtp(struct perf_evlist *evlist,
91 const char *sys, const char *name, void *handler); 103 const char *sys, const char *name, void *handler);
92 104
@@ -303,8 +315,6 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
303void perf_evlist__set_tracking_event(struct perf_evlist *evlist, 315void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
304 struct perf_evsel *tracking_evsel); 316 struct perf_evsel *tracking_evsel);
305 317
306void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr);
307
308struct perf_evsel * 318struct perf_evsel *
309perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, const char *str); 319perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, const char *str);
310 320
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 3bbf73e979c0..66d066f18b5b 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -295,7 +295,6 @@ struct perf_evsel *perf_evsel__new_cycles(bool precise)
295 if (!precise) 295 if (!precise)
296 goto new_event; 296 goto new_event;
297 297
298 perf_event_attr__set_max_precise_ip(&attr);
299 /* 298 /*
300 * Now let the usual logic to set up the perf_event_attr defaults 299 * Now let the usual logic to set up the perf_event_attr defaults
301 * to kick in when we return and before perf_evsel__open() is called. 300 * to kick in when we return and before perf_evsel__open() is called.
@@ -305,6 +304,8 @@ new_event:
305 if (evsel == NULL) 304 if (evsel == NULL)
306 goto out; 305 goto out;
307 306
307 evsel->precise_max = true;
308
308 /* use asprintf() because free(evsel) assumes name is allocated */ 309 /* use asprintf() because free(evsel) assumes name is allocated */
309 if (asprintf(&evsel->name, "cycles%s%s%.*s", 310 if (asprintf(&evsel->name, "cycles%s%s%.*s",
310 (attr.precise_ip || attr.exclude_kernel) ? ":" : "", 311 (attr.precise_ip || attr.exclude_kernel) ? ":" : "",
@@ -1036,7 +1037,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
1036 attr->mmap2 = track && !perf_missing_features.mmap2; 1037 attr->mmap2 = track && !perf_missing_features.mmap2;
1037 attr->comm = track; 1038 attr->comm = track;
1038 attr->ksymbol = track && !perf_missing_features.ksymbol; 1039 attr->ksymbol = track && !perf_missing_features.ksymbol;
1039 attr->bpf_event = track && opts->bpf_event && 1040 attr->bpf_event = track && !opts->no_bpf_event &&
1040 !perf_missing_features.bpf_event; 1041 !perf_missing_features.bpf_event;
1041 1042
1042 if (opts->record_namespaces) 1043 if (opts->record_namespaces)
@@ -1083,7 +1084,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
1083 } 1084 }
1084 1085
1085 if (evsel->precise_max) 1086 if (evsel->precise_max)
1086 perf_event_attr__set_max_precise_ip(attr); 1087 attr->precise_ip = 3;
1087 1088
1088 if (opts->all_user) { 1089 if (opts->all_user) {
1089 attr->exclude_kernel = 1; 1090 attr->exclude_kernel = 1;
@@ -1292,6 +1293,7 @@ void perf_evsel__exit(struct perf_evsel *evsel)
1292{ 1293{
1293 assert(list_empty(&evsel->node)); 1294 assert(list_empty(&evsel->node));
1294 assert(evsel->evlist == NULL); 1295 assert(evsel->evlist == NULL);
1296 perf_evsel__free_counts(evsel);
1295 perf_evsel__free_fd(evsel); 1297 perf_evsel__free_fd(evsel);
1296 perf_evsel__free_id(evsel); 1298 perf_evsel__free_id(evsel);
1297 perf_evsel__free_config_terms(evsel); 1299 perf_evsel__free_config_terms(evsel);
@@ -1342,10 +1344,9 @@ void perf_counts_values__scale(struct perf_counts_values *count,
1342 count->val = 0; 1344 count->val = 0;
1343 } else if (count->run < count->ena) { 1345 } else if (count->run < count->ena) {
1344 scaled = 1; 1346 scaled = 1;
1345 count->val = (u64)((double) count->val * count->ena / count->run + 0.5); 1347 count->val = (u64)((double) count->val * count->ena / count->run);
1346 } 1348 }
1347 } else 1349 }
1348 count->ena = count->run = 0;
1349 1350
1350 if (pscaled) 1351 if (pscaled)
1351 *pscaled = scaled; 1352 *pscaled = scaled;
@@ -1749,6 +1750,59 @@ static bool ignore_missing_thread(struct perf_evsel *evsel,
1749 return true; 1750 return true;
1750} 1751}
1751 1752
1753static void display_attr(struct perf_event_attr *attr)
1754{
1755 if (verbose >= 2) {
1756 fprintf(stderr, "%.60s\n", graph_dotted_line);
1757 fprintf(stderr, "perf_event_attr:\n");
1758 perf_event_attr__fprintf(stderr, attr, __open_attr__fprintf, NULL);
1759 fprintf(stderr, "%.60s\n", graph_dotted_line);
1760 }
1761}
1762
1763static int perf_event_open(struct perf_evsel *evsel,
1764 pid_t pid, int cpu, int group_fd,
1765 unsigned long flags)
1766{
1767 int precise_ip = evsel->attr.precise_ip;
1768 int fd;
1769
1770 while (1) {
1771 pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx",
1772 pid, cpu, group_fd, flags);
1773
1774 fd = sys_perf_event_open(&evsel->attr, pid, cpu, group_fd, flags);
1775 if (fd >= 0)
1776 break;
1777
1778 /*
1779 * Do quick precise_ip fallback if:
1780 * - there is precise_ip set in perf_event_attr
1781 * - maximum precise is requested
1782 * - sys_perf_event_open failed with ENOTSUP error,
1783 * which is associated with wrong precise_ip
1784 */
1785 if (!precise_ip || !evsel->precise_max || (errno != ENOTSUP))
1786 break;
1787
1788 /*
1789 * We tried all the precise_ip values, and it's
1790 * still failing, so leave it to standard fallback.
1791 */
1792 if (!evsel->attr.precise_ip) {
1793 evsel->attr.precise_ip = precise_ip;
1794 break;
1795 }
1796
1797 pr_debug2("\nsys_perf_event_open failed, error %d\n", -ENOTSUP);
1798 evsel->attr.precise_ip--;
1799 pr_debug2("decreasing precise_ip by one (%d)\n", evsel->attr.precise_ip);
1800 display_attr(&evsel->attr);
1801 }
1802
1803 return fd;
1804}
1805
1752int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 1806int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
1753 struct thread_map *threads) 1807 struct thread_map *threads)
1754{ 1808{
@@ -1824,12 +1878,7 @@ retry_sample_id:
1824 if (perf_missing_features.sample_id_all) 1878 if (perf_missing_features.sample_id_all)
1825 evsel->attr.sample_id_all = 0; 1879 evsel->attr.sample_id_all = 0;
1826 1880
1827 if (verbose >= 2) { 1881 display_attr(&evsel->attr);
1828 fprintf(stderr, "%.60s\n", graph_dotted_line);
1829 fprintf(stderr, "perf_event_attr:\n");
1830 perf_event_attr__fprintf(stderr, &evsel->attr, __open_attr__fprintf, NULL);
1831 fprintf(stderr, "%.60s\n", graph_dotted_line);
1832 }
1833 1882
1834 for (cpu = 0; cpu < cpus->nr; cpu++) { 1883 for (cpu = 0; cpu < cpus->nr; cpu++) {
1835 1884
@@ -1841,13 +1890,10 @@ retry_sample_id:
1841 1890
1842 group_fd = get_group_fd(evsel, cpu, thread); 1891 group_fd = get_group_fd(evsel, cpu, thread);
1843retry_open: 1892retry_open:
1844 pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx",
1845 pid, cpus->map[cpu], group_fd, flags);
1846
1847 test_attr__ready(); 1893 test_attr__ready();
1848 1894
1849 fd = sys_perf_event_open(&evsel->attr, pid, cpus->map[cpu], 1895 fd = perf_event_open(evsel, pid, cpus->map[cpu],
1850 group_fd, flags); 1896 group_fd, flags);
1851 1897
1852 FD(evsel, cpu, thread) = fd; 1898 FD(evsel, cpu, thread) = fd;
1853 1899
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index cc578e02e08f..0f2c6c93d721 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -73,6 +73,8 @@ struct perf_evsel_config_term {
73 73
74struct perf_stat_evsel; 74struct perf_stat_evsel;
75 75
76typedef int (perf_evsel__sb_cb_t)(union perf_event *event, void *data);
77
76/** struct perf_evsel - event selector 78/** struct perf_evsel - event selector
77 * 79 *
78 * @evlist - evlist this evsel is in, if it is in one. 80 * @evlist - evlist this evsel is in, if it is in one.
@@ -151,6 +153,10 @@ struct perf_evsel {
151 bool collect_stat; 153 bool collect_stat;
152 bool weak_group; 154 bool weak_group;
153 const char *pmu_name; 155 const char *pmu_name;
156 struct {
157 perf_evsel__sb_cb_t *cb;
158 void *data;
159 } side_band;
154}; 160};
155 161
156union u64_swap { 162union u64_swap {
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 01b324c275b9..b9e693825873 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -18,6 +18,7 @@
18#include <sys/utsname.h> 18#include <sys/utsname.h>
19#include <linux/time64.h> 19#include <linux/time64.h>
20#include <dirent.h> 20#include <dirent.h>
21#include <bpf/libbpf.h>
21 22
22#include "evlist.h" 23#include "evlist.h"
23#include "evsel.h" 24#include "evsel.h"
@@ -40,6 +41,7 @@
40#include "time-utils.h" 41#include "time-utils.h"
41#include "units.h" 42#include "units.h"
42#include "cputopo.h" 43#include "cputopo.h"
44#include "bpf-event.h"
43 45
44#include "sane_ctype.h" 46#include "sane_ctype.h"
45 47
@@ -861,6 +863,104 @@ static int write_clockid(struct feat_fd *ff,
861 sizeof(ff->ph->env.clockid_res_ns)); 863 sizeof(ff->ph->env.clockid_res_ns));
862} 864}
863 865
866static int write_dir_format(struct feat_fd *ff,
867 struct perf_evlist *evlist __maybe_unused)
868{
869 struct perf_session *session;
870 struct perf_data *data;
871
872 session = container_of(ff->ph, struct perf_session, header);
873 data = session->data;
874
875 if (WARN_ON(!perf_data__is_dir(data)))
876 return -1;
877
878 return do_write(ff, &data->dir.version, sizeof(data->dir.version));
879}
880
881#ifdef HAVE_LIBBPF_SUPPORT
882static int write_bpf_prog_info(struct feat_fd *ff,
883 struct perf_evlist *evlist __maybe_unused)
884{
885 struct perf_env *env = &ff->ph->env;
886 struct rb_root *root;
887 struct rb_node *next;
888 int ret;
889
890 down_read(&env->bpf_progs.lock);
891
892 ret = do_write(ff, &env->bpf_progs.infos_cnt,
893 sizeof(env->bpf_progs.infos_cnt));
894 if (ret < 0)
895 goto out;
896
897 root = &env->bpf_progs.infos;
898 next = rb_first(root);
899 while (next) {
900 struct bpf_prog_info_node *node;
901 size_t len;
902
903 node = rb_entry(next, struct bpf_prog_info_node, rb_node);
904 next = rb_next(&node->rb_node);
905 len = sizeof(struct bpf_prog_info_linear) +
906 node->info_linear->data_len;
907
908 /* before writing to file, translate address to offset */
909 bpf_program__bpil_addr_to_offs(node->info_linear);
910 ret = do_write(ff, node->info_linear, len);
911 /*
912 * translate back to address even when do_write() fails,
913 * so that this function never changes the data.
914 */
915 bpf_program__bpil_offs_to_addr(node->info_linear);
916 if (ret < 0)
917 goto out;
918 }
919out:
920 up_read(&env->bpf_progs.lock);
921 return ret;
922}
923#else // HAVE_LIBBPF_SUPPORT
924static int write_bpf_prog_info(struct feat_fd *ff __maybe_unused,
925 struct perf_evlist *evlist __maybe_unused)
926{
927 return 0;
928}
929#endif // HAVE_LIBBPF_SUPPORT
930
931static int write_bpf_btf(struct feat_fd *ff,
932 struct perf_evlist *evlist __maybe_unused)
933{
934 struct perf_env *env = &ff->ph->env;
935 struct rb_root *root;
936 struct rb_node *next;
937 int ret;
938
939 down_read(&env->bpf_progs.lock);
940
941 ret = do_write(ff, &env->bpf_progs.btfs_cnt,
942 sizeof(env->bpf_progs.btfs_cnt));
943
944 if (ret < 0)
945 goto out;
946
947 root = &env->bpf_progs.btfs;
948 next = rb_first(root);
949 while (next) {
950 struct btf_node *node;
951
952 node = rb_entry(next, struct btf_node, rb_node);
953 next = rb_next(&node->rb_node);
954 ret = do_write(ff, &node->id,
955 sizeof(u32) * 2 + node->data_size);
956 if (ret < 0)
957 goto out;
958 }
959out:
960 up_read(&env->bpf_progs.lock);
961 return ret;
962}
963
864static int cpu_cache_level__sort(const void *a, const void *b) 964static int cpu_cache_level__sort(const void *a, const void *b)
865{ 965{
866 struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a; 966 struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
@@ -1341,6 +1441,63 @@ static void print_clockid(struct feat_fd *ff, FILE *fp)
1341 ff->ph->env.clockid_res_ns * 1000); 1441 ff->ph->env.clockid_res_ns * 1000);
1342} 1442}
1343 1443
1444static void print_dir_format(struct feat_fd *ff, FILE *fp)
1445{
1446 struct perf_session *session;
1447 struct perf_data *data;
1448
1449 session = container_of(ff->ph, struct perf_session, header);
1450 data = session->data;
1451
1452 fprintf(fp, "# directory data version : %"PRIu64"\n", data->dir.version);
1453}
1454
1455static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
1456{
1457 struct perf_env *env = &ff->ph->env;
1458 struct rb_root *root;
1459 struct rb_node *next;
1460
1461 down_read(&env->bpf_progs.lock);
1462
1463 root = &env->bpf_progs.infos;
1464 next = rb_first(root);
1465
1466 while (next) {
1467 struct bpf_prog_info_node *node;
1468
1469 node = rb_entry(next, struct bpf_prog_info_node, rb_node);
1470 next = rb_next(&node->rb_node);
1471
1472 bpf_event__print_bpf_prog_info(&node->info_linear->info,
1473 env, fp);
1474 }
1475
1476 up_read(&env->bpf_progs.lock);
1477}
1478
1479static void print_bpf_btf(struct feat_fd *ff, FILE *fp)
1480{
1481 struct perf_env *env = &ff->ph->env;
1482 struct rb_root *root;
1483 struct rb_node *next;
1484
1485 down_read(&env->bpf_progs.lock);
1486
1487 root = &env->bpf_progs.btfs;
1488 next = rb_first(root);
1489
1490 while (next) {
1491 struct btf_node *node;
1492
1493 node = rb_entry(next, struct btf_node, rb_node);
1494 next = rb_next(&node->rb_node);
1495 fprintf(fp, "# btf info of id %u\n", node->id);
1496 }
1497
1498 up_read(&env->bpf_progs.lock);
1499}
1500
1344static void free_event_desc(struct perf_evsel *events) 1501static void free_event_desc(struct perf_evsel *events)
1345{ 1502{
1346 struct perf_evsel *evsel; 1503 struct perf_evsel *evsel;
@@ -2373,6 +2530,139 @@ static int process_clockid(struct feat_fd *ff,
2373 return 0; 2530 return 0;
2374} 2531}
2375 2532
2533static int process_dir_format(struct feat_fd *ff,
2534 void *_data __maybe_unused)
2535{
2536 struct perf_session *session;
2537 struct perf_data *data;
2538
2539 session = container_of(ff->ph, struct perf_session, header);
2540 data = session->data;
2541
2542 if (WARN_ON(!perf_data__is_dir(data)))
2543 return -1;
2544
2545 return do_read_u64(ff, &data->dir.version);
2546}
2547
2548#ifdef HAVE_LIBBPF_SUPPORT
2549static int process_bpf_prog_info(struct feat_fd *ff, void *data __maybe_unused)
2550{
2551 struct bpf_prog_info_linear *info_linear;
2552 struct bpf_prog_info_node *info_node;
2553 struct perf_env *env = &ff->ph->env;
2554 u32 count, i;
2555 int err = -1;
2556
2557 if (ff->ph->needs_swap) {
2558 pr_warning("interpreting bpf_prog_info from systems with endianity is not yet supported\n");
2559 return 0;
2560 }
2561
2562 if (do_read_u32(ff, &count))
2563 return -1;
2564
2565 down_write(&env->bpf_progs.lock);
2566
2567 for (i = 0; i < count; ++i) {
2568 u32 info_len, data_len;
2569
2570 info_linear = NULL;
2571 info_node = NULL;
2572 if (do_read_u32(ff, &info_len))
2573 goto out;
2574 if (do_read_u32(ff, &data_len))
2575 goto out;
2576
2577 if (info_len > sizeof(struct bpf_prog_info)) {
2578 pr_warning("detected invalid bpf_prog_info\n");
2579 goto out;
2580 }
2581
2582 info_linear = malloc(sizeof(struct bpf_prog_info_linear) +
2583 data_len);
2584 if (!info_linear)
2585 goto out;
2586 info_linear->info_len = sizeof(struct bpf_prog_info);
2587 info_linear->data_len = data_len;
2588 if (do_read_u64(ff, (u64 *)(&info_linear->arrays)))
2589 goto out;
2590 if (__do_read(ff, &info_linear->info, info_len))
2591 goto out;
2592 if (info_len < sizeof(struct bpf_prog_info))
2593 memset(((void *)(&info_linear->info)) + info_len, 0,
2594 sizeof(struct bpf_prog_info) - info_len);
2595
2596 if (__do_read(ff, info_linear->data, data_len))
2597 goto out;
2598
2599 info_node = malloc(sizeof(struct bpf_prog_info_node));
2600 if (!info_node)
2601 goto out;
2602
2603 /* after reading from file, translate offset to address */
2604 bpf_program__bpil_offs_to_addr(info_linear);
2605 info_node->info_linear = info_linear;
2606 perf_env__insert_bpf_prog_info(env, info_node);
2607 }
2608
2609 return 0;
2610out:
2611 free(info_linear);
2612 free(info_node);
2613 up_write(&env->bpf_progs.lock);
2614 return err;
2615}
2616#else // HAVE_LIBBPF_SUPPORT
2617static int process_bpf_prog_info(struct feat_fd *ff __maybe_unused, void *data __maybe_unused)
2618{
2619 return 0;
2620}
2621#endif // HAVE_LIBBPF_SUPPORT
2622
2623static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused)
2624{
2625 struct perf_env *env = &ff->ph->env;
2626 u32 count, i;
2627
2628 if (ff->ph->needs_swap) {
2629 pr_warning("interpreting btf from systems with endianity is not yet supported\n");
2630 return 0;
2631 }
2632
2633 if (do_read_u32(ff, &count))
2634 return -1;
2635
2636 down_write(&env->bpf_progs.lock);
2637
2638 for (i = 0; i < count; ++i) {
2639 struct btf_node *node;
2640 u32 id, data_size;
2641
2642 if (do_read_u32(ff, &id))
2643 return -1;
2644 if (do_read_u32(ff, &data_size))
2645 return -1;
2646
2647 node = malloc(sizeof(struct btf_node) + data_size);
2648 if (!node)
2649 return -1;
2650
2651 node->id = id;
2652 node->data_size = data_size;
2653
2654 if (__do_read(ff, node->data, data_size)) {
2655 free(node);
2656 return -1;
2657 }
2658
2659 perf_env__insert_btf(env, node);
2660 }
2661
2662 up_write(&env->bpf_progs.lock);
2663 return 0;
2664}
2665
2376struct feature_ops { 2666struct feature_ops {
2377 int (*write)(struct feat_fd *ff, struct perf_evlist *evlist); 2667 int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
2378 void (*print)(struct feat_fd *ff, FILE *fp); 2668 void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2432,7 +2722,10 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
2432 FEAT_OPN(CACHE, cache, true), 2722 FEAT_OPN(CACHE, cache, true),
2433 FEAT_OPR(SAMPLE_TIME, sample_time, false), 2723 FEAT_OPR(SAMPLE_TIME, sample_time, false),
2434 FEAT_OPR(MEM_TOPOLOGY, mem_topology, true), 2724 FEAT_OPR(MEM_TOPOLOGY, mem_topology, true),
2435 FEAT_OPR(CLOCKID, clockid, false) 2725 FEAT_OPR(CLOCKID, clockid, false),
2726 FEAT_OPN(DIR_FORMAT, dir_format, false),
2727 FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false),
2728 FEAT_OPR(BPF_BTF, bpf_btf, false),
2436}; 2729};
2437 2730
2438struct header_print_data { 2731struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 0d553ddca0a3..386da49e1bfa 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -39,6 +39,9 @@ enum {
39 HEADER_SAMPLE_TIME, 39 HEADER_SAMPLE_TIME,
40 HEADER_MEM_TOPOLOGY, 40 HEADER_MEM_TOPOLOGY,
41 HEADER_CLOCKID, 41 HEADER_CLOCKID,
42 HEADER_DIR_FORMAT,
43 HEADER_BPF_PROG_INFO,
44 HEADER_BPF_BTF,
42 HEADER_LAST_FEATURE, 45 HEADER_LAST_FEATURE,
43 HEADER_FEAT_BITS = 256, 46 HEADER_FEAT_BITS = 256,
44}; 47};
@@ -48,6 +51,10 @@ enum perf_header_version {
48 PERF_HEADER_VERSION_2, 51 PERF_HEADER_VERSION_2,
49}; 52};
50 53
54enum perf_dir_version {
55 PERF_DIR_VERSION = 1,
56};
57
51struct perf_file_section { 58struct perf_file_section {
52 u64 offset; 59 u64 offset;
53 u64 size; 60 u64 size;
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index f9eb95bf3938..7ace7a10054d 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -19,6 +19,7 @@
19#include <math.h> 19#include <math.h>
20#include <inttypes.h> 20#include <inttypes.h>
21#include <sys/param.h> 21#include <sys/param.h>
22#include <linux/time64.h>
22 23
23static bool hists__filter_entry_by_dso(struct hists *hists, 24static bool hists__filter_entry_by_dso(struct hists *hists,
24 struct hist_entry *he); 25 struct hist_entry *he);
@@ -192,6 +193,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
192 hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3); 193 hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3);
193 hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); 194 hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
194 hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); 195 hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
196 hists__new_col_len(hists, HISTC_TIME, 12);
195 197
196 if (h->srcline) { 198 if (h->srcline) {
197 len = MAX(strlen(h->srcline), strlen(sort_srcline.se_header)); 199 len = MAX(strlen(h->srcline), strlen(sort_srcline.se_header));
@@ -246,6 +248,14 @@ static void he_stat__add_cpumode_period(struct he_stat *he_stat,
246 } 248 }
247} 249}
248 250
251static long hist_time(unsigned long htime)
252{
253 unsigned long time_quantum = symbol_conf.time_quantum;
254 if (time_quantum)
255 return (htime / time_quantum) * time_quantum;
256 return htime;
257}
258
249static void he_stat__add_period(struct he_stat *he_stat, u64 period, 259static void he_stat__add_period(struct he_stat *he_stat, u64 period,
250 u64 weight) 260 u64 weight)
251{ 261{
@@ -426,6 +436,13 @@ static int hist_entry__init(struct hist_entry *he,
426 goto err_rawdata; 436 goto err_rawdata;
427 } 437 }
428 438
439 if (symbol_conf.res_sample) {
440 he->res_samples = calloc(sizeof(struct res_sample),
441 symbol_conf.res_sample);
442 if (!he->res_samples)
443 goto err_srcline;
444 }
445
429 INIT_LIST_HEAD(&he->pairs.node); 446 INIT_LIST_HEAD(&he->pairs.node);
430 thread__get(he->thread); 447 thread__get(he->thread);
431 he->hroot_in = RB_ROOT_CACHED; 448 he->hroot_in = RB_ROOT_CACHED;
@@ -436,6 +453,9 @@ static int hist_entry__init(struct hist_entry *he,
436 453
437 return 0; 454 return 0;
438 455
456err_srcline:
457 free(he->srcline);
458
439err_rawdata: 459err_rawdata:
440 free(he->raw_data); 460 free(he->raw_data);
441 461
@@ -593,6 +613,32 @@ out:
593 return he; 613 return he;
594} 614}
595 615
616static unsigned random_max(unsigned high)
617{
618 unsigned thresh = -high % high;
619 for (;;) {
620 unsigned r = random();
621 if (r >= thresh)
622 return r % high;
623 }
624}
625
626static void hists__res_sample(struct hist_entry *he, struct perf_sample *sample)
627{
628 struct res_sample *r;
629 int j;
630
631 if (he->num_res < symbol_conf.res_sample) {
632 j = he->num_res++;
633 } else {
634 j = random_max(symbol_conf.res_sample);
635 }
636 r = &he->res_samples[j];
637 r->time = sample->time;
638 r->cpu = sample->cpu;
639 r->tid = sample->tid;
640}
641
596static struct hist_entry* 642static struct hist_entry*
597__hists__add_entry(struct hists *hists, 643__hists__add_entry(struct hists *hists,
598 struct addr_location *al, 644 struct addr_location *al,
@@ -635,10 +681,13 @@ __hists__add_entry(struct hists *hists,
635 .raw_data = sample->raw_data, 681 .raw_data = sample->raw_data,
636 .raw_size = sample->raw_size, 682 .raw_size = sample->raw_size,
637 .ops = ops, 683 .ops = ops,
684 .time = hist_time(sample->time),
638 }, *he = hists__findnew_entry(hists, &entry, al, sample_self); 685 }, *he = hists__findnew_entry(hists, &entry, al, sample_self);
639 686
640 if (!hists->has_callchains && he && he->callchain_size != 0) 687 if (!hists->has_callchains && he && he->callchain_size != 0)
641 hists->has_callchains = true; 688 hists->has_callchains = true;
689 if (he && symbol_conf.res_sample)
690 hists__res_sample(he, sample);
642 return he; 691 return he;
643} 692}
644 693
@@ -1062,8 +1111,10 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
1062 1111
1063 err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent, 1112 err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent,
1064 iter->evsel, al, max_stack_depth); 1113 iter->evsel, al, max_stack_depth);
1065 if (err) 1114 if (err) {
1115 map__put(alm);
1066 return err; 1116 return err;
1117 }
1067 1118
1068 err = iter->ops->prepare_entry(iter, al); 1119 err = iter->ops->prepare_entry(iter, al);
1069 if (err) 1120 if (err)
@@ -1162,6 +1213,7 @@ void hist_entry__delete(struct hist_entry *he)
1162 mem_info__zput(he->mem_info); 1213 mem_info__zput(he->mem_info);
1163 } 1214 }
1164 1215
1216 zfree(&he->res_samples);
1165 zfree(&he->stat_acc); 1217 zfree(&he->stat_acc);
1166 free_srcline(he->srcline); 1218 free_srcline(he->srcline);
1167 if (he->srcfile && he->srcfile[0]) 1219 if (he->srcfile && he->srcfile[0])
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 4af27fbab24f..76ff6c6d03b8 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -31,6 +31,7 @@ enum hist_filter {
31 31
32enum hist_column { 32enum hist_column {
33 HISTC_SYMBOL, 33 HISTC_SYMBOL,
34 HISTC_TIME,
34 HISTC_DSO, 35 HISTC_DSO,
35 HISTC_THREAD, 36 HISTC_THREAD,
36 HISTC_COMM, 37 HISTC_COMM,
@@ -432,9 +433,18 @@ struct hist_browser_timer {
432}; 433};
433 434
434struct annotation_options; 435struct annotation_options;
436struct res_sample;
437
438enum rstype {
439 A_NORMAL,
440 A_ASM,
441 A_SOURCE
442};
435 443
436#ifdef HAVE_SLANG_SUPPORT 444#ifdef HAVE_SLANG_SUPPORT
437#include "../ui/keysyms.h" 445#include "../ui/keysyms.h"
446void attr_to_script(char *buf, struct perf_event_attr *attr);
447
438int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, 448int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
439 struct hist_browser_timer *hbt, 449 struct hist_browser_timer *hbt,
440 struct annotation_options *annotation_opts); 450 struct annotation_options *annotation_opts);
@@ -449,7 +459,13 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
449 struct perf_env *env, 459 struct perf_env *env,
450 bool warn_lost_event, 460 bool warn_lost_event,
451 struct annotation_options *annotation_options); 461 struct annotation_options *annotation_options);
452int script_browse(const char *script_opt); 462
463int script_browse(const char *script_opt, struct perf_evsel *evsel);
464
465void run_script(char *cmd);
466int res_sample_browse(struct res_sample *res_samples, int num_res,
467 struct perf_evsel *evsel, enum rstype rstype);
468void res_sample_init(void);
453#else 469#else
454static inline 470static inline
455int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, 471int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
@@ -478,11 +494,22 @@ static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused,
478 return 0; 494 return 0;
479} 495}
480 496
481static inline int script_browse(const char *script_opt __maybe_unused) 497static inline int script_browse(const char *script_opt __maybe_unused,
498 struct perf_evsel *evsel __maybe_unused)
482{ 499{
483 return 0; 500 return 0;
484} 501}
485 502
503static inline int res_sample_browse(struct res_sample *res_samples __maybe_unused,
504 int num_res __maybe_unused,
505 struct perf_evsel *evsel __maybe_unused,
506 enum rstype rstype __maybe_unused)
507{
508 return 0;
509}
510
511static inline void res_sample_init(void) {}
512
486#define K_LEFT -1000 513#define K_LEFT -1000
487#define K_RIGHT -2000 514#define K_RIGHT -2000
488#define K_SWITCH_INPUT_DATA -3000 515#define K_SWITCH_INPUT_DATA -3000
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
index 6e03db142091..872fab163585 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -251,19 +251,15 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params)
251 if (!(decoder->tsc_ctc_ratio_n % decoder->tsc_ctc_ratio_d)) 251 if (!(decoder->tsc_ctc_ratio_n % decoder->tsc_ctc_ratio_d))
252 decoder->tsc_ctc_mult = decoder->tsc_ctc_ratio_n / 252 decoder->tsc_ctc_mult = decoder->tsc_ctc_ratio_n /
253 decoder->tsc_ctc_ratio_d; 253 decoder->tsc_ctc_ratio_d;
254
255 /*
256 * Allow for timestamps appearing to backwards because a TSC
257 * packet has slipped past a MTC packet, so allow 2 MTC ticks
258 * or ...
259 */
260 decoder->tsc_slip = multdiv(2 << decoder->mtc_shift,
261 decoder->tsc_ctc_ratio_n,
262 decoder->tsc_ctc_ratio_d);
263 } 254 }
264 /* ... or 0x100 paranoia */ 255
265 if (decoder->tsc_slip < 0x100) 256 /*
266 decoder->tsc_slip = 0x100; 257 * A TSC packet can slip past MTC packets so that the timestamp appears
258 * to go backwards. One estimate is that can be up to about 40 CPU
259 * cycles, which is certainly less than 0x1000 TSC ticks, but accept
260 * slippage an order of magnitude more to be on the safe side.
261 */
262 decoder->tsc_slip = 0x10000;
267 263
268 intel_pt_log("timestamp: mtc_shift %u\n", decoder->mtc_shift); 264 intel_pt_log("timestamp: mtc_shift %u\n", decoder->mtc_shift);
269 intel_pt_log("timestamp: tsc_ctc_ratio_n %u\n", decoder->tsc_ctc_ratio_n); 265 intel_pt_log("timestamp: tsc_ctc_ratio_n %u\n", decoder->tsc_ctc_ratio_n);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 61959aba7e27..3c520baa198c 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1421,6 +1421,20 @@ static void machine__set_kernel_mmap(struct machine *machine,
1421 machine->vmlinux_map->end = ~0ULL; 1421 machine->vmlinux_map->end = ~0ULL;
1422} 1422}
1423 1423
1424static void machine__update_kernel_mmap(struct machine *machine,
1425 u64 start, u64 end)
1426{
1427 struct map *map = machine__kernel_map(machine);
1428
1429 map__get(map);
1430 map_groups__remove(&machine->kmaps, map);
1431
1432 machine__set_kernel_mmap(machine, start, end);
1433
1434 map_groups__insert(&machine->kmaps, map);
1435 map__put(map);
1436}
1437
1424int machine__create_kernel_maps(struct machine *machine) 1438int machine__create_kernel_maps(struct machine *machine)
1425{ 1439{
1426 struct dso *kernel = machine__get_kernel(machine); 1440 struct dso *kernel = machine__get_kernel(machine);
@@ -1453,17 +1467,11 @@ int machine__create_kernel_maps(struct machine *machine)
1453 goto out_put; 1467 goto out_put;
1454 } 1468 }
1455 1469
1456 /* we have a real start address now, so re-order the kmaps */ 1470 /*
1457 map = machine__kernel_map(machine); 1471 * we have a real start address now, so re-order the kmaps
1458 1472 * assume it's the last in the kmaps
1459 map__get(map); 1473 */
1460 map_groups__remove(&machine->kmaps, map); 1474 machine__update_kernel_mmap(machine, addr, ~0ULL);
1461
1462 /* assume it's the last in the kmaps */
1463 machine__set_kernel_mmap(machine, addr, ~0ULL);
1464
1465 map_groups__insert(&machine->kmaps, map);
1466 map__put(map);
1467 } 1475 }
1468 1476
1469 if (machine__create_extra_kernel_maps(machine, kernel)) 1477 if (machine__create_extra_kernel_maps(machine, kernel))
@@ -1599,7 +1607,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
1599 if (strstr(kernel->long_name, "vmlinux")) 1607 if (strstr(kernel->long_name, "vmlinux"))
1600 dso__set_short_name(kernel, "[kernel.vmlinux]", false); 1608 dso__set_short_name(kernel, "[kernel.vmlinux]", false);
1601 1609
1602 machine__set_kernel_mmap(machine, event->mmap.start, 1610 machine__update_kernel_mmap(machine, event->mmap.start,
1603 event->mmap.start + event->mmap.len); 1611 event->mmap.start + event->mmap.len);
1604 1612
1605 /* 1613 /*
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index fbeb0c6efaa6..e32628cd20a7 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -577,10 +577,25 @@ static void __maps__purge(struct maps *maps)
577 } 577 }
578} 578}
579 579
580static void __maps__purge_names(struct maps *maps)
581{
582 struct rb_root *root = &maps->names;
583 struct rb_node *next = rb_first(root);
584
585 while (next) {
586 struct map *pos = rb_entry(next, struct map, rb_node_name);
587
588 next = rb_next(&pos->rb_node_name);
589 rb_erase_init(&pos->rb_node_name, root);
590 map__put(pos);
591 }
592}
593
580static void maps__exit(struct maps *maps) 594static void maps__exit(struct maps *maps)
581{ 595{
582 down_write(&maps->lock); 596 down_write(&maps->lock);
583 __maps__purge(maps); 597 __maps__purge(maps);
598 __maps__purge_names(maps);
584 up_write(&maps->lock); 599 up_write(&maps->lock);
585} 600}
586 601
@@ -917,6 +932,9 @@ static void __maps__remove(struct maps *maps, struct map *map)
917{ 932{
918 rb_erase_init(&map->rb_node, &maps->entries); 933 rb_erase_init(&map->rb_node, &maps->entries);
919 map__put(map); 934 map__put(map);
935
936 rb_erase_init(&map->rb_node_name, &maps->names);
937 map__put(map);
920} 938}
921 939
922void maps__remove(struct maps *maps, struct map *map) 940void maps__remove(struct maps *maps, struct map *map)
diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c
index ea523d3b248f..989fed6f43b5 100644
--- a/tools/perf/util/ordered-events.c
+++ b/tools/perf/util/ordered-events.c
@@ -270,6 +270,8 @@ static int __ordered_events__flush(struct ordered_events *oe, enum oe_flush how,
270 "FINAL", 270 "FINAL",
271 "ROUND", 271 "ROUND",
272 "HALF ", 272 "HALF ",
273 "TOP ",
274 "TIME ",
273 }; 275 };
274 int err; 276 int err;
275 bool show_progress = false; 277 bool show_progress = false;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 4dcc01b2532c..5ef4939408f2 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -2271,6 +2271,7 @@ static bool is_event_supported(u8 type, unsigned config)
2271 perf_evsel__delete(evsel); 2271 perf_evsel__delete(evsel);
2272 } 2272 }
2273 2273
2274 thread_map__put(tmap);
2274 return ret; 2275 return ret;
2275} 2276}
2276 2277
@@ -2341,6 +2342,7 @@ void print_sdt_events(const char *subsys_glob, const char *event_glob,
2341 printf(" %-50s [%s]\n", buf, "SDT event"); 2342 printf(" %-50s [%s]\n", buf, "SDT event");
2342 free(buf); 2343 free(buf);
2343 } 2344 }
2345 free(path);
2344 } else 2346 } else
2345 printf(" %-50s [%s]\n", nd->s, "SDT event"); 2347 printf(" %-50s [%s]\n", nd->s, "SDT event");
2346 if (nd2) { 2348 if (nd2) {
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 6199a3174ab9..e0429f4ef335 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -732,10 +732,20 @@ static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
732 732
733 if (!is_arm_pmu_core(name)) { 733 if (!is_arm_pmu_core(name)) {
734 pname = pe->pmu ? pe->pmu : "cpu"; 734 pname = pe->pmu ? pe->pmu : "cpu";
735
736 /*
737 * uncore alias may be from different PMU
738 * with common prefix
739 */
740 if (pmu_is_uncore(name) &&
741 !strncmp(pname, name, strlen(pname)))
742 goto new_alias;
743
735 if (strcmp(pname, name)) 744 if (strcmp(pname, name))
736 continue; 745 continue;
737 } 746 }
738 747
748new_alias:
739 /* need type casts to override 'const' */ 749 /* need type casts to override 'const' */
740 __perf_pmu__new_alias(head, NULL, (char *)pe->name, 750 __perf_pmu__new_alias(head, NULL, (char *)pe->name,
741 (char *)pe->desc, (char *)pe->event, 751 (char *)pe->desc, (char *)pe->event,
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index a1b8d9649ca7..198e09ff611e 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -160,8 +160,10 @@ static struct map *kernel_get_module_map(const char *module)
160 if (module && strchr(module, '/')) 160 if (module && strchr(module, '/'))
161 return dso__new_map(module); 161 return dso__new_map(module);
162 162
163 if (!module) 163 if (!module) {
164 module = "kernel"; 164 pos = machine__kernel_map(host_machine);
165 return map__get(pos);
166 }
165 167
166 for (pos = maps__first(maps); pos; pos = map__next(pos)) { 168 for (pos = maps__first(maps); pos; pos = map__next(pos)) {
167 /* short_name is "[module]" */ 169 /* short_name is "[module]" */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index db643f3c2b95..b17f1c9bc965 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -132,6 +132,7 @@ struct perf_session *perf_session__new(struct perf_data *data,
132 ordered_events__init(&session->ordered_events, 132 ordered_events__init(&session->ordered_events,
133 ordered_events__deliver_event, NULL); 133 ordered_events__deliver_event, NULL);
134 134
135 perf_env__init(&session->header.env);
135 if (data) { 136 if (data) {
136 if (perf_data__open(data)) 137 if (perf_data__open(data))
137 goto out_delete; 138 goto out_delete;
@@ -152,6 +153,10 @@ struct perf_session *perf_session__new(struct perf_data *data,
152 } 153 }
153 154
154 perf_evlist__init_trace_event_sample_raw(session->evlist); 155 perf_evlist__init_trace_event_sample_raw(session->evlist);
156
157 /* Open the directory data. */
158 if (data->is_dir && perf_data__open_dir(data))
159 goto out_delete;
155 } 160 }
156 } else { 161 } else {
157 session->machines.host.env = &perf_env; 162 session->machines.host.env = &perf_env;
@@ -1843,10 +1848,17 @@ fetch_mmaped_event(struct perf_session *session,
1843#define NUM_MMAPS 128 1848#define NUM_MMAPS 128
1844#endif 1849#endif
1845 1850
1851struct reader;
1852
1853typedef s64 (*reader_cb_t)(struct perf_session *session,
1854 union perf_event *event,
1855 u64 file_offset);
1856
1846struct reader { 1857struct reader {
1847 int fd; 1858 int fd;
1848 u64 data_size; 1859 u64 data_size;
1849 u64 data_offset; 1860 u64 data_offset;
1861 reader_cb_t process;
1850}; 1862};
1851 1863
1852static int 1864static int
@@ -1917,7 +1929,7 @@ more:
1917 size = event->header.size; 1929 size = event->header.size;
1918 1930
1919 if (size < sizeof(struct perf_event_header) || 1931 if (size < sizeof(struct perf_event_header) ||
1920 (skip = perf_session__process_event(session, event, file_pos)) < 0) { 1932 (skip = rd->process(session, event, file_pos)) < 0) {
1921 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", 1933 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1922 file_offset + head, event->header.size, 1934 file_offset + head, event->header.size,
1923 event->header.type); 1935 event->header.type);
@@ -1943,12 +1955,20 @@ out:
1943 return err; 1955 return err;
1944} 1956}
1945 1957
1958static s64 process_simple(struct perf_session *session,
1959 union perf_event *event,
1960 u64 file_offset)
1961{
1962 return perf_session__process_event(session, event, file_offset);
1963}
1964
1946static int __perf_session__process_events(struct perf_session *session) 1965static int __perf_session__process_events(struct perf_session *session)
1947{ 1966{
1948 struct reader rd = { 1967 struct reader rd = {
1949 .fd = perf_data__fd(session->data), 1968 .fd = perf_data__fd(session->data),
1950 .data_size = session->header.data_size, 1969 .data_size = session->header.data_size,
1951 .data_offset = session->header.data_offset, 1970 .data_offset = session->header.data_offset,
1971 .process = process_simple,
1952 }; 1972 };
1953 struct ordered_events *oe = &session->ordered_events; 1973 struct ordered_events *oe = &session->ordered_events;
1954 struct perf_tool *tool = session->tool; 1974 struct perf_tool *tool = session->tool;
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index d2299e912e59..5d2518e89fc4 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -3,6 +3,7 @@
3#include <inttypes.h> 3#include <inttypes.h>
4#include <regex.h> 4#include <regex.h>
5#include <linux/mman.h> 5#include <linux/mman.h>
6#include <linux/time64.h>
6#include "sort.h" 7#include "sort.h"
7#include "hist.h" 8#include "hist.h"
8#include "comm.h" 9#include "comm.h"
@@ -12,9 +13,11 @@
12#include "evsel.h" 13#include "evsel.h"
13#include "evlist.h" 14#include "evlist.h"
14#include "strlist.h" 15#include "strlist.h"
16#include "strbuf.h"
15#include <traceevent/event-parse.h> 17#include <traceevent/event-parse.h>
16#include "mem-events.h" 18#include "mem-events.h"
17#include "annotate.h" 19#include "annotate.h"
20#include "time-utils.h"
18#include <linux/kernel.h> 21#include <linux/kernel.h>
19 22
20regex_t parent_regex; 23regex_t parent_regex;
@@ -654,6 +657,42 @@ struct sort_entry sort_socket = {
654 .se_width_idx = HISTC_SOCKET, 657 .se_width_idx = HISTC_SOCKET,
655}; 658};
656 659
660/* --sort time */
661
662static int64_t
663sort__time_cmp(struct hist_entry *left, struct hist_entry *right)
664{
665 return right->time - left->time;
666}
667
668static int hist_entry__time_snprintf(struct hist_entry *he, char *bf,
669 size_t size, unsigned int width)
670{
671 unsigned long secs;
672 unsigned long long nsecs;
673 char he_time[32];
674
675 nsecs = he->time;
676 secs = nsecs / NSEC_PER_SEC;
677 nsecs -= secs * NSEC_PER_SEC;
678
679 if (symbol_conf.nanosecs)
680 snprintf(he_time, sizeof he_time, "%5lu.%09llu: ",
681 secs, nsecs);
682 else
683 timestamp__scnprintf_usec(he->time, he_time,
684 sizeof(he_time));
685
686 return repsep_snprintf(bf, size, "%-.*s", width, he_time);
687}
688
689struct sort_entry sort_time = {
690 .se_header = "Time",
691 .se_cmp = sort__time_cmp,
692 .se_snprintf = hist_entry__time_snprintf,
693 .se_width_idx = HISTC_TIME,
694};
695
657/* --sort trace */ 696/* --sort trace */
658 697
659static char *get_trace_output(struct hist_entry *he) 698static char *get_trace_output(struct hist_entry *he)
@@ -1634,6 +1673,7 @@ static struct sort_dimension common_sort_dimensions[] = {
1634 DIM(SORT_DSO_SIZE, "dso_size", sort_dso_size), 1673 DIM(SORT_DSO_SIZE, "dso_size", sort_dso_size),
1635 DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id), 1674 DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id),
1636 DIM(SORT_SYM_IPC_NULL, "ipc_null", sort_sym_ipc_null), 1675 DIM(SORT_SYM_IPC_NULL, "ipc_null", sort_sym_ipc_null),
1676 DIM(SORT_TIME, "time", sort_time),
1637}; 1677};
1638 1678
1639#undef DIM 1679#undef DIM
@@ -3068,3 +3108,54 @@ void reset_output_field(void)
3068 reset_dimensions(); 3108 reset_dimensions();
3069 perf_hpp__reset_output_field(&perf_hpp_list); 3109 perf_hpp__reset_output_field(&perf_hpp_list);
3070} 3110}
3111
3112#define INDENT (3*8 + 1)
3113
3114static void add_key(struct strbuf *sb, const char *str, int *llen)
3115{
3116 if (*llen >= 75) {
3117 strbuf_addstr(sb, "\n\t\t\t ");
3118 *llen = INDENT;
3119 }
3120 strbuf_addf(sb, " %s", str);
3121 *llen += strlen(str) + 1;
3122}
3123
3124static void add_sort_string(struct strbuf *sb, struct sort_dimension *s, int n,
3125 int *llen)
3126{
3127 int i;
3128
3129 for (i = 0; i < n; i++)
3130 add_key(sb, s[i].name, llen);
3131}
3132
3133static void add_hpp_sort_string(struct strbuf *sb, struct hpp_dimension *s, int n,
3134 int *llen)
3135{
3136 int i;
3137
3138 for (i = 0; i < n; i++)
3139 add_key(sb, s[i].name, llen);
3140}
3141
3142const char *sort_help(const char *prefix)
3143{
3144 struct strbuf sb;
3145 char *s;
3146 int len = strlen(prefix) + INDENT;
3147
3148 strbuf_init(&sb, 300);
3149 strbuf_addstr(&sb, prefix);
3150 add_hpp_sort_string(&sb, hpp_sort_dimensions,
3151 ARRAY_SIZE(hpp_sort_dimensions), &len);
3152 add_sort_string(&sb, common_sort_dimensions,
3153 ARRAY_SIZE(common_sort_dimensions), &len);
3154 add_sort_string(&sb, bstack_sort_dimensions,
3155 ARRAY_SIZE(bstack_sort_dimensions), &len);
3156 add_sort_string(&sb, memory_sort_dimensions,
3157 ARRAY_SIZE(memory_sort_dimensions), &len);
3158 s = strbuf_detach(&sb, NULL);
3159 strbuf_release(&sb);
3160 return s;
3161}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 2fbee0b1011c..ce376a73f964 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -47,6 +47,12 @@ extern struct sort_entry sort_srcline;
47extern enum sort_type sort__first_dimension; 47extern enum sort_type sort__first_dimension;
48extern const char default_mem_sort_order[]; 48extern const char default_mem_sort_order[];
49 49
50struct res_sample {
51 u64 time;
52 int cpu;
53 int tid;
54};
55
50struct he_stat { 56struct he_stat {
51 u64 period; 57 u64 period;
52 u64 period_sys; 58 u64 period_sys;
@@ -135,10 +141,13 @@ struct hist_entry {
135 char *srcfile; 141 char *srcfile;
136 struct symbol *parent; 142 struct symbol *parent;
137 struct branch_info *branch_info; 143 struct branch_info *branch_info;
144 long time;
138 struct hists *hists; 145 struct hists *hists;
139 struct mem_info *mem_info; 146 struct mem_info *mem_info;
140 void *raw_data; 147 void *raw_data;
141 u32 raw_size; 148 u32 raw_size;
149 int num_res;
150 struct res_sample *res_samples;
142 void *trace_output; 151 void *trace_output;
143 struct perf_hpp_list *hpp_list; 152 struct perf_hpp_list *hpp_list;
144 struct hist_entry *parent_he; 153 struct hist_entry *parent_he;
@@ -231,6 +240,7 @@ enum sort_type {
231 SORT_DSO_SIZE, 240 SORT_DSO_SIZE,
232 SORT_CGROUP_ID, 241 SORT_CGROUP_ID,
233 SORT_SYM_IPC_NULL, 242 SORT_SYM_IPC_NULL,
243 SORT_TIME,
234 244
235 /* branch stack specific sort keys */ 245 /* branch stack specific sort keys */
236 __SORT_BRANCH_STACK, 246 __SORT_BRANCH_STACK,
@@ -286,6 +296,8 @@ void reset_output_field(void);
286void sort__setup_elide(FILE *fp); 296void sort__setup_elide(FILE *fp);
287void perf_hpp__set_elide(int idx, bool elide); 297void perf_hpp__set_elide(int idx, bool elide);
288 298
299const char *sort_help(const char *prefix);
300
289int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); 301int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
290 302
291bool is_strict_order(const char *order); 303bool is_strict_order(const char *order);
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index 4d40515307b8..2856cc9d5a31 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -291,10 +291,8 @@ process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel
291 break; 291 break;
292 case AGGR_GLOBAL: 292 case AGGR_GLOBAL:
293 aggr->val += count->val; 293 aggr->val += count->val;
294 if (config->scale) { 294 aggr->ena += count->ena;
295 aggr->ena += count->ena; 295 aggr->run += count->run;
296 aggr->run += count->run;
297 }
298 case AGGR_UNSET: 296 case AGGR_UNSET:
299 default: 297 default:
300 break; 298 break;
@@ -442,10 +440,8 @@ int create_perf_stat_counter(struct perf_evsel *evsel,
442 struct perf_event_attr *attr = &evsel->attr; 440 struct perf_event_attr *attr = &evsel->attr;
443 struct perf_evsel *leader = evsel->leader; 441 struct perf_evsel *leader = evsel->leader;
444 442
445 if (config->scale) { 443 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
446 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 444 PERF_FORMAT_TOTAL_TIME_RUNNING;
447 PERF_FORMAT_TOTAL_TIME_RUNNING;
448 }
449 445
450 /* 446 /*
451 * The event is part of non trivial group, let's enable 447 * The event is part of non trivial group, let's enable
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 758bf5f74e6e..5cbad55cd99d 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -6,6 +6,7 @@
6#include <string.h> 6#include <string.h>
7#include <linux/kernel.h> 7#include <linux/kernel.h>
8#include <linux/mman.h> 8#include <linux/mman.h>
9#include <linux/time64.h>
9#include <sys/types.h> 10#include <sys/types.h>
10#include <sys/stat.h> 11#include <sys/stat.h>
11#include <sys/param.h> 12#include <sys/param.h>
@@ -39,15 +40,18 @@ int vmlinux_path__nr_entries;
39char **vmlinux_path; 40char **vmlinux_path;
40 41
41struct symbol_conf symbol_conf = { 42struct symbol_conf symbol_conf = {
43 .nanosecs = false,
42 .use_modules = true, 44 .use_modules = true,
43 .try_vmlinux_path = true, 45 .try_vmlinux_path = true,
44 .demangle = true, 46 .demangle = true,
45 .demangle_kernel = false, 47 .demangle_kernel = false,
46 .cumulate_callchain = true, 48 .cumulate_callchain = true,
49 .time_quantum = 100 * NSEC_PER_MSEC, /* 100ms */
47 .show_hist_headers = true, 50 .show_hist_headers = true,
48 .symfs = "", 51 .symfs = "",
49 .event_group = true, 52 .event_group = true,
50 .inline_name = true, 53 .inline_name = true,
54 .res_sample = 0,
51}; 55};
52 56
53static enum dso_binary_type binary_type_symtab[] = { 57static enum dso_binary_type binary_type_symtab[] = {
@@ -1451,6 +1455,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
1451 case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: 1455 case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
1452 return true; 1456 return true;
1453 1457
1458 case DSO_BINARY_TYPE__BPF_PROG_INFO:
1454 case DSO_BINARY_TYPE__NOT_FOUND: 1459 case DSO_BINARY_TYPE__NOT_FOUND:
1455 default: 1460 default:
1456 return false; 1461 return false;
diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h
index fffea68c1203..6c55fa6fccec 100644
--- a/tools/perf/util/symbol_conf.h
+++ b/tools/perf/util/symbol_conf.h
@@ -8,6 +8,7 @@ struct strlist;
8struct intlist; 8struct intlist;
9 9
10struct symbol_conf { 10struct symbol_conf {
11 bool nanosecs;
11 unsigned short priv_size; 12 unsigned short priv_size;
12 bool try_vmlinux_path, 13 bool try_vmlinux_path,
13 init_annotation, 14 init_annotation,
@@ -55,6 +56,7 @@ struct symbol_conf {
55 *sym_list_str, 56 *sym_list_str,
56 *col_width_list_str, 57 *col_width_list_str,
57 *bt_stop_list_str; 58 *bt_stop_list_str;
59 unsigned long time_quantum;
58 struct strlist *dso_list, 60 struct strlist *dso_list,
59 *comm_list, 61 *comm_list,
60 *sym_list, 62 *sym_list,
@@ -66,6 +68,7 @@ struct symbol_conf {
66 struct intlist *pid_list, 68 struct intlist *pid_list,
67 *tid_list; 69 *tid_list;
68 const char *symfs; 70 const char *symfs;
71 int res_sample;
69}; 72};
70 73
71extern struct symbol_conf symbol_conf; 74extern struct symbol_conf symbol_conf;
diff --git a/tools/perf/util/time-utils.c b/tools/perf/util/time-utils.c
index 0f53baec660e..20663a460df3 100644
--- a/tools/perf/util/time-utils.c
+++ b/tools/perf/util/time-utils.c
@@ -453,6 +453,14 @@ int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz)
453 return scnprintf(buf, sz, "%"PRIu64".%06"PRIu64, sec, usec); 453 return scnprintf(buf, sz, "%"PRIu64".%06"PRIu64, sec, usec);
454} 454}
455 455
456int timestamp__scnprintf_nsec(u64 timestamp, char *buf, size_t sz)
457{
458 u64 sec = timestamp / NSEC_PER_SEC,
459 nsec = timestamp % NSEC_PER_SEC;
460
461 return scnprintf(buf, sz, "%" PRIu64 ".%09" PRIu64, sec, nsec);
462}
463
456int fetch_current_timestamp(char *buf, size_t sz) 464int fetch_current_timestamp(char *buf, size_t sz)
457{ 465{
458 struct timeval tv; 466 struct timeval tv;
diff --git a/tools/perf/util/time-utils.h b/tools/perf/util/time-utils.h
index b923de44e36f..72a42ea1d513 100644
--- a/tools/perf/util/time-utils.h
+++ b/tools/perf/util/time-utils.h
@@ -30,6 +30,7 @@ int perf_time__parse_for_ranges(const char *str, struct perf_session *session,
30 int *range_size, int *range_num); 30 int *range_size, int *range_num);
31 31
32int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz); 32int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz);
33int timestamp__scnprintf_nsec(u64 timestamp, char *buf, size_t sz);
33 34
34int fetch_current_timestamp(char *buf, size_t sz); 35int fetch_current_timestamp(char *buf, size_t sz);
35 36