aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-06-03 16:18:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-03 16:18:00 -0400
commit3d521f9151dacab566904d1f57dcb3e7080cdd8f (patch)
tree160d15ff955541c6ca27a69c8291a0269f105bb3
parent776edb59317ada867dfcddde40b55648beeb0078 (diff)
parente450f90e8c7d0bf70519223c1b848446ae63f313 (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into next
Pull perf updates from Ingo Molnar: "The tooling changes maintained by Jiri Olsa until Arnaldo is on vacation: User visible changes: - Add -F option for specifying output fields (Namhyung Kim) - Propagate exit status of a command line workload for record command (Namhyung Kim) - Use tid for finding thread (Namhyung Kim) - Clarify the output of perf sched map plus small sched command fixes (Dongsheng Yang) - Wire up perf_regs and unwind support for ARM64 (Jean Pihet) - Factor hists statistics counts processing which in turn also fixes several bugs in TUI report command (Namhyung Kim) - Add --percentage option to control absolute/relative percentage output (Namhyung Kim) - Add --list-cmds to 'kmem', 'mem', 'lock' and 'sched', for use by completion scripts (Ramkumar Ramachandra) Development/infrastructure changes and fixes: - Android related fixes for pager and map dso resolving (Michael Lentine) - Add libdw DWARF post unwind support for ARM (Jean Pihet) - Consolidate types.h for ARM and ARM64 (Jean Pihet) - Fix possible null pointer dereference in session.c (Masanari Iida) - Cleanup, remove unused variables in map_switch_event() (Dongsheng Yang) - Remove nr_state_machine_bugs in perf latency (Dongsheng Yang) - Remove usage of trace_sched_wakeup(.success) (Peter Zijlstra) - Cleanups for perf.h header (Jiri Olsa) - Consolidate types.h and export.h within tools (Borislav Petkov) - Move u64_swap union to its single user's header, evsel.h (Borislav Petkov) - Fix for s390 to properly parse tracepoints plus test code (Alexander Yarygin) - Handle EINTR error for readn/writen (Namhyung Kim) - Add a test case for hists filtering (Namhyung Kim) - Share map_groups among threads of the same group (Arnaldo Carvalho de Melo, Jiri Olsa) - Making some code (cpu node map and report parse callchain callback) global to be usable by upcomming changes (Don Zickus) - Fix pmu object compilation error (Jiri Olsa) Kernel side changes: - intrusive uprobes fixes from Oleg Nesterov. Since the interface is admin-only, and the bug only affects user-space ("any probed jmp/call can kill the application"), we queued these fixes via the development tree, as a special exception. - more fuzzer motivated race fixes and related refactoring and robustization. - allow PMU drivers to be built as modules. (No actual module yet, because the x86 Intel uncore module wasn't ready in time for this)" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (114 commits) perf tools: Add automatic remapping of Android libraries perf tools: Add cat as fallback pager perf tests: Add a testcase for histogram output sorting perf tests: Factor out print_hists_*() perf tools: Introduce reset_output_field() perf tools: Get rid of obsolete hist_entry__sort_list perf hists: Reset width of output fields with header length perf tools: Skip elided sort entries perf top: Add --fields option to specify output fields perf report/tui: Fix a bug when --fields/sort is given perf tools: Add ->sort() member to struct sort_entry perf report: Add -F option to specify output fields perf tools: Call perf_hpp__init() before setting up GUI browsers perf tools: Consolidate management of default sort orders perf tools: Allow hpp fields to be sort keys perf ui: Get rid of callback from __hpp__fmt() perf tools: Consolidate output field handling to hpp format routines perf tools: Use hpp formats to sort final output perf tools: Support event grouping in hpp ->sort() perf tools: Use hpp formats to sort hist entries ...
-rw-r--r--arch/x86/include/asm/uprobes.h16
-rw-r--r--arch/x86/kernel/cpu/perf_event.c1
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_ds.c22
-rw-r--r--arch/x86/kernel/uprobes.c551
-rw-r--r--include/linux/perf_event.h1
-rw-r--r--include/uapi/linux/perf_event.h8
-rw-r--r--kernel/events/core.c117
-rw-r--r--kernel/events/uprobes.c31
-rw-r--r--kernel/hrtimer.c1
-rw-r--r--tools/include/linux/compiler.h2
-rw-r--r--tools/include/linux/export.h (renamed from tools/virtio/linux/export.h)5
-rw-r--r--tools/include/linux/types.h (renamed from tools/lib/lockdep/uinclude/linux/types.h)29
-rw-r--r--tools/lib/lockdep/Makefile2
-rw-r--r--tools/lib/lockdep/uinclude/linux/export.h7
-rw-r--r--tools/perf/Documentation/perf-diff.txt26
-rw-r--r--tools/perf/Documentation/perf-report.txt43
-rw-r--r--tools/perf/Documentation/perf-top.txt32
-rw-r--r--tools/perf/MANIFEST2
-rw-r--r--tools/perf/Makefile.perf12
-rw-r--r--tools/perf/arch/arm/Makefile7
-rw-r--r--tools/perf/arch/arm/include/perf_regs.h7
-rw-r--r--tools/perf/arch/arm/tests/dwarf-unwind.c60
-rw-r--r--tools/perf/arch/arm/tests/regs_load.S58
-rw-r--r--tools/perf/arch/arm/util/unwind-libdw.c36
-rw-r--r--tools/perf/arch/arm64/Makefile7
-rw-r--r--tools/perf/arch/arm64/include/perf_regs.h88
-rw-r--r--tools/perf/arch/arm64/util/dwarf-regs.c80
-rw-r--r--tools/perf/arch/arm64/util/unwind-libunwind.c82
-rw-r--r--tools/perf/arch/x86/include/perf_regs.h2
-rw-r--r--tools/perf/arch/x86/tests/dwarf-unwind.c2
-rw-r--r--tools/perf/arch/x86/util/tsc.c2
-rw-r--r--tools/perf/arch/x86/util/tsc.h2
-rw-r--r--tools/perf/builtin-annotate.c3
-rw-r--r--tools/perf/builtin-diff.c50
-rw-r--r--tools/perf/builtin-inject.c2
-rw-r--r--tools/perf/builtin-kmem.c88
-rw-r--r--tools/perf/builtin-lock.c10
-rw-r--r--tools/perf/builtin-mem.c15
-rw-r--r--tools/perf/builtin-record.c158
-rw-r--r--tools/perf/builtin-report.c196
-rw-r--r--tools/perf/builtin-sched.c80
-rw-r--r--tools/perf/builtin-top.c28
-rw-r--r--tools/perf/config/Makefile20
-rw-r--r--tools/perf/config/feature-checks/Makefile4
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-on-exit.c16
-rw-r--r--tools/perf/perf-completion.sh4
-rw-r--r--tools/perf/perf-sys.h190
-rw-r--r--tools/perf/perf.h248
-rw-r--r--tools/perf/tests/attr.c7
-rw-r--r--tools/perf/tests/builtin-test.c18
-rw-r--r--tools/perf/tests/code-reading.c5
-rw-r--r--tools/perf/tests/dso-data.c2
-rw-r--r--tools/perf/tests/dwarf-unwind.c2
-rw-r--r--tools/perf/tests/evsel-tp-sched.c3
-rw-r--r--tools/perf/tests/hists_common.c205
-rw-r--r--tools/perf/tests/hists_common.h47
-rw-r--r--tools/perf/tests/hists_filter.c290
-rw-r--r--tools/perf/tests/hists_link.c173
-rw-r--r--tools/perf/tests/hists_output.c618
-rw-r--r--tools/perf/tests/keep-tracking.c2
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c233
-rw-r--r--tools/perf/tests/parse-events.c142
-rw-r--r--tools/perf/tests/parse-no-sample-id-all.c2
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c3
-rw-r--r--tools/perf/tests/rdpmc.c2
-rw-r--r--tools/perf/tests/sample-parsing.c2
-rw-r--r--tools/perf/tests/tests.h6
-rw-r--r--tools/perf/tests/thread-mg-share.c90
-rw-r--r--tools/perf/ui/browser.h4
-rw-r--r--tools/perf/ui/browsers/hists.c233
-rw-r--r--tools/perf/ui/gtk/hists.c52
-rw-r--r--tools/perf/ui/hist.c252
-rw-r--r--tools/perf/ui/progress.h2
-rw-r--r--tools/perf/ui/setup.c2
-rw-r--r--tools/perf/ui/stdio/hist.c81
-rw-r--r--tools/perf/util/annotate.h2
-rw-r--r--tools/perf/util/build-id.c2
-rw-r--r--tools/perf/util/build-id.h2
-rw-r--r--tools/perf/util/callchain.c78
-rw-r--r--tools/perf/util/callchain.h8
-rw-r--r--tools/perf/util/config.c4
-rw-r--r--tools/perf/util/cpumap.c160
-rw-r--r--tools/perf/util/cpumap.h35
-rw-r--r--tools/perf/util/dso.h2
-rw-r--r--tools/perf/util/event.c4
-rw-r--r--tools/perf/util/event.h24
-rw-r--r--tools/perf/util/evsel.h9
-rw-r--r--tools/perf/util/header.h4
-rw-r--r--tools/perf/util/hist.c187
-rw-r--r--tools/perf/util/hist.h46
-rw-r--r--tools/perf/util/include/linux/bitmap.h3
-rw-r--r--tools/perf/util/include/linux/export.h6
-rw-r--r--tools/perf/util/include/linux/list.h1
-rw-r--r--tools/perf/util/include/linux/types.h29
-rw-r--r--tools/perf/util/machine.c11
-rw-r--r--tools/perf/util/map.c118
-rw-r--r--tools/perf/util/map.h14
-rw-r--r--tools/perf/util/pager.c12
-rw-r--r--tools/perf/util/parse-events.h3
-rw-r--r--tools/perf/util/parse-events.y14
-rw-r--r--tools/perf/util/perf_regs.h2
-rw-r--r--tools/perf/util/pmu.c6
-rw-r--r--tools/perf/util/pmu.h2
-rw-r--r--tools/perf/util/session.c5
-rw-r--r--tools/perf/util/sort.c436
-rw-r--r--tools/perf/util/sort.h6
-rw-r--r--tools/perf/util/stat.h2
-rw-r--r--tools/perf/util/svghelper.c2
-rw-r--r--tools/perf/util/svghelper.h2
-rw-r--r--tools/perf/util/symbol.h4
-rw-r--r--tools/perf/util/thread.c52
-rw-r--r--tools/perf/util/thread.h3
-rw-r--r--tools/perf/util/top.h2
-rw-r--r--tools/perf/util/types.h24
-rw-r--r--tools/perf/util/unwind-libdw.c2
-rw-r--r--tools/perf/util/unwind.h2
-rw-r--r--tools/perf/util/util.c2
-rw-r--r--tools/perf/util/util.h2
-rw-r--r--tools/perf/util/values.h2
-rw-r--r--tools/virtio/Makefile2
-rw-r--r--tools/virtio/linux/kernel.h7
-rw-r--r--tools/virtio/linux/types.h28
123 files changed, 4591 insertions, 1718 deletions
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h
index 3087ea9c5f2e..93bee7b93854 100644
--- a/arch/x86/include/asm/uprobes.h
+++ b/arch/x86/include/asm/uprobes.h
@@ -33,15 +33,27 @@ typedef u8 uprobe_opcode_t;
33#define UPROBE_SWBP_INSN 0xcc 33#define UPROBE_SWBP_INSN 0xcc
34#define UPROBE_SWBP_INSN_SIZE 1 34#define UPROBE_SWBP_INSN_SIZE 1
35 35
36struct uprobe_xol_ops;
37
36struct arch_uprobe { 38struct arch_uprobe {
37 u16 fixups;
38 union { 39 union {
39 u8 insn[MAX_UINSN_BYTES]; 40 u8 insn[MAX_UINSN_BYTES];
40 u8 ixol[MAX_UINSN_BYTES]; 41 u8 ixol[MAX_UINSN_BYTES];
41 }; 42 };
43
44 u16 fixups;
45 const struct uprobe_xol_ops *ops;
46
47 union {
42#ifdef CONFIG_X86_64 48#ifdef CONFIG_X86_64
43 unsigned long rip_rela_target_address; 49 unsigned long rip_rela_target_address;
44#endif 50#endif
51 struct {
52 s32 offs;
53 u8 ilen;
54 u8 opc1;
55 } branch;
56 };
45}; 57};
46 58
47struct arch_uprobe_task { 59struct arch_uprobe_task {
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index ae407f7226c8..89f3b7c1af20 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -721,6 +721,7 @@ int perf_assign_events(struct perf_event **events, int n,
721 721
722 return sched.state.unassigned; 722 return sched.state.unassigned;
723} 723}
724EXPORT_SYMBOL_GPL(perf_assign_events);
724 725
725int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) 726int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign)
726{ 727{
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index ae96cfa5eddd..980970cb744d 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -108,15 +108,31 @@ static u64 precise_store_data(u64 status)
108 return val; 108 return val;
109} 109}
110 110
111static u64 precise_store_data_hsw(u64 status) 111static u64 precise_store_data_hsw(struct perf_event *event, u64 status)
112{ 112{
113 union perf_mem_data_src dse; 113 union perf_mem_data_src dse;
114 u64 cfg = event->hw.config & INTEL_ARCH_EVENT_MASK;
114 115
115 dse.val = 0; 116 dse.val = 0;
116 dse.mem_op = PERF_MEM_OP_STORE; 117 dse.mem_op = PERF_MEM_OP_STORE;
117 dse.mem_lvl = PERF_MEM_LVL_NA; 118 dse.mem_lvl = PERF_MEM_LVL_NA;
119
120 /*
121 * L1 info only valid for following events:
122 *
123 * MEM_UOPS_RETIRED.STLB_MISS_STORES
124 * MEM_UOPS_RETIRED.LOCK_STORES
125 * MEM_UOPS_RETIRED.SPLIT_STORES
126 * MEM_UOPS_RETIRED.ALL_STORES
127 */
128 if (cfg != 0x12d0 && cfg != 0x22d0 && cfg != 0x42d0 && cfg != 0x82d0)
129 return dse.mem_lvl;
130
118 if (status & 1) 131 if (status & 1)
119 dse.mem_lvl = PERF_MEM_LVL_L1; 132 dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_HIT;
133 else
134 dse.mem_lvl = PERF_MEM_LVL_L1 | PERF_MEM_LVL_MISS;
135
120 /* Nothing else supported. Sorry. */ 136 /* Nothing else supported. Sorry. */
121 return dse.val; 137 return dse.val;
122} 138}
@@ -887,7 +903,7 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
887 data.data_src.val = load_latency_data(pebs->dse); 903 data.data_src.val = load_latency_data(pebs->dse);
888 else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW) 904 else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW)
889 data.data_src.val = 905 data.data_src.val =
890 precise_store_data_hsw(pebs->dse); 906 precise_store_data_hsw(event, pebs->dse);
891 else 907 else
892 data.data_src.val = precise_store_data(pebs->dse); 908 data.data_src.val = precise_store_data(pebs->dse);
893 } 909 }
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index 2ed845928b5f..ace22916ade3 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -53,7 +53,7 @@
53#define OPCODE1(insn) ((insn)->opcode.bytes[0]) 53#define OPCODE1(insn) ((insn)->opcode.bytes[0])
54#define OPCODE2(insn) ((insn)->opcode.bytes[1]) 54#define OPCODE2(insn) ((insn)->opcode.bytes[1])
55#define OPCODE3(insn) ((insn)->opcode.bytes[2]) 55#define OPCODE3(insn) ((insn)->opcode.bytes[2])
56#define MODRM_REG(insn) X86_MODRM_REG(insn->modrm.value) 56#define MODRM_REG(insn) X86_MODRM_REG((insn)->modrm.value)
57 57
58#define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\ 58#define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\
59 (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \ 59 (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \
@@ -229,63 +229,6 @@ static int validate_insn_32bits(struct arch_uprobe *auprobe, struct insn *insn)
229 return -ENOTSUPP; 229 return -ENOTSUPP;
230} 230}
231 231
232/*
233 * Figure out which fixups arch_uprobe_post_xol() will need to perform, and
234 * annotate arch_uprobe->fixups accordingly. To start with,
235 * arch_uprobe->fixups is either zero or it reflects rip-related fixups.
236 */
237static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn)
238{
239 bool fix_ip = true, fix_call = false; /* defaults */
240 int reg;
241
242 insn_get_opcode(insn); /* should be a nop */
243
244 switch (OPCODE1(insn)) {
245 case 0x9d:
246 /* popf */
247 auprobe->fixups |= UPROBE_FIX_SETF;
248 break;
249 case 0xc3: /* ret/lret */
250 case 0xcb:
251 case 0xc2:
252 case 0xca:
253 /* ip is correct */
254 fix_ip = false;
255 break;
256 case 0xe8: /* call relative - Fix return addr */
257 fix_call = true;
258 break;
259 case 0x9a: /* call absolute - Fix return addr, not ip */
260 fix_call = true;
261 fix_ip = false;
262 break;
263 case 0xff:
264 insn_get_modrm(insn);
265 reg = MODRM_REG(insn);
266 if (reg == 2 || reg == 3) {
267 /* call or lcall, indirect */
268 /* Fix return addr; ip is correct. */
269 fix_call = true;
270 fix_ip = false;
271 } else if (reg == 4 || reg == 5) {
272 /* jmp or ljmp, indirect */
273 /* ip is correct. */
274 fix_ip = false;
275 }
276 break;
277 case 0xea: /* jmp absolute -- ip is correct */
278 fix_ip = false;
279 break;
280 default:
281 break;
282 }
283 if (fix_ip)
284 auprobe->fixups |= UPROBE_FIX_IP;
285 if (fix_call)
286 auprobe->fixups |= UPROBE_FIX_CALL;
287}
288
289#ifdef CONFIG_X86_64 232#ifdef CONFIG_X86_64
290/* 233/*
291 * If arch_uprobe->insn doesn't use rip-relative addressing, return 234 * If arch_uprobe->insn doesn't use rip-relative addressing, return
@@ -310,15 +253,11 @@ static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn)
310 * - The displacement is always 4 bytes. 253 * - The displacement is always 4 bytes.
311 */ 254 */
312static void 255static void
313handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn) 256handle_riprel_insn(struct arch_uprobe *auprobe, struct insn *insn)
314{ 257{
315 u8 *cursor; 258 u8 *cursor;
316 u8 reg; 259 u8 reg;
317 260
318 if (mm->context.ia32_compat)
319 return;
320
321 auprobe->rip_rela_target_address = 0x0;
322 if (!insn_rip_relative(insn)) 261 if (!insn_rip_relative(insn))
323 return; 262 return;
324 263
@@ -372,7 +311,48 @@ handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct ins
372 cursor++; 311 cursor++;
373 memmove(cursor, cursor + insn->displacement.nbytes, insn->immediate.nbytes); 312 memmove(cursor, cursor + insn->displacement.nbytes, insn->immediate.nbytes);
374 } 313 }
375 return; 314}
315
316/*
317 * If we're emulating a rip-relative instruction, save the contents
318 * of the scratch register and store the target address in that register.
319 */
320static void
321pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs,
322 struct arch_uprobe_task *autask)
323{
324 if (auprobe->fixups & UPROBE_FIX_RIP_AX) {
325 autask->saved_scratch_register = regs->ax;
326 regs->ax = current->utask->vaddr;
327 regs->ax += auprobe->rip_rela_target_address;
328 } else if (auprobe->fixups & UPROBE_FIX_RIP_CX) {
329 autask->saved_scratch_register = regs->cx;
330 regs->cx = current->utask->vaddr;
331 regs->cx += auprobe->rip_rela_target_address;
332 }
333}
334
335static void
336handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction)
337{
338 if (auprobe->fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) {
339 struct arch_uprobe_task *autask;
340
341 autask = &current->utask->autask;
342 if (auprobe->fixups & UPROBE_FIX_RIP_AX)
343 regs->ax = autask->saved_scratch_register;
344 else
345 regs->cx = autask->saved_scratch_register;
346
347 /*
348 * The original instruction includes a displacement, and so
349 * is 4 bytes longer than what we've just single-stepped.
350 * Caller may need to apply other fixups to handle stuff
351 * like "jmpq *...(%rip)" and "callq *...(%rip)".
352 */
353 if (correction)
354 *correction += 4;
355 }
376} 356}
377 357
378static int validate_insn_64bits(struct arch_uprobe *auprobe, struct insn *insn) 358static int validate_insn_64bits(struct arch_uprobe *auprobe, struct insn *insn)
@@ -401,9 +381,19 @@ static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm,
401 return validate_insn_64bits(auprobe, insn); 381 return validate_insn_64bits(auprobe, insn);
402} 382}
403#else /* 32-bit: */ 383#else /* 32-bit: */
404static void handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn) 384/*
385 * No RIP-relative addressing on 32-bit
386 */
387static void handle_riprel_insn(struct arch_uprobe *auprobe, struct insn *insn)
388{
389}
390static void pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs,
391 struct arch_uprobe_task *autask)
392{
393}
394static void handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs,
395 long *correction)
405{ 396{
406 /* No RIP-relative addressing on 32-bit */
407} 397}
408 398
409static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn) 399static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn)
@@ -412,141 +402,311 @@ static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm,
412} 402}
413#endif /* CONFIG_X86_64 */ 403#endif /* CONFIG_X86_64 */
414 404
415/** 405struct uprobe_xol_ops {
416 * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. 406 bool (*emulate)(struct arch_uprobe *, struct pt_regs *);
417 * @mm: the probed address space. 407 int (*pre_xol)(struct arch_uprobe *, struct pt_regs *);
418 * @arch_uprobe: the probepoint information. 408 int (*post_xol)(struct arch_uprobe *, struct pt_regs *);
419 * @addr: virtual address at which to install the probepoint 409};
420 * Return 0 on success or a -ve number on error. 410
411static inline int sizeof_long(void)
412{
413 return is_ia32_task() ? 4 : 8;
414}
415
416static int default_pre_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
417{
418 pre_xol_rip_insn(auprobe, regs, &current->utask->autask);
419 return 0;
420}
421
422/*
423 * Adjust the return address pushed by a call insn executed out of line.
421 */ 424 */
422int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr) 425static int adjust_ret_addr(unsigned long sp, long correction)
423{ 426{
424 int ret; 427 int rasize = sizeof_long();
425 struct insn insn; 428 long ra;
426 429
427 auprobe->fixups = 0; 430 if (copy_from_user(&ra, (void __user *)sp, rasize))
428 ret = validate_insn_bits(auprobe, mm, &insn); 431 return -EFAULT;
429 if (ret != 0)
430 return ret;
431 432
432 handle_riprel_insn(auprobe, mm, &insn); 433 ra += correction;
433 prepare_fixups(auprobe, &insn); 434 if (copy_to_user((void __user *)sp, &ra, rasize))
435 return -EFAULT;
434 436
435 return 0; 437 return 0;
436} 438}
437 439
438#ifdef CONFIG_X86_64 440static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
439/*
440 * If we're emulating a rip-relative instruction, save the contents
441 * of the scratch register and store the target address in that register.
442 */
443static void
444pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs,
445 struct arch_uprobe_task *autask)
446{ 441{
447 if (auprobe->fixups & UPROBE_FIX_RIP_AX) { 442 struct uprobe_task *utask = current->utask;
448 autask->saved_scratch_register = regs->ax; 443 long correction = (long)(utask->vaddr - utask->xol_vaddr);
449 regs->ax = current->utask->vaddr; 444
450 regs->ax += auprobe->rip_rela_target_address; 445 handle_riprel_post_xol(auprobe, regs, &correction);
451 } else if (auprobe->fixups & UPROBE_FIX_RIP_CX) { 446 if (auprobe->fixups & UPROBE_FIX_IP)
452 autask->saved_scratch_register = regs->cx; 447 regs->ip += correction;
453 regs->cx = current->utask->vaddr; 448
454 regs->cx += auprobe->rip_rela_target_address; 449 if (auprobe->fixups & UPROBE_FIX_CALL) {
450 if (adjust_ret_addr(regs->sp, correction)) {
451 regs->sp += sizeof_long();
452 return -ERESTART;
453 }
455 } 454 }
455
456 return 0;
456} 457}
457#else 458
458static void 459static struct uprobe_xol_ops default_xol_ops = {
459pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs, 460 .pre_xol = default_pre_xol_op,
460 struct arch_uprobe_task *autask) 461 .post_xol = default_post_xol_op,
462};
463
464static bool branch_is_call(struct arch_uprobe *auprobe)
461{ 465{
462 /* No RIP-relative addressing on 32-bit */ 466 return auprobe->branch.opc1 == 0xe8;
463} 467}
464#endif
465 468
466/* 469#define CASE_COND \
467 * arch_uprobe_pre_xol - prepare to execute out of line. 470 COND(70, 71, XF(OF)) \
468 * @auprobe: the probepoint information. 471 COND(72, 73, XF(CF)) \
469 * @regs: reflects the saved user state of current task. 472 COND(74, 75, XF(ZF)) \
470 */ 473 COND(78, 79, XF(SF)) \
471int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 474 COND(7a, 7b, XF(PF)) \
472{ 475 COND(76, 77, XF(CF) || XF(ZF)) \
473 struct arch_uprobe_task *autask; 476 COND(7c, 7d, XF(SF) != XF(OF)) \
477 COND(7e, 7f, XF(ZF) || XF(SF) != XF(OF))
474 478
475 autask = &current->utask->autask; 479#define COND(op_y, op_n, expr) \
476 autask->saved_trap_nr = current->thread.trap_nr; 480 case 0x ## op_y: DO((expr) != 0) \
477 current->thread.trap_nr = UPROBE_TRAP_NR; 481 case 0x ## op_n: DO((expr) == 0)
478 regs->ip = current->utask->xol_vaddr;
479 pre_xol_rip_insn(auprobe, regs, autask);
480 482
481 autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF); 483#define XF(xf) (!!(flags & X86_EFLAGS_ ## xf))
482 regs->flags |= X86_EFLAGS_TF;
483 if (test_tsk_thread_flag(current, TIF_BLOCKSTEP))
484 set_task_blockstep(current, false);
485 484
486 return 0; 485static bool is_cond_jmp_opcode(u8 opcode)
486{
487 switch (opcode) {
488 #define DO(expr) \
489 return true;
490 CASE_COND
491 #undef DO
492
493 default:
494 return false;
495 }
487} 496}
488 497
489/* 498static bool check_jmp_cond(struct arch_uprobe *auprobe, struct pt_regs *regs)
490 * This function is called by arch_uprobe_post_xol() to adjust the return
491 * address pushed by a call instruction executed out of line.
492 */
493static int adjust_ret_addr(unsigned long sp, long correction)
494{ 499{
495 int rasize, ncopied; 500 unsigned long flags = regs->flags;
496 long ra = 0;
497 501
498 if (is_ia32_task()) 502 switch (auprobe->branch.opc1) {
499 rasize = 4; 503 #define DO(expr) \
500 else 504 return expr;
501 rasize = 8; 505 CASE_COND
506 #undef DO
502 507
503 ncopied = copy_from_user(&ra, (void __user *)sp, rasize); 508 default: /* not a conditional jmp */
504 if (unlikely(ncopied)) 509 return true;
505 return -EFAULT; 510 }
511}
506 512
507 ra += correction; 513#undef XF
508 ncopied = copy_to_user((void __user *)sp, &ra, rasize); 514#undef COND
509 if (unlikely(ncopied)) 515#undef CASE_COND
510 return -EFAULT;
511 516
512 return 0; 517static bool branch_emulate_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
518{
519 unsigned long new_ip = regs->ip += auprobe->branch.ilen;
520 unsigned long offs = (long)auprobe->branch.offs;
521
522 if (branch_is_call(auprobe)) {
523 unsigned long new_sp = regs->sp - sizeof_long();
524 /*
525 * If it fails we execute this (mangled, see the comment in
526 * branch_clear_offset) insn out-of-line. In the likely case
527 * this should trigger the trap, and the probed application
528 * should die or restart the same insn after it handles the
529 * signal, arch_uprobe_post_xol() won't be even called.
530 *
531 * But there is corner case, see the comment in ->post_xol().
532 */
533 if (copy_to_user((void __user *)new_sp, &new_ip, sizeof_long()))
534 return false;
535 regs->sp = new_sp;
536 } else if (!check_jmp_cond(auprobe, regs)) {
537 offs = 0;
538 }
539
540 regs->ip = new_ip + offs;
541 return true;
513} 542}
514 543
515#ifdef CONFIG_X86_64 544static int branch_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs)
516static bool is_riprel_insn(struct arch_uprobe *auprobe)
517{ 545{
518 return ((auprobe->fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) != 0); 546 BUG_ON(!branch_is_call(auprobe));
547 /*
548 * We can only get here if branch_emulate_op() failed to push the ret
549 * address _and_ another thread expanded our stack before the (mangled)
550 * "call" insn was executed out-of-line. Just restore ->sp and restart.
551 * We could also restore ->ip and try to call branch_emulate_op() again.
552 */
553 regs->sp += sizeof_long();
554 return -ERESTART;
519} 555}
520 556
521static void 557static void branch_clear_offset(struct arch_uprobe *auprobe, struct insn *insn)
522handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction)
523{ 558{
524 if (is_riprel_insn(auprobe)) { 559 /*
525 struct arch_uprobe_task *autask; 560 * Turn this insn into "call 1f; 1:", this is what we will execute
561 * out-of-line if ->emulate() fails. We only need this to generate
562 * a trap, so that the probed task receives the correct signal with
563 * the properly filled siginfo.
564 *
565 * But see the comment in ->post_xol(), in the unlikely case it can
566 * succeed. So we need to ensure that the new ->ip can not fall into
567 * the non-canonical area and trigger #GP.
568 *
569 * We could turn it into (say) "pushf", but then we would need to
570 * divorce ->insn[] and ->ixol[]. We need to preserve the 1st byte
571 * of ->insn[] for set_orig_insn().
572 */
573 memset(auprobe->insn + insn_offset_immediate(insn),
574 0, insn->immediate.nbytes);
575}
526 576
527 autask = &current->utask->autask; 577static struct uprobe_xol_ops branch_xol_ops = {
528 if (auprobe->fixups & UPROBE_FIX_RIP_AX) 578 .emulate = branch_emulate_op,
529 regs->ax = autask->saved_scratch_register; 579 .post_xol = branch_post_xol_op,
530 else 580};
531 regs->cx = autask->saved_scratch_register; 581
582/* Returns -ENOSYS if branch_xol_ops doesn't handle this insn */
583static int branch_setup_xol_ops(struct arch_uprobe *auprobe, struct insn *insn)
584{
585 u8 opc1 = OPCODE1(insn);
586
587 /* has the side-effect of processing the entire instruction */
588 insn_get_length(insn);
589 if (WARN_ON_ONCE(!insn_complete(insn)))
590 return -ENOEXEC;
591
592 switch (opc1) {
593 case 0xeb: /* jmp 8 */
594 case 0xe9: /* jmp 32 */
595 case 0x90: /* prefix* + nop; same as jmp with .offs = 0 */
596 break;
597
598 case 0xe8: /* call relative */
599 branch_clear_offset(auprobe, insn);
600 break;
532 601
602 case 0x0f:
603 if (insn->opcode.nbytes != 2)
604 return -ENOSYS;
533 /* 605 /*
534 * The original instruction includes a displacement, and so 606 * If it is a "near" conditional jmp, OPCODE2() - 0x10 matches
535 * is 4 bytes longer than what we've just single-stepped. 607 * OPCODE1() of the "short" jmp which checks the same condition.
536 * Fall through to handle stuff like "jmpq *...(%rip)" and
537 * "callq *...(%rip)".
538 */ 608 */
539 if (correction) 609 opc1 = OPCODE2(insn) - 0x10;
540 *correction += 4; 610 default:
611 if (!is_cond_jmp_opcode(opc1))
612 return -ENOSYS;
541 } 613 }
614
615 auprobe->branch.opc1 = opc1;
616 auprobe->branch.ilen = insn->length;
617 auprobe->branch.offs = insn->immediate.value;
618
619 auprobe->ops = &branch_xol_ops;
620 return 0;
542} 621}
543#else 622
544static void 623/**
545handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction) 624 * arch_uprobe_analyze_insn - instruction analysis including validity and fixups.
625 * @mm: the probed address space.
626 * @arch_uprobe: the probepoint information.
627 * @addr: virtual address at which to install the probepoint
628 * Return 0 on success or a -ve number on error.
629 */
630int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr)
631{
632 struct insn insn;
633 bool fix_ip = true, fix_call = false;
634 int ret;
635
636 ret = validate_insn_bits(auprobe, mm, &insn);
637 if (ret)
638 return ret;
639
640 ret = branch_setup_xol_ops(auprobe, &insn);
641 if (ret != -ENOSYS)
642 return ret;
643
644 /*
645 * Figure out which fixups arch_uprobe_post_xol() will need to perform,
646 * and annotate arch_uprobe->fixups accordingly. To start with, ->fixups
647 * is either zero or it reflects rip-related fixups.
648 */
649 switch (OPCODE1(&insn)) {
650 case 0x9d: /* popf */
651 auprobe->fixups |= UPROBE_FIX_SETF;
652 break;
653 case 0xc3: /* ret or lret -- ip is correct */
654 case 0xcb:
655 case 0xc2:
656 case 0xca:
657 fix_ip = false;
658 break;
659 case 0x9a: /* call absolute - Fix return addr, not ip */
660 fix_call = true;
661 fix_ip = false;
662 break;
663 case 0xea: /* jmp absolute -- ip is correct */
664 fix_ip = false;
665 break;
666 case 0xff:
667 insn_get_modrm(&insn);
668 switch (MODRM_REG(&insn)) {
669 case 2: case 3: /* call or lcall, indirect */
670 fix_call = true;
671 case 4: case 5: /* jmp or ljmp, indirect */
672 fix_ip = false;
673 }
674 /* fall through */
675 default:
676 handle_riprel_insn(auprobe, &insn);
677 }
678
679 if (fix_ip)
680 auprobe->fixups |= UPROBE_FIX_IP;
681 if (fix_call)
682 auprobe->fixups |= UPROBE_FIX_CALL;
683
684 auprobe->ops = &default_xol_ops;
685 return 0;
686}
687
688/*
689 * arch_uprobe_pre_xol - prepare to execute out of line.
690 * @auprobe: the probepoint information.
691 * @regs: reflects the saved user state of current task.
692 */
693int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
546{ 694{
547 /* No RIP-relative addressing on 32-bit */ 695 struct uprobe_task *utask = current->utask;
696
697 regs->ip = utask->xol_vaddr;
698 utask->autask.saved_trap_nr = current->thread.trap_nr;
699 current->thread.trap_nr = UPROBE_TRAP_NR;
700
701 utask->autask.saved_tf = !!(regs->flags & X86_EFLAGS_TF);
702 regs->flags |= X86_EFLAGS_TF;
703 if (test_tsk_thread_flag(current, TIF_BLOCKSTEP))
704 set_task_blockstep(current, false);
705
706 if (auprobe->ops->pre_xol)
707 return auprobe->ops->pre_xol(auprobe, regs);
708 return 0;
548} 709}
549#endif
550 710
551/* 711/*
552 * If xol insn itself traps and generates a signal(Say, 712 * If xol insn itself traps and generates a signal(Say,
@@ -592,22 +752,25 @@ bool arch_uprobe_xol_was_trapped(struct task_struct *t)
592 */ 752 */
593int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 753int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
594{ 754{
595 struct uprobe_task *utask; 755 struct uprobe_task *utask = current->utask;
596 long correction;
597 int result = 0;
598 756
599 WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR); 757 WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
600 758
601 utask = current->utask; 759 if (auprobe->ops->post_xol) {
602 current->thread.trap_nr = utask->autask.saved_trap_nr; 760 int err = auprobe->ops->post_xol(auprobe, regs);
603 correction = (long)(utask->vaddr - utask->xol_vaddr); 761 if (err) {
604 handle_riprel_post_xol(auprobe, regs, &correction); 762 arch_uprobe_abort_xol(auprobe, regs);
605 if (auprobe->fixups & UPROBE_FIX_IP) 763 /*
606 regs->ip += correction; 764 * Restart the probed insn. ->post_xol() must ensure
607 765 * this is really possible if it returns -ERESTART.
608 if (auprobe->fixups & UPROBE_FIX_CALL) 766 */
609 result = adjust_ret_addr(regs->sp, correction); 767 if (err == -ERESTART)
768 return 0;
769 return err;
770 }
771 }
610 772
773 current->thread.trap_nr = utask->autask.saved_trap_nr;
611 /* 774 /*
612 * arch_uprobe_pre_xol() doesn't save the state of TIF_BLOCKSTEP 775 * arch_uprobe_pre_xol() doesn't save the state of TIF_BLOCKSTEP
613 * so we can get an extra SIGTRAP if we do not clear TF. We need 776 * so we can get an extra SIGTRAP if we do not clear TF. We need
@@ -618,7 +781,7 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
618 else if (!(auprobe->fixups & UPROBE_FIX_SETF)) 781 else if (!(auprobe->fixups & UPROBE_FIX_SETF))
619 regs->flags &= ~X86_EFLAGS_TF; 782 regs->flags &= ~X86_EFLAGS_TF;
620 783
621 return result; 784 return 0;
622} 785}
623 786
624/* callback routine for handling exceptions. */ 787/* callback routine for handling exceptions. */
@@ -652,8 +815,9 @@ int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val,
652 815
653/* 816/*
654 * This function gets called when XOL instruction either gets trapped or 817 * This function gets called when XOL instruction either gets trapped or
655 * the thread has a fatal signal, so reset the instruction pointer to its 818 * the thread has a fatal signal, or if arch_uprobe_post_xol() failed.
656 * probed address. 819 * Reset the instruction pointer to its probed address for the potential
820 * restart or for post mortem analysis.
657 */ 821 */
658void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) 822void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
659{ 823{
@@ -668,25 +832,10 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
668 regs->flags &= ~X86_EFLAGS_TF; 832 regs->flags &= ~X86_EFLAGS_TF;
669} 833}
670 834
671/*
672 * Skip these instructions as per the currently known x86 ISA.
673 * rep=0x66*; nop=0x90
674 */
675static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) 835static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
676{ 836{
677 int i; 837 if (auprobe->ops->emulate)
678 838 return auprobe->ops->emulate(auprobe, regs);
679 for (i = 0; i < MAX_UINSN_BYTES; i++) {
680 if (auprobe->insn[i] == 0x66)
681 continue;
682
683 if (auprobe->insn[i] == 0x90) {
684 regs->ip += i + 1;
685 return true;
686 }
687
688 break;
689 }
690 return false; 839 return false;
691} 840}
692 841
@@ -701,23 +850,21 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
701unsigned long 850unsigned long
702arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs) 851arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs)
703{ 852{
704 int rasize, ncopied; 853 int rasize = sizeof_long(), nleft;
705 unsigned long orig_ret_vaddr = 0; /* clear high bits for 32-bit apps */ 854 unsigned long orig_ret_vaddr = 0; /* clear high bits for 32-bit apps */
706 855
707 rasize = is_ia32_task() ? 4 : 8; 856 if (copy_from_user(&orig_ret_vaddr, (void __user *)regs->sp, rasize))
708 ncopied = copy_from_user(&orig_ret_vaddr, (void __user *)regs->sp, rasize);
709 if (unlikely(ncopied))
710 return -1; 857 return -1;
711 858
712 /* check whether address has been already hijacked */ 859 /* check whether address has been already hijacked */
713 if (orig_ret_vaddr == trampoline_vaddr) 860 if (orig_ret_vaddr == trampoline_vaddr)
714 return orig_ret_vaddr; 861 return orig_ret_vaddr;
715 862
716 ncopied = copy_to_user((void __user *)regs->sp, &trampoline_vaddr, rasize); 863 nleft = copy_to_user((void __user *)regs->sp, &trampoline_vaddr, rasize);
717 if (likely(!ncopied)) 864 if (likely(!nleft))
718 return orig_ret_vaddr; 865 return orig_ret_vaddr;
719 866
720 if (ncopied != rasize) { 867 if (nleft != rasize) {
721 pr_err("uprobe: return address clobbered: pid=%d, %%sp=%#lx, " 868 pr_err("uprobe: return address clobbered: pid=%d, %%sp=%#lx, "
722 "%%ip=%#lx\n", current->pid, regs->sp, regs->ip); 869 "%%ip=%#lx\n", current->pid, regs->sp, regs->ip);
723 870
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 3ef6ea12806a..a9209118d80f 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -172,6 +172,7 @@ struct perf_event;
172struct pmu { 172struct pmu {
173 struct list_head entry; 173 struct list_head entry;
174 174
175 struct module *module;
175 struct device *dev; 176 struct device *dev;
176 const struct attribute_group **attr_groups; 177 const struct attribute_group **attr_groups;
177 const char *name; 178 const char *name;
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 853bc1ccb395..e3fc8f09d110 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -722,10 +722,10 @@ enum perf_callchain_context {
722 PERF_CONTEXT_MAX = (__u64)-4095, 722 PERF_CONTEXT_MAX = (__u64)-4095,
723}; 723};
724 724
725#define PERF_FLAG_FD_NO_GROUP (1U << 0) 725#define PERF_FLAG_FD_NO_GROUP (1UL << 0)
726#define PERF_FLAG_FD_OUTPUT (1U << 1) 726#define PERF_FLAG_FD_OUTPUT (1UL << 1)
727#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */ 727#define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
728#define PERF_FLAG_FD_CLOEXEC (1U << 3) /* O_CLOEXEC */ 728#define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
729 729
730union perf_mem_data_src { 730union perf_mem_data_src {
731 __u64 val; 731 __u64 val;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 440eefc67397..689237a0c5e8 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -39,6 +39,7 @@
39#include <linux/hw_breakpoint.h> 39#include <linux/hw_breakpoint.h>
40#include <linux/mm_types.h> 40#include <linux/mm_types.h>
41#include <linux/cgroup.h> 41#include <linux/cgroup.h>
42#include <linux/module.h>
42 43
43#include "internal.h" 44#include "internal.h"
44 45
@@ -1677,6 +1678,8 @@ event_sched_in(struct perf_event *event,
1677 u64 tstamp = perf_event_time(event); 1678 u64 tstamp = perf_event_time(event);
1678 int ret = 0; 1679 int ret = 0;
1679 1680
1681 lockdep_assert_held(&ctx->lock);
1682
1680 if (event->state <= PERF_EVENT_STATE_OFF) 1683 if (event->state <= PERF_EVENT_STATE_OFF)
1681 return 0; 1684 return 0;
1682 1685
@@ -3244,9 +3247,13 @@ static void __free_event(struct perf_event *event)
3244 if (event->ctx) 3247 if (event->ctx)
3245 put_ctx(event->ctx); 3248 put_ctx(event->ctx);
3246 3249
3250 if (event->pmu)
3251 module_put(event->pmu->module);
3252
3247 call_rcu(&event->rcu_head, free_event_rcu); 3253 call_rcu(&event->rcu_head, free_event_rcu);
3248} 3254}
3249static void free_event(struct perf_event *event) 3255
3256static void _free_event(struct perf_event *event)
3250{ 3257{
3251 irq_work_sync(&event->pending); 3258 irq_work_sync(&event->pending);
3252 3259
@@ -3267,42 +3274,31 @@ static void free_event(struct perf_event *event)
3267 if (is_cgroup_event(event)) 3274 if (is_cgroup_event(event))
3268 perf_detach_cgroup(event); 3275 perf_detach_cgroup(event);
3269 3276
3270
3271 __free_event(event); 3277 __free_event(event);
3272} 3278}
3273 3279
3274int perf_event_release_kernel(struct perf_event *event) 3280/*
3281 * Used to free events which have a known refcount of 1, such as in error paths
3282 * where the event isn't exposed yet and inherited events.
3283 */
3284static void free_event(struct perf_event *event)
3275{ 3285{
3276 struct perf_event_context *ctx = event->ctx; 3286 if (WARN(atomic_long_cmpxchg(&event->refcount, 1, 0) != 1,
3277 3287 "unexpected event refcount: %ld; ptr=%p\n",
3278 WARN_ON_ONCE(ctx->parent_ctx); 3288 atomic_long_read(&event->refcount), event)) {
3279 /* 3289 /* leak to avoid use-after-free */
3280 * There are two ways this annotation is useful: 3290 return;
3281 * 3291 }
3282 * 1) there is a lock recursion from perf_event_exit_task
3283 * see the comment there.
3284 *
3285 * 2) there is a lock-inversion with mmap_sem through
3286 * perf_event_read_group(), which takes faults while
3287 * holding ctx->mutex, however this is called after
3288 * the last filedesc died, so there is no possibility
3289 * to trigger the AB-BA case.
3290 */
3291 mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING);
3292 perf_remove_from_context(event, true);
3293 mutex_unlock(&ctx->mutex);
3294
3295 free_event(event);
3296 3292
3297 return 0; 3293 _free_event(event);
3298} 3294}
3299EXPORT_SYMBOL_GPL(perf_event_release_kernel);
3300 3295
3301/* 3296/*
3302 * Called when the last reference to the file is gone. 3297 * Called when the last reference to the file is gone.
3303 */ 3298 */
3304static void put_event(struct perf_event *event) 3299static void put_event(struct perf_event *event)
3305{ 3300{
3301 struct perf_event_context *ctx = event->ctx;
3306 struct task_struct *owner; 3302 struct task_struct *owner;
3307 3303
3308 if (!atomic_long_dec_and_test(&event->refcount)) 3304 if (!atomic_long_dec_and_test(&event->refcount))
@@ -3341,9 +3337,33 @@ static void put_event(struct perf_event *event)
3341 put_task_struct(owner); 3337 put_task_struct(owner);
3342 } 3338 }
3343 3339
3344 perf_event_release_kernel(event); 3340 WARN_ON_ONCE(ctx->parent_ctx);
3341 /*
3342 * There are two ways this annotation is useful:
3343 *
3344 * 1) there is a lock recursion from perf_event_exit_task
3345 * see the comment there.
3346 *
3347 * 2) there is a lock-inversion with mmap_sem through
3348 * perf_event_read_group(), which takes faults while
3349 * holding ctx->mutex, however this is called after
3350 * the last filedesc died, so there is no possibility
3351 * to trigger the AB-BA case.
3352 */
3353 mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING);
3354 perf_remove_from_context(event, true);
3355 mutex_unlock(&ctx->mutex);
3356
3357 _free_event(event);
3345} 3358}
3346 3359
3360int perf_event_release_kernel(struct perf_event *event)
3361{
3362 put_event(event);
3363 return 0;
3364}
3365EXPORT_SYMBOL_GPL(perf_event_release_kernel);
3366
3347static int perf_release(struct inode *inode, struct file *file) 3367static int perf_release(struct inode *inode, struct file *file)
3348{ 3368{
3349 put_event(file->private_data); 3369 put_event(file->private_data);
@@ -6578,6 +6598,7 @@ free_pdc:
6578 free_percpu(pmu->pmu_disable_count); 6598 free_percpu(pmu->pmu_disable_count);
6579 goto unlock; 6599 goto unlock;
6580} 6600}
6601EXPORT_SYMBOL_GPL(perf_pmu_register);
6581 6602
6582void perf_pmu_unregister(struct pmu *pmu) 6603void perf_pmu_unregister(struct pmu *pmu)
6583{ 6604{
@@ -6599,6 +6620,7 @@ void perf_pmu_unregister(struct pmu *pmu)
6599 put_device(pmu->dev); 6620 put_device(pmu->dev);
6600 free_pmu_context(pmu); 6621 free_pmu_context(pmu);
6601} 6622}
6623EXPORT_SYMBOL_GPL(perf_pmu_unregister);
6602 6624
6603struct pmu *perf_init_event(struct perf_event *event) 6625struct pmu *perf_init_event(struct perf_event *event)
6604{ 6626{
@@ -6612,6 +6634,10 @@ struct pmu *perf_init_event(struct perf_event *event)
6612 pmu = idr_find(&pmu_idr, event->attr.type); 6634 pmu = idr_find(&pmu_idr, event->attr.type);
6613 rcu_read_unlock(); 6635 rcu_read_unlock();
6614 if (pmu) { 6636 if (pmu) {
6637 if (!try_module_get(pmu->module)) {
6638 pmu = ERR_PTR(-ENODEV);
6639 goto unlock;
6640 }
6615 event->pmu = pmu; 6641 event->pmu = pmu;
6616 ret = pmu->event_init(event); 6642 ret = pmu->event_init(event);
6617 if (ret) 6643 if (ret)
@@ -6620,6 +6646,10 @@ struct pmu *perf_init_event(struct perf_event *event)
6620 } 6646 }
6621 6647
6622 list_for_each_entry_rcu(pmu, &pmus, entry) { 6648 list_for_each_entry_rcu(pmu, &pmus, entry) {
6649 if (!try_module_get(pmu->module)) {
6650 pmu = ERR_PTR(-ENODEV);
6651 goto unlock;
6652 }
6623 event->pmu = pmu; 6653 event->pmu = pmu;
6624 ret = pmu->event_init(event); 6654 ret = pmu->event_init(event);
6625 if (!ret) 6655 if (!ret)
@@ -6798,6 +6828,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
6798err_pmu: 6828err_pmu:
6799 if (event->destroy) 6829 if (event->destroy)
6800 event->destroy(event); 6830 event->destroy(event);
6831 module_put(pmu->module);
6801err_ns: 6832err_ns:
6802 if (event->ns) 6833 if (event->ns)
6803 put_pid_ns(event->ns); 6834 put_pid_ns(event->ns);
@@ -7067,20 +7098,26 @@ SYSCALL_DEFINE5(perf_event_open,
7067 } 7098 }
7068 } 7099 }
7069 7100
7101 if (task && group_leader &&
7102 group_leader->attr.inherit != attr.inherit) {
7103 err = -EINVAL;
7104 goto err_task;
7105 }
7106
7070 get_online_cpus(); 7107 get_online_cpus();
7071 7108
7072 event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, 7109 event = perf_event_alloc(&attr, cpu, task, group_leader, NULL,
7073 NULL, NULL); 7110 NULL, NULL);
7074 if (IS_ERR(event)) { 7111 if (IS_ERR(event)) {
7075 err = PTR_ERR(event); 7112 err = PTR_ERR(event);
7076 goto err_task; 7113 goto err_cpus;
7077 } 7114 }
7078 7115
7079 if (flags & PERF_FLAG_PID_CGROUP) { 7116 if (flags & PERF_FLAG_PID_CGROUP) {
7080 err = perf_cgroup_connect(pid, event, &attr, group_leader); 7117 err = perf_cgroup_connect(pid, event, &attr, group_leader);
7081 if (err) { 7118 if (err) {
7082 __free_event(event); 7119 __free_event(event);
7083 goto err_task; 7120 goto err_cpus;
7084 } 7121 }
7085 } 7122 }
7086 7123
@@ -7242,8 +7279,9 @@ err_context:
7242 put_ctx(ctx); 7279 put_ctx(ctx);
7243err_alloc: 7280err_alloc:
7244 free_event(event); 7281 free_event(event);
7245err_task: 7282err_cpus:
7246 put_online_cpus(); 7283 put_online_cpus();
7284err_task:
7247 if (task) 7285 if (task)
7248 put_task_struct(task); 7286 put_task_struct(task);
7249err_group_fd: 7287err_group_fd:
@@ -7379,7 +7417,7 @@ __perf_event_exit_task(struct perf_event *child_event,
7379 struct perf_event_context *child_ctx, 7417 struct perf_event_context *child_ctx,
7380 struct task_struct *child) 7418 struct task_struct *child)
7381{ 7419{
7382 perf_remove_from_context(child_event, !!child_event->parent); 7420 perf_remove_from_context(child_event, true);
7383 7421
7384 /* 7422 /*
7385 * It can happen that the parent exits first, and has events 7423 * It can happen that the parent exits first, and has events
@@ -7394,7 +7432,7 @@ __perf_event_exit_task(struct perf_event *child_event,
7394 7432
7395static void perf_event_exit_task_context(struct task_struct *child, int ctxn) 7433static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
7396{ 7434{
7397 struct perf_event *child_event, *tmp; 7435 struct perf_event *child_event;
7398 struct perf_event_context *child_ctx; 7436 struct perf_event_context *child_ctx;
7399 unsigned long flags; 7437 unsigned long flags;
7400 7438
@@ -7448,24 +7486,9 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
7448 */ 7486 */
7449 mutex_lock(&child_ctx->mutex); 7487 mutex_lock(&child_ctx->mutex);
7450 7488
7451again: 7489 list_for_each_entry_rcu(child_event, &child_ctx->event_list, event_entry)
7452 list_for_each_entry_safe(child_event, tmp, &child_ctx->pinned_groups,
7453 group_entry)
7454 __perf_event_exit_task(child_event, child_ctx, child);
7455
7456 list_for_each_entry_safe(child_event, tmp, &child_ctx->flexible_groups,
7457 group_entry)
7458 __perf_event_exit_task(child_event, child_ctx, child); 7490 __perf_event_exit_task(child_event, child_ctx, child);
7459 7491
7460 /*
7461 * If the last event was a group event, it will have appended all
7462 * its siblings to the list, but we obtained 'tmp' before that which
7463 * will still point to the list head terminating the iteration.
7464 */
7465 if (!list_empty(&child_ctx->pinned_groups) ||
7466 !list_empty(&child_ctx->flexible_groups))
7467 goto again;
7468
7469 mutex_unlock(&child_ctx->mutex); 7492 mutex_unlock(&child_ctx->mutex);
7470 7493
7471 put_ctx(child_ctx); 7494 put_ctx(child_ctx);
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 04709b66369d..d1edc5e6fd03 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -60,8 +60,6 @@ static struct percpu_rw_semaphore dup_mmap_sem;
60 60
61/* Have a copy of original instruction */ 61/* Have a copy of original instruction */
62#define UPROBE_COPY_INSN 0 62#define UPROBE_COPY_INSN 0
63/* Can skip singlestep */
64#define UPROBE_SKIP_SSTEP 1
65 63
66struct uprobe { 64struct uprobe {
67 struct rb_node rb_node; /* node in the rb tree */ 65 struct rb_node rb_node; /* node in the rb tree */
@@ -491,12 +489,9 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
491 uprobe->offset = offset; 489 uprobe->offset = offset;
492 init_rwsem(&uprobe->register_rwsem); 490 init_rwsem(&uprobe->register_rwsem);
493 init_rwsem(&uprobe->consumer_rwsem); 491 init_rwsem(&uprobe->consumer_rwsem);
494 /* For now assume that the instruction need not be single-stepped */
495 __set_bit(UPROBE_SKIP_SSTEP, &uprobe->flags);
496 492
497 /* add to uprobes_tree, sorted on inode:offset */ 493 /* add to uprobes_tree, sorted on inode:offset */
498 cur_uprobe = insert_uprobe(uprobe); 494 cur_uprobe = insert_uprobe(uprobe);
499
500 /* a uprobe exists for this inode:offset combination */ 495 /* a uprobe exists for this inode:offset combination */
501 if (cur_uprobe) { 496 if (cur_uprobe) {
502 kfree(uprobe); 497 kfree(uprobe);
@@ -1628,20 +1623,6 @@ bool uprobe_deny_signal(void)
1628 return true; 1623 return true;
1629} 1624}
1630 1625
1631/*
1632 * Avoid singlestepping the original instruction if the original instruction
1633 * is a NOP or can be emulated.
1634 */
1635static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs)
1636{
1637 if (test_bit(UPROBE_SKIP_SSTEP, &uprobe->flags)) {
1638 if (arch_uprobe_skip_sstep(&uprobe->arch, regs))
1639 return true;
1640 clear_bit(UPROBE_SKIP_SSTEP, &uprobe->flags);
1641 }
1642 return false;
1643}
1644
1645static void mmf_recalc_uprobes(struct mm_struct *mm) 1626static void mmf_recalc_uprobes(struct mm_struct *mm)
1646{ 1627{
1647 struct vm_area_struct *vma; 1628 struct vm_area_struct *vma;
@@ -1868,13 +1849,13 @@ static void handle_swbp(struct pt_regs *regs)
1868 1849
1869 handler_chain(uprobe, regs); 1850 handler_chain(uprobe, regs);
1870 1851
1871 if (can_skip_sstep(uprobe, regs)) 1852 if (arch_uprobe_skip_sstep(&uprobe->arch, regs))
1872 goto out; 1853 goto out;
1873 1854
1874 if (!pre_ssout(uprobe, regs, bp_vaddr)) 1855 if (!pre_ssout(uprobe, regs, bp_vaddr))
1875 return; 1856 return;
1876 1857
1877 /* can_skip_sstep() succeeded, or restart if can't singlestep */ 1858 /* arch_uprobe_skip_sstep() succeeded, or restart if can't singlestep */
1878out: 1859out:
1879 put_uprobe(uprobe); 1860 put_uprobe(uprobe);
1880} 1861}
@@ -1886,10 +1867,11 @@ out:
1886static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) 1867static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs)
1887{ 1868{
1888 struct uprobe *uprobe; 1869 struct uprobe *uprobe;
1870 int err = 0;
1889 1871
1890 uprobe = utask->active_uprobe; 1872 uprobe = utask->active_uprobe;
1891 if (utask->state == UTASK_SSTEP_ACK) 1873 if (utask->state == UTASK_SSTEP_ACK)
1892 arch_uprobe_post_xol(&uprobe->arch, regs); 1874 err = arch_uprobe_post_xol(&uprobe->arch, regs);
1893 else if (utask->state == UTASK_SSTEP_TRAPPED) 1875 else if (utask->state == UTASK_SSTEP_TRAPPED)
1894 arch_uprobe_abort_xol(&uprobe->arch, regs); 1876 arch_uprobe_abort_xol(&uprobe->arch, regs);
1895 else 1877 else
@@ -1903,6 +1885,11 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs)
1903 spin_lock_irq(&current->sighand->siglock); 1885 spin_lock_irq(&current->sighand->siglock);
1904 recalc_sigpending(); /* see uprobe_deny_signal() */ 1886 recalc_sigpending(); /* see uprobe_deny_signal() */
1905 spin_unlock_irq(&current->sighand->siglock); 1887 spin_unlock_irq(&current->sighand->siglock);
1888
1889 if (unlikely(err)) {
1890 uprobe_warn(current, "execute the probed insn, sending SIGILL.");
1891 force_sig_info(SIGILL, SEND_SIG_FORCED, current);
1892 }
1906} 1893}
1907 1894
1908/* 1895/*
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index e0501fe7140d..3ab28993f6e0 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1039,6 +1039,7 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
1039 1039
1040 return ret; 1040 return ret;
1041} 1041}
1042EXPORT_SYMBOL_GPL(__hrtimer_start_range_ns);
1042 1043
1043/** 1044/**
1044 * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU 1045 * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU
diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h
index fbc6665c6d53..88461f09cc86 100644
--- a/tools/include/linux/compiler.h
+++ b/tools/include/linux/compiler.h
@@ -35,4 +35,6 @@
35# define unlikely(x) __builtin_expect(!!(x), 0) 35# define unlikely(x) __builtin_expect(!!(x), 0)
36#endif 36#endif
37 37
38#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
39
38#endif /* _TOOLS_LINUX_COMPILER_H */ 40#endif /* _TOOLS_LINUX_COMPILER_H */
diff --git a/tools/virtio/linux/export.h b/tools/include/linux/export.h
index 7311d326894a..d07e586b9ba0 100644
--- a/tools/virtio/linux/export.h
+++ b/tools/include/linux/export.h
@@ -1,5 +1,10 @@
1#ifndef _TOOLS_LINUX_EXPORT_H_
2#define _TOOLS_LINUX_EXPORT_H_
3
1#define EXPORT_SYMBOL(sym) 4#define EXPORT_SYMBOL(sym)
2#define EXPORT_SYMBOL_GPL(sym) 5#define EXPORT_SYMBOL_GPL(sym)
3#define EXPORT_SYMBOL_GPL_FUTURE(sym) 6#define EXPORT_SYMBOL_GPL_FUTURE(sym)
4#define EXPORT_UNUSED_SYMBOL(sym) 7#define EXPORT_UNUSED_SYMBOL(sym)
5#define EXPORT_UNUSED_SYMBOL_GPL(sym) 8#define EXPORT_UNUSED_SYMBOL_GPL(sym)
9
10#endif
diff --git a/tools/lib/lockdep/uinclude/linux/types.h b/tools/include/linux/types.h
index 929938f426de..b5cf25e05df2 100644
--- a/tools/lib/lockdep/uinclude/linux/types.h
+++ b/tools/include/linux/types.h
@@ -1,8 +1,9 @@
1#ifndef _LIBLOCKDEP_LINUX_TYPES_H_ 1#ifndef _TOOLS_LINUX_TYPES_H_
2#define _LIBLOCKDEP_LINUX_TYPES_H_ 2#define _TOOLS_LINUX_TYPES_H_
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <stddef.h> 5#include <stddef.h>
6#include <stdint.h>
6 7
7#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ 8#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */
8#include <asm/types.h> 9#include <asm/types.h>
@@ -10,10 +11,22 @@
10struct page; 11struct page;
11struct kmem_cache; 12struct kmem_cache;
12 13
13typedef unsigned gfp_t; 14typedef enum {
15 GFP_KERNEL,
16 GFP_ATOMIC,
17 __GFP_HIGHMEM,
18 __GFP_HIGH
19} gfp_t;
14 20
15typedef __u64 u64; 21/*
16typedef __s64 s64; 22 * We define u64 as uint64_t for every architecture
23 * so that we can print it with "%"PRIx64 without getting warnings.
24 *
25 * typedef __u64 u64;
26 * typedef __s64 s64;
27 */
28typedef uint64_t u64;
29typedef int64_t s64;
17 30
18typedef __u32 u32; 31typedef __u32 u32;
19typedef __s32 s32; 32typedef __s32 s32;
@@ -35,6 +48,10 @@ typedef __s8 s8;
35#define __bitwise 48#define __bitwise
36#endif 49#endif
37 50
51#define __force
52#define __user
53#define __must_check
54#define __cold
38 55
39typedef __u16 __bitwise __le16; 56typedef __u16 __bitwise __le16;
40typedef __u16 __bitwise __be16; 57typedef __u16 __bitwise __be16;
@@ -55,4 +72,4 @@ struct hlist_node {
55 struct hlist_node *next, **pprev; 72 struct hlist_node *next, **pprev;
56}; 73};
57 74
58#endif 75#endif /* _TOOLS_LINUX_TYPES_H_ */
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile
index bba2f5253b6e..52f9279c6c13 100644
--- a/tools/lib/lockdep/Makefile
+++ b/tools/lib/lockdep/Makefile
@@ -104,7 +104,7 @@ N =
104 104
105export Q VERBOSE 105export Q VERBOSE
106 106
107INCLUDES = -I. -I/usr/local/include -I./uinclude -I./include $(CONFIG_INCLUDES) 107INCLUDES = -I. -I/usr/local/include -I./uinclude -I./include -I../../include $(CONFIG_INCLUDES)
108 108
109# Set compile option CFLAGS if not set elsewhere 109# Set compile option CFLAGS if not set elsewhere
110CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g 110CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g
diff --git a/tools/lib/lockdep/uinclude/linux/export.h b/tools/lib/lockdep/uinclude/linux/export.h
deleted file mode 100644
index 6bdf3492c535..000000000000
--- a/tools/lib/lockdep/uinclude/linux/export.h
+++ /dev/null
@@ -1,7 +0,0 @@
1#ifndef _LIBLOCKDEP_LINUX_EXPORT_H_
2#define _LIBLOCKDEP_LINUX_EXPORT_H_
3
4#define EXPORT_SYMBOL(sym)
5#define EXPORT_SYMBOL_GPL(sym)
6
7#endif
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index fdfceee0ffd0..b3b8abae62b8 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -33,21 +33,25 @@ OPTIONS
33-d:: 33-d::
34--dsos=:: 34--dsos=::
35 Only consider symbols in these dsos. CSV that understands 35 Only consider symbols in these dsos. CSV that understands
36 file://filename entries. 36 file://filename entries. This option will affect the percentage
37 of the Baseline/Delta column. See --percentage for more info.
37 38
38-C:: 39-C::
39--comms=:: 40--comms=::
40 Only consider symbols in these comms. CSV that understands 41 Only consider symbols in these comms. CSV that understands
41 file://filename entries. 42 file://filename entries. This option will affect the percentage
43 of the Baseline/Delta column. See --percentage for more info.
42 44
43-S:: 45-S::
44--symbols=:: 46--symbols=::
45 Only consider these symbols. CSV that understands 47 Only consider these symbols. CSV that understands
46 file://filename entries. 48 file://filename entries. This option will affect the percentage
49 of the Baseline/Delta column. See --percentage for more info.
47 50
48-s:: 51-s::
49--sort=:: 52--sort=::
50 Sort by key(s): pid, comm, dso, symbol. 53 Sort by key(s): pid, comm, dso, symbol, cpu, parent, srcline.
54 Please see description of --sort in the perf-report man page.
51 55
52-t:: 56-t::
53--field-separator=:: 57--field-separator=::
@@ -89,6 +93,14 @@ OPTIONS
89--order:: 93--order::
90 Specify compute sorting column number. 94 Specify compute sorting column number.
91 95
96--percentage::
97 Determine how to display the overhead percentage of filtered entries.
98 Filters can be applied by --comms, --dsos and/or --symbols options.
99
100 "relative" means it's relative to filtered entries only so that the
101 sum of shown entries will be always 100%. "absolute" means it retains
102 the original value before and after the filter is applied.
103
92COMPARISON 104COMPARISON
93---------- 105----------
94The comparison is governed by the baseline file. The baseline perf.data 106The comparison is governed by the baseline file. The baseline perf.data
@@ -157,6 +169,10 @@ with:
157 - period_percent being the % of the hist entry period value within 169 - period_percent being the % of the hist entry period value within
158 single data file 170 single data file
159 171
172 - with filtering by -C, -d and/or -S, period_percent might be changed
173 relative to how entries are filtered. Use --percentage=absolute to
174 prevent such fluctuation.
175
160ratio 176ratio
161~~~~~ 177~~~~~
162If specified the 'Ratio' column is displayed with value 'r' computed as: 178If specified the 'Ratio' column is displayed with value 'r' computed as:
@@ -187,4 +203,4 @@ If specified the 'Weighted diff' column is displayed with value 'd' computed as:
187 203
188SEE ALSO 204SEE ALSO
189-------- 205--------
190linkperf:perf-record[1] 206linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 8eab8a4bdeb8..a1b5185402d5 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -25,10 +25,6 @@ OPTIONS
25--verbose:: 25--verbose::
26 Be more verbose. (show symbol address, etc) 26 Be more verbose. (show symbol address, etc)
27 27
28-d::
29--dsos=::
30 Only consider symbols in these dsos. CSV that understands
31 file://filename entries.
32-n:: 28-n::
33--show-nr-samples:: 29--show-nr-samples::
34 Show the number of samples for each symbol 30 Show the number of samples for each symbol
@@ -42,11 +38,18 @@ OPTIONS
42-c:: 38-c::
43--comms=:: 39--comms=::
44 Only consider symbols in these comms. CSV that understands 40 Only consider symbols in these comms. CSV that understands
45 file://filename entries. 41 file://filename entries. This option will affect the percentage of
42 the overhead column. See --percentage for more info.
43-d::
44--dsos=::
45 Only consider symbols in these dsos. CSV that understands
46 file://filename entries. This option will affect the percentage of
47 the overhead column. See --percentage for more info.
46-S:: 48-S::
47--symbols=:: 49--symbols=::
48 Only consider these symbols. CSV that understands 50 Only consider these symbols. CSV that understands
49 file://filename entries. 51 file://filename entries. This option will affect the percentage of
52 the overhead column. See --percentage for more info.
50 53
51--symbol-filter=:: 54--symbol-filter=::
52 Only show symbols that match (partially) with this filter. 55 Only show symbols that match (partially) with this filter.
@@ -76,6 +79,15 @@ OPTIONS
76 abort cost. This is the global weight. 79 abort cost. This is the global weight.
77 - local_weight: Local weight version of the weight above. 80 - local_weight: Local weight version of the weight above.
78 - transaction: Transaction abort flags. 81 - transaction: Transaction abort flags.
82 - overhead: Overhead percentage of sample
83 - overhead_sys: Overhead percentage of sample running in system mode
84 - overhead_us: Overhead percentage of sample running in user mode
85 - overhead_guest_sys: Overhead percentage of sample running in system mode
86 on guest machine
87 - overhead_guest_us: Overhead percentage of sample running in user mode on
88 guest machine
89 - sample: Number of sample
90 - period: Raw number of event count of sample
79 91
80 By default, comm, dso and symbol keys are used. 92 By default, comm, dso and symbol keys are used.
81 (i.e. --sort comm,dso,symbol) 93 (i.e. --sort comm,dso,symbol)
@@ -95,6 +107,16 @@ OPTIONS
95 And default sort keys are changed to comm, dso_from, symbol_from, dso_to 107 And default sort keys are changed to comm, dso_from, symbol_from, dso_to
96 and symbol_to, see '--branch-stack'. 108 and symbol_to, see '--branch-stack'.
97 109
110-F::
111--fields=::
112 Specify output field - multiple keys can be specified in CSV format.
113 Following fields are available:
114 overhead, overhead_sys, overhead_us, sample and period.
115 Also it can contain any sort key(s).
116
117 By default, every sort keys not specified in -F will be appended
118 automatically.
119
98-p:: 120-p::
99--parent=<regex>:: 121--parent=<regex>::
100 A regex filter to identify parent. The parent is a caller of this 122 A regex filter to identify parent. The parent is a caller of this
@@ -237,6 +259,15 @@ OPTIONS
237 Do not show entries which have an overhead under that percent. 259 Do not show entries which have an overhead under that percent.
238 (Default: 0). 260 (Default: 0).
239 261
262--percentage::
263 Determine how to display the overhead percentage of filtered entries.
264 Filters can be applied by --comms, --dsos and/or --symbols options and
265 Zoom operations on the TUI (thread, dso, etc).
266
267 "relative" means it's relative to filtered entries only so that the
268 sum of shown entries will be always 100%. "absolute" means it retains
269 the original value before and after the filter is applied.
270
240--header:: 271--header::
241 Show header information in the perf.data file. This includes 272 Show header information in the perf.data file. This includes
242 various information like hostname, OS and perf version, cpu/mem 273 various information like hostname, OS and perf version, cpu/mem
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 976b00c6cdb1..dcfa54c851e9 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -113,7 +113,17 @@ Default is to monitor all CPUS.
113-s:: 113-s::
114--sort:: 114--sort::
115 Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight, 115 Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight,
116 local_weight, abort, in_tx, transaction 116 local_weight, abort, in_tx, transaction, overhead, sample, period.
117 Please see description of --sort in the perf-report man page.
118
119--fields=::
120 Specify output field - multiple keys can be specified in CSV format.
121 Following fields are available:
122 overhead, overhead_sys, overhead_us, sample and period.
123 Also it can contain any sort key(s).
124
125 By default, every sort keys not specified in --field will be appended
126 automatically.
117 127
118-n:: 128-n::
119--show-nr-samples:: 129--show-nr-samples::
@@ -123,13 +133,16 @@ Default is to monitor all CPUS.
123 Show a column with the sum of periods. 133 Show a column with the sum of periods.
124 134
125--dsos:: 135--dsos::
126 Only consider symbols in these dsos. 136 Only consider symbols in these dsos. This option will affect the
137 percentage of the overhead column. See --percentage for more info.
127 138
128--comms:: 139--comms::
129 Only consider symbols in these comms. 140 Only consider symbols in these comms. This option will affect the
141 percentage of the overhead column. See --percentage for more info.
130 142
131--symbols:: 143--symbols::
132 Only consider these symbols. 144 Only consider these symbols. This option will affect the
145 percentage of the overhead column. See --percentage for more info.
133 146
134-M:: 147-M::
135--disassembler-style=:: Set disassembler style for objdump. 148--disassembler-style=:: Set disassembler style for objdump.
@@ -165,6 +178,15 @@ Default is to monitor all CPUS.
165 Do not show entries which have an overhead under that percent. 178 Do not show entries which have an overhead under that percent.
166 (Default: 0). 179 (Default: 0).
167 180
181--percentage::
182 Determine how to display the overhead percentage of filtered entries.
183 Filters can be applied by --comms, --dsos and/or --symbols options and
184 Zoom operations on the TUI (thread, dso, etc).
185
186 "relative" means it's relative to filtered entries only so that the
187 sum of shown entries will be always 100%. "absolute" means it retains
188 the original value before and after the filter is applied.
189
168INTERACTIVE PROMPTING KEYS 190INTERACTIVE PROMPTING KEYS
169-------------------------- 191--------------------------
170 192
@@ -200,4 +222,4 @@ Pressing any unmapped key displays a menu, and prompts for input.
200 222
201SEE ALSO 223SEE ALSO
202-------- 224--------
203linkperf:perf-stat[1], linkperf:perf-list[1] 225linkperf:perf-stat[1], linkperf:perf-list[1], linkperf:perf-report[1]
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index c0c87c87b60f..45da209b6ed3 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -7,6 +7,8 @@ tools/lib/symbol/kallsyms.h
7tools/include/asm/bug.h 7tools/include/asm/bug.h
8tools/include/linux/compiler.h 8tools/include/linux/compiler.h
9tools/include/linux/hash.h 9tools/include/linux/hash.h
10tools/include/linux/export.h
11tools/include/linux/types.h
10include/linux/const.h 12include/linux/const.h
11include/linux/perf_event.h 13include/linux/perf_event.h
12include/linux/rbtree.h 14include/linux/rbtree.h
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 895edd32930c..02f0a4dd1a80 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -222,12 +222,12 @@ LIB_H += util/include/linux/const.h
222LIB_H += util/include/linux/ctype.h 222LIB_H += util/include/linux/ctype.h
223LIB_H += util/include/linux/kernel.h 223LIB_H += util/include/linux/kernel.h
224LIB_H += util/include/linux/list.h 224LIB_H += util/include/linux/list.h
225LIB_H += util/include/linux/export.h 225LIB_H += ../include/linux/export.h
226LIB_H += util/include/linux/poison.h 226LIB_H += util/include/linux/poison.h
227LIB_H += util/include/linux/rbtree.h 227LIB_H += util/include/linux/rbtree.h
228LIB_H += util/include/linux/rbtree_augmented.h 228LIB_H += util/include/linux/rbtree_augmented.h
229LIB_H += util/include/linux/string.h 229LIB_H += util/include/linux/string.h
230LIB_H += util/include/linux/types.h 230LIB_H += ../include/linux/types.h
231LIB_H += util/include/linux/linkage.h 231LIB_H += util/include/linux/linkage.h
232LIB_H += util/include/asm/asm-offsets.h 232LIB_H += util/include/asm/asm-offsets.h
233LIB_H += ../include/asm/bug.h 233LIB_H += ../include/asm/bug.h
@@ -252,7 +252,6 @@ LIB_H += util/event.h
252LIB_H += util/evsel.h 252LIB_H += util/evsel.h
253LIB_H += util/evlist.h 253LIB_H += util/evlist.h
254LIB_H += util/exec_cmd.h 254LIB_H += util/exec_cmd.h
255LIB_H += util/types.h
256LIB_H += util/levenshtein.h 255LIB_H += util/levenshtein.h
257LIB_H += util/machine.h 256LIB_H += util/machine.h
258LIB_H += util/map.h 257LIB_H += util/map.h
@@ -397,7 +396,10 @@ LIB_OBJS += $(OUTPUT)tests/rdpmc.o
397LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o 396LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
398LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o 397LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
399LIB_OBJS += $(OUTPUT)tests/pmu.o 398LIB_OBJS += $(OUTPUT)tests/pmu.o
399LIB_OBJS += $(OUTPUT)tests/hists_common.o
400LIB_OBJS += $(OUTPUT)tests/hists_link.o 400LIB_OBJS += $(OUTPUT)tests/hists_link.o
401LIB_OBJS += $(OUTPUT)tests/hists_filter.o
402LIB_OBJS += $(OUTPUT)tests/hists_output.o
401LIB_OBJS += $(OUTPUT)tests/python-use.o 403LIB_OBJS += $(OUTPUT)tests/python-use.o
402LIB_OBJS += $(OUTPUT)tests/bp_signal.o 404LIB_OBJS += $(OUTPUT)tests/bp_signal.o
403LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o 405LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
@@ -410,10 +412,12 @@ LIB_OBJS += $(OUTPUT)tests/code-reading.o
410LIB_OBJS += $(OUTPUT)tests/sample-parsing.o 412LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
411LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o 413LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
412ifndef NO_DWARF_UNWIND 414ifndef NO_DWARF_UNWIND
413ifeq ($(ARCH),x86) 415ifeq ($(ARCH),$(filter $(ARCH),x86 arm))
414LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o 416LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
415endif 417endif
416endif 418endif
419LIB_OBJS += $(OUTPUT)tests/mmap-thread-lookup.o
420LIB_OBJS += $(OUTPUT)tests/thread-mg-share.o
417 421
418BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 422BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
419BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 423BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile
index 67e9b3d38e89..09d62153d384 100644
--- a/tools/perf/arch/arm/Makefile
+++ b/tools/perf/arch/arm/Makefile
@@ -5,3 +5,10 @@ endif
5ifndef NO_LIBUNWIND 5ifndef NO_LIBUNWIND
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o 6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
7endif 7endif
8ifndef NO_LIBDW_DWARF_UNWIND
9LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libdw.o
10endif
11ifndef NO_DWARF_UNWIND
12LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
13LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
14endif
diff --git a/tools/perf/arch/arm/include/perf_regs.h b/tools/perf/arch/arm/include/perf_regs.h
index 2a1cfde66b69..f619c9c5a4bf 100644
--- a/tools/perf/arch/arm/include/perf_regs.h
+++ b/tools/perf/arch/arm/include/perf_regs.h
@@ -2,10 +2,15 @@
2#define ARCH_PERF_REGS_H 2#define ARCH_PERF_REGS_H
3 3
4#include <stdlib.h> 4#include <stdlib.h>
5#include "../../util/types.h" 5#include <linux/types.h>
6#include <asm/perf_regs.h> 6#include <asm/perf_regs.h>
7 7
8void perf_regs_load(u64 *regs);
9
8#define PERF_REGS_MASK ((1ULL << PERF_REG_ARM_MAX) - 1) 10#define PERF_REGS_MASK ((1ULL << PERF_REG_ARM_MAX) - 1)
11#define PERF_REGS_MAX PERF_REG_ARM_MAX
12#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
13
9#define PERF_REG_IP PERF_REG_ARM_PC 14#define PERF_REG_IP PERF_REG_ARM_PC
10#define PERF_REG_SP PERF_REG_ARM_SP 15#define PERF_REG_SP PERF_REG_ARM_SP
11 16
diff --git a/tools/perf/arch/arm/tests/dwarf-unwind.c b/tools/perf/arch/arm/tests/dwarf-unwind.c
new file mode 100644
index 000000000000..9f870d27cb39
--- /dev/null
+++ b/tools/perf/arch/arm/tests/dwarf-unwind.c
@@ -0,0 +1,60 @@
1#include <string.h>
2#include "perf_regs.h"
3#include "thread.h"
4#include "map.h"
5#include "event.h"
6#include "tests/tests.h"
7
8#define STACK_SIZE 8192
9
10static int sample_ustack(struct perf_sample *sample,
11 struct thread *thread, u64 *regs)
12{
13 struct stack_dump *stack = &sample->user_stack;
14 struct map *map;
15 unsigned long sp;
16 u64 stack_size, *buf;
17
18 buf = malloc(STACK_SIZE);
19 if (!buf) {
20 pr_debug("failed to allocate sample uregs data\n");
21 return -1;
22 }
23
24 sp = (unsigned long) regs[PERF_REG_ARM_SP];
25
26 map = map_groups__find(thread->mg, MAP__VARIABLE, (u64) sp);
27 if (!map) {
28 pr_debug("failed to get stack map\n");
29 free(buf);
30 return -1;
31 }
32
33 stack_size = map->end - sp;
34 stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
35
36 memcpy(buf, (void *) sp, stack_size);
37 stack->data = (char *) buf;
38 stack->size = stack_size;
39 return 0;
40}
41
42int test__arch_unwind_sample(struct perf_sample *sample,
43 struct thread *thread)
44{
45 struct regs_dump *regs = &sample->user_regs;
46 u64 *buf;
47
48 buf = calloc(1, sizeof(u64) * PERF_REGS_MAX);
49 if (!buf) {
50 pr_debug("failed to allocate sample uregs data\n");
51 return -1;
52 }
53
54 perf_regs_load(buf);
55 regs->abi = PERF_SAMPLE_REGS_ABI;
56 regs->regs = buf;
57 regs->mask = PERF_REGS_MASK;
58
59 return sample_ustack(sample, thread, buf);
60}
diff --git a/tools/perf/arch/arm/tests/regs_load.S b/tools/perf/arch/arm/tests/regs_load.S
new file mode 100644
index 000000000000..e09e983946fe
--- /dev/null
+++ b/tools/perf/arch/arm/tests/regs_load.S
@@ -0,0 +1,58 @@
1#include <linux/linkage.h>
2
3#define R0 0x00
4#define R1 0x08
5#define R2 0x10
6#define R3 0x18
7#define R4 0x20
8#define R5 0x28
9#define R6 0x30
10#define R7 0x38
11#define R8 0x40
12#define R9 0x48
13#define SL 0x50
14#define FP 0x58
15#define IP 0x60
16#define SP 0x68
17#define LR 0x70
18#define PC 0x78
19
20/*
21 * Implementation of void perf_regs_load(u64 *regs);
22 *
23 * This functions fills in the 'regs' buffer from the actual registers values,
24 * in the way the perf built-in unwinding test expects them:
25 * - the PC at the time at the call to this function. Since this function
26 * is called using a bl instruction, the PC value is taken from LR.
27 * The built-in unwinding test then unwinds the call stack from the dwarf
28 * information in unwind__get_entries.
29 *
30 * Notes:
31 * - the 8 bytes stride in the registers offsets comes from the fact
32 * that the registers are stored in an u64 array (u64 *regs),
33 * - the regs buffer needs to be zeroed before the call to this function,
34 * in this case using a calloc in dwarf-unwind.c.
35 */
36
37.text
38.type perf_regs_load,%function
39ENTRY(perf_regs_load)
40 str r0, [r0, #R0]
41 str r1, [r0, #R1]
42 str r2, [r0, #R2]
43 str r3, [r0, #R3]
44 str r4, [r0, #R4]
45 str r5, [r0, #R5]
46 str r6, [r0, #R6]
47 str r7, [r0, #R7]
48 str r8, [r0, #R8]
49 str r9, [r0, #R9]
50 str sl, [r0, #SL]
51 str fp, [r0, #FP]
52 str ip, [r0, #IP]
53 str sp, [r0, #SP]
54 str lr, [r0, #LR]
55 str lr, [r0, #PC] // store pc as lr in order to skip the call
56 // to this function
57 mov pc, lr
58ENDPROC(perf_regs_load)
diff --git a/tools/perf/arch/arm/util/unwind-libdw.c b/tools/perf/arch/arm/util/unwind-libdw.c
new file mode 100644
index 000000000000..b4176c60117a
--- /dev/null
+++ b/tools/perf/arch/arm/util/unwind-libdw.c
@@ -0,0 +1,36 @@
1#include <elfutils/libdwfl.h>
2#include "../../util/unwind-libdw.h"
3#include "../../util/perf_regs.h"
4
5bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
6{
7 struct unwind_info *ui = arg;
8 struct regs_dump *user_regs = &ui->sample->user_regs;
9 Dwarf_Word dwarf_regs[PERF_REG_ARM_MAX];
10
11#define REG(r) ({ \
12 Dwarf_Word val = 0; \
13 perf_reg_value(&val, user_regs, PERF_REG_ARM_##r); \
14 val; \
15})
16
17 dwarf_regs[0] = REG(R0);
18 dwarf_regs[1] = REG(R1);
19 dwarf_regs[2] = REG(R2);
20 dwarf_regs[3] = REG(R3);
21 dwarf_regs[4] = REG(R4);
22 dwarf_regs[5] = REG(R5);
23 dwarf_regs[6] = REG(R6);
24 dwarf_regs[7] = REG(R7);
25 dwarf_regs[8] = REG(R8);
26 dwarf_regs[9] = REG(R9);
27 dwarf_regs[10] = REG(R10);
28 dwarf_regs[11] = REG(FP);
29 dwarf_regs[12] = REG(IP);
30 dwarf_regs[13] = REG(SP);
31 dwarf_regs[14] = REG(LR);
32 dwarf_regs[15] = REG(PC);
33
34 return dwfl_thread_state_registers(thread, 0, PERF_REG_ARM_MAX,
35 dwarf_regs);
36}
diff --git a/tools/perf/arch/arm64/Makefile b/tools/perf/arch/arm64/Makefile
new file mode 100644
index 000000000000..67e9b3d38e89
--- /dev/null
+++ b/tools/perf/arch/arm64/Makefile
@@ -0,0 +1,7 @@
1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif
5ifndef NO_LIBUNWIND
6LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
7endif
diff --git a/tools/perf/arch/arm64/include/perf_regs.h b/tools/perf/arch/arm64/include/perf_regs.h
new file mode 100644
index 000000000000..e9441b9e2a30
--- /dev/null
+++ b/tools/perf/arch/arm64/include/perf_regs.h
@@ -0,0 +1,88 @@
1#ifndef ARCH_PERF_REGS_H
2#define ARCH_PERF_REGS_H
3
4#include <stdlib.h>
5#include <linux/types.h>
6#include <asm/perf_regs.h>
7
8#define PERF_REGS_MASK ((1ULL << PERF_REG_ARM64_MAX) - 1)
9#define PERF_REG_IP PERF_REG_ARM64_PC
10#define PERF_REG_SP PERF_REG_ARM64_SP
11
12static inline const char *perf_reg_name(int id)
13{
14 switch (id) {
15 case PERF_REG_ARM64_X0:
16 return "x0";
17 case PERF_REG_ARM64_X1:
18 return "x1";
19 case PERF_REG_ARM64_X2:
20 return "x2";
21 case PERF_REG_ARM64_X3:
22 return "x3";
23 case PERF_REG_ARM64_X4:
24 return "x4";
25 case PERF_REG_ARM64_X5:
26 return "x5";
27 case PERF_REG_ARM64_X6:
28 return "x6";
29 case PERF_REG_ARM64_X7:
30 return "x7";
31 case PERF_REG_ARM64_X8:
32 return "x8";
33 case PERF_REG_ARM64_X9:
34 return "x9";
35 case PERF_REG_ARM64_X10:
36 return "x10";
37 case PERF_REG_ARM64_X11:
38 return "x11";
39 case PERF_REG_ARM64_X12:
40 return "x12";
41 case PERF_REG_ARM64_X13:
42 return "x13";
43 case PERF_REG_ARM64_X14:
44 return "x14";
45 case PERF_REG_ARM64_X15:
46 return "x15";
47 case PERF_REG_ARM64_X16:
48 return "x16";
49 case PERF_REG_ARM64_X17:
50 return "x17";
51 case PERF_REG_ARM64_X18:
52 return "x18";
53 case PERF_REG_ARM64_X19:
54 return "x19";
55 case PERF_REG_ARM64_X20:
56 return "x20";
57 case PERF_REG_ARM64_X21:
58 return "x21";
59 case PERF_REG_ARM64_X22:
60 return "x22";
61 case PERF_REG_ARM64_X23:
62 return "x23";
63 case PERF_REG_ARM64_X24:
64 return "x24";
65 case PERF_REG_ARM64_X25:
66 return "x25";
67 case PERF_REG_ARM64_X26:
68 return "x26";
69 case PERF_REG_ARM64_X27:
70 return "x27";
71 case PERF_REG_ARM64_X28:
72 return "x28";
73 case PERF_REG_ARM64_X29:
74 return "x29";
75 case PERF_REG_ARM64_SP:
76 return "sp";
77 case PERF_REG_ARM64_LR:
78 return "lr";
79 case PERF_REG_ARM64_PC:
80 return "pc";
81 default:
82 return NULL;
83 }
84
85 return NULL;
86}
87
88#endif /* ARCH_PERF_REGS_H */
diff --git a/tools/perf/arch/arm64/util/dwarf-regs.c b/tools/perf/arch/arm64/util/dwarf-regs.c
new file mode 100644
index 000000000000..d49efeb8172e
--- /dev/null
+++ b/tools/perf/arch/arm64/util/dwarf-regs.c
@@ -0,0 +1,80 @@
1/*
2 * Mapping of DWARF debug register numbers into register names.
3 *
4 * Copyright (C) 2010 Will Deacon, ARM Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <stddef.h>
12#include <dwarf-regs.h>
13
14struct pt_regs_dwarfnum {
15 const char *name;
16 unsigned int dwarfnum;
17};
18
19#define STR(s) #s
20#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
21#define GPR_DWARFNUM_NAME(num) \
22 {.name = STR(%x##num), .dwarfnum = num}
23#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
24
25/*
26 * Reference:
27 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0057b/IHI0057B_aadwarf64.pdf
28 */
29static const struct pt_regs_dwarfnum regdwarfnum_table[] = {
30 GPR_DWARFNUM_NAME(0),
31 GPR_DWARFNUM_NAME(1),
32 GPR_DWARFNUM_NAME(2),
33 GPR_DWARFNUM_NAME(3),
34 GPR_DWARFNUM_NAME(4),
35 GPR_DWARFNUM_NAME(5),
36 GPR_DWARFNUM_NAME(6),
37 GPR_DWARFNUM_NAME(7),
38 GPR_DWARFNUM_NAME(8),
39 GPR_DWARFNUM_NAME(9),
40 GPR_DWARFNUM_NAME(10),
41 GPR_DWARFNUM_NAME(11),
42 GPR_DWARFNUM_NAME(12),
43 GPR_DWARFNUM_NAME(13),
44 GPR_DWARFNUM_NAME(14),
45 GPR_DWARFNUM_NAME(15),
46 GPR_DWARFNUM_NAME(16),
47 GPR_DWARFNUM_NAME(17),
48 GPR_DWARFNUM_NAME(18),
49 GPR_DWARFNUM_NAME(19),
50 GPR_DWARFNUM_NAME(20),
51 GPR_DWARFNUM_NAME(21),
52 GPR_DWARFNUM_NAME(22),
53 GPR_DWARFNUM_NAME(23),
54 GPR_DWARFNUM_NAME(24),
55 GPR_DWARFNUM_NAME(25),
56 GPR_DWARFNUM_NAME(26),
57 GPR_DWARFNUM_NAME(27),
58 GPR_DWARFNUM_NAME(28),
59 GPR_DWARFNUM_NAME(29),
60 REG_DWARFNUM_NAME("%lr", 30),
61 REG_DWARFNUM_NAME("%sp", 31),
62 REG_DWARFNUM_END,
63};
64
65/**
66 * get_arch_regstr() - lookup register name from it's DWARF register number
67 * @n: the DWARF register number
68 *
69 * get_arch_regstr() returns the name of the register in struct
70 * regdwarfnum_table from it's DWARF register number. If the register is not
71 * found in the table, this returns NULL;
72 */
73const char *get_arch_regstr(unsigned int n)
74{
75 const struct pt_regs_dwarfnum *roff;
76 for (roff = regdwarfnum_table; roff->name != NULL; roff++)
77 if (roff->dwarfnum == n)
78 return roff->name;
79 return NULL;
80}
diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c
new file mode 100644
index 000000000000..436ee43859dc
--- /dev/null
+++ b/tools/perf/arch/arm64/util/unwind-libunwind.c
@@ -0,0 +1,82 @@
1
2#include <errno.h>
3#include <libunwind.h>
4#include "perf_regs.h"
5#include "../../util/unwind.h"
6
7int libunwind__arch_reg_id(int regnum)
8{
9 switch (regnum) {
10 case UNW_AARCH64_X0:
11 return PERF_REG_ARM64_X0;
12 case UNW_AARCH64_X1:
13 return PERF_REG_ARM64_X1;
14 case UNW_AARCH64_X2:
15 return PERF_REG_ARM64_X2;
16 case UNW_AARCH64_X3:
17 return PERF_REG_ARM64_X3;
18 case UNW_AARCH64_X4:
19 return PERF_REG_ARM64_X4;
20 case UNW_AARCH64_X5:
21 return PERF_REG_ARM64_X5;
22 case UNW_AARCH64_X6:
23 return PERF_REG_ARM64_X6;
24 case UNW_AARCH64_X7:
25 return PERF_REG_ARM64_X7;
26 case UNW_AARCH64_X8:
27 return PERF_REG_ARM64_X8;
28 case UNW_AARCH64_X9:
29 return PERF_REG_ARM64_X9;
30 case UNW_AARCH64_X10:
31 return PERF_REG_ARM64_X10;
32 case UNW_AARCH64_X11:
33 return PERF_REG_ARM64_X11;
34 case UNW_AARCH64_X12:
35 return PERF_REG_ARM64_X12;
36 case UNW_AARCH64_X13:
37 return PERF_REG_ARM64_X13;
38 case UNW_AARCH64_X14:
39 return PERF_REG_ARM64_X14;
40 case UNW_AARCH64_X15:
41 return PERF_REG_ARM64_X15;
42 case UNW_AARCH64_X16:
43 return PERF_REG_ARM64_X16;
44 case UNW_AARCH64_X17:
45 return PERF_REG_ARM64_X17;
46 case UNW_AARCH64_X18:
47 return PERF_REG_ARM64_X18;
48 case UNW_AARCH64_X19:
49 return PERF_REG_ARM64_X19;
50 case UNW_AARCH64_X20:
51 return PERF_REG_ARM64_X20;
52 case UNW_AARCH64_X21:
53 return PERF_REG_ARM64_X21;
54 case UNW_AARCH64_X22:
55 return PERF_REG_ARM64_X22;
56 case UNW_AARCH64_X23:
57 return PERF_REG_ARM64_X23;
58 case UNW_AARCH64_X24:
59 return PERF_REG_ARM64_X24;
60 case UNW_AARCH64_X25:
61 return PERF_REG_ARM64_X25;
62 case UNW_AARCH64_X26:
63 return PERF_REG_ARM64_X26;
64 case UNW_AARCH64_X27:
65 return PERF_REG_ARM64_X27;
66 case UNW_AARCH64_X28:
67 return PERF_REG_ARM64_X28;
68 case UNW_AARCH64_X29:
69 return PERF_REG_ARM64_X29;
70 case UNW_AARCH64_X30:
71 return PERF_REG_ARM64_LR;
72 case UNW_AARCH64_SP:
73 return PERF_REG_ARM64_SP;
74 case UNW_AARCH64_PC:
75 return PERF_REG_ARM64_PC;
76 default:
77 pr_err("unwind: invalid reg id %d\n", regnum);
78 return -EINVAL;
79 }
80
81 return -EINVAL;
82}
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index fc819ca34a7e..7df517acfef8 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -2,7 +2,7 @@
2#define ARCH_PERF_REGS_H 2#define ARCH_PERF_REGS_H
3 3
4#include <stdlib.h> 4#include <stdlib.h>
5#include "../../util/types.h" 5#include <linux/types.h>
6#include <asm/perf_regs.h> 6#include <asm/perf_regs.h>
7 7
8void perf_regs_load(u64 *regs); 8void perf_regs_load(u64 *regs);
diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c
index 83bc2385e6d3..9f89f899ccc7 100644
--- a/tools/perf/arch/x86/tests/dwarf-unwind.c
+++ b/tools/perf/arch/x86/tests/dwarf-unwind.c
@@ -23,7 +23,7 @@ static int sample_ustack(struct perf_sample *sample,
23 23
24 sp = (unsigned long) regs[PERF_REG_X86_SP]; 24 sp = (unsigned long) regs[PERF_REG_X86_SP];
25 25
26 map = map_groups__find(&thread->mg, MAP__VARIABLE, (u64) sp); 26 map = map_groups__find(thread->mg, MAP__VARIABLE, (u64) sp);
27 if (!map) { 27 if (!map) {
28 pr_debug("failed to get stack map\n"); 28 pr_debug("failed to get stack map\n");
29 free(buf); 29 free(buf);
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c
index b2519e49424f..40021fa3129b 100644
--- a/tools/perf/arch/x86/util/tsc.c
+++ b/tools/perf/arch/x86/util/tsc.c
@@ -4,7 +4,7 @@
4#include <linux/perf_event.h> 4#include <linux/perf_event.h>
5 5
6#include "../../perf.h" 6#include "../../perf.h"
7#include "../../util/types.h" 7#include <linux/types.h>
8#include "../../util/debug.h" 8#include "../../util/debug.h"
9#include "tsc.h" 9#include "tsc.h"
10 10
diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h
index a24dec81c795..2affe0366b59 100644
--- a/tools/perf/arch/x86/util/tsc.h
+++ b/tools/perf/arch/x86/util/tsc.h
@@ -1,7 +1,7 @@
1#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ 1#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
2#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ 2#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
3 3
4#include "../../util/types.h" 4#include <linux/types.h>
5 5
6struct perf_tsc_conversion { 6struct perf_tsc_conversion {
7 u16 time_shift; 7 u16 time_shift;
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 0da603b79b61..d30d2c2e2a7a 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -46,7 +46,7 @@ struct perf_annotate {
46}; 46};
47 47
48static int perf_evsel__add_sample(struct perf_evsel *evsel, 48static int perf_evsel__add_sample(struct perf_evsel *evsel,
49 struct perf_sample *sample, 49 struct perf_sample *sample __maybe_unused,
50 struct addr_location *al, 50 struct addr_location *al,
51 struct perf_annotate *ann) 51 struct perf_annotate *ann)
52{ 52{
@@ -70,7 +70,6 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
70 return -ENOMEM; 70 return -ENOMEM;
71 71
72 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 72 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
73 evsel->hists.stats.total_period += sample->period;
74 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 73 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
75 return ret; 74 return ret;
76} 75}
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 204fffe22532..8bff543acaab 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -60,7 +60,6 @@ static int data__files_cnt;
60#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0) 60#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
61#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1) 61#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
62 62
63static char diff__default_sort_order[] = "dso,symbol";
64static bool force; 63static bool force;
65static bool show_period; 64static bool show_period;
66static bool show_formula; 65static bool show_formula;
@@ -220,7 +219,8 @@ static int setup_compute(const struct option *opt, const char *str,
220 219
221static double period_percent(struct hist_entry *he, u64 period) 220static double period_percent(struct hist_entry *he, u64 period)
222{ 221{
223 u64 total = he->hists->stats.total_period; 222 u64 total = hists__total_period(he->hists);
223
224 return (period * 100.0) / total; 224 return (period * 100.0) / total;
225} 225}
226 226
@@ -259,11 +259,18 @@ static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
259static int formula_delta(struct hist_entry *he, struct hist_entry *pair, 259static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
260 char *buf, size_t size) 260 char *buf, size_t size)
261{ 261{
262 u64 he_total = he->hists->stats.total_period;
263 u64 pair_total = pair->hists->stats.total_period;
264
265 if (symbol_conf.filter_relative) {
266 he_total = he->hists->stats.total_non_filtered_period;
267 pair_total = pair->hists->stats.total_non_filtered_period;
268 }
262 return scnprintf(buf, size, 269 return scnprintf(buf, size,
263 "(%" PRIu64 " * 100 / %" PRIu64 ") - " 270 "(%" PRIu64 " * 100 / %" PRIu64 ") - "
264 "(%" PRIu64 " * 100 / %" PRIu64 ")", 271 "(%" PRIu64 " * 100 / %" PRIu64 ")",
265 pair->stat.period, pair->hists->stats.total_period, 272 pair->stat.period, pair_total,
266 he->stat.period, he->hists->stats.total_period); 273 he->stat.period, he_total);
267} 274}
268 275
269static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, 276static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
@@ -327,16 +334,22 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
327 return -1; 334 return -1;
328 } 335 }
329 336
330 if (al.filtered)
331 return 0;
332
333 if (hists__add_entry(&evsel->hists, &al, sample->period, 337 if (hists__add_entry(&evsel->hists, &al, sample->period,
334 sample->weight, sample->transaction)) { 338 sample->weight, sample->transaction)) {
335 pr_warning("problem incrementing symbol period, skipping event\n"); 339 pr_warning("problem incrementing symbol period, skipping event\n");
336 return -1; 340 return -1;
337 } 341 }
338 342
343 /*
344 * The total_period is updated here before going to the output
345 * tree since normally only the baseline hists will call
346 * hists__output_resort() and precompute needs the total
347 * period in order to sort entries by percentage delta.
348 */
339 evsel->hists.stats.total_period += sample->period; 349 evsel->hists.stats.total_period += sample->period;
350 if (!al.filtered)
351 evsel->hists.stats.total_non_filtered_period += sample->period;
352
340 return 0; 353 return 0;
341} 354}
342 355
@@ -564,8 +577,7 @@ static void hists__compute_resort(struct hists *hists)
564 hists->entries = RB_ROOT; 577 hists->entries = RB_ROOT;
565 next = rb_first(root); 578 next = rb_first(root);
566 579
567 hists->nr_entries = 0; 580 hists__reset_stats(hists);
568 hists->stats.total_period = 0;
569 hists__reset_col_len(hists); 581 hists__reset_col_len(hists);
570 582
571 while (next != NULL) { 583 while (next != NULL) {
@@ -575,7 +587,10 @@ static void hists__compute_resort(struct hists *hists)
575 next = rb_next(&he->rb_node_in); 587 next = rb_next(&he->rb_node_in);
576 588
577 insert_hist_entry_by_compute(&hists->entries, he, compute); 589 insert_hist_entry_by_compute(&hists->entries, he, compute);
578 hists__inc_nr_entries(hists, he); 590 hists__inc_stats(hists, he);
591
592 if (!he->filtered)
593 hists__calc_col_len(hists, he);
579 } 594 }
580} 595}
581 596
@@ -725,20 +740,24 @@ static const struct option options[] = {
725 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", 740 OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
726 "only consider these symbols"), 741 "only consider these symbols"),
727 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 742 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
728 "sort by key(s): pid, comm, dso, symbol, parent"), 743 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
744 " Please refer the man page for the complete list."),
729 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", 745 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
730 "separator for columns, no spaces will be added between " 746 "separator for columns, no spaces will be added between "
731 "columns '.' is reserved."), 747 "columns '.' is reserved."),
732 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 748 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
733 "Look for files with symbols relative to this directory"), 749 "Look for files with symbols relative to this directory"),
734 OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), 750 OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
751 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
752 "How to display percentage of filtered entries", parse_filter_percentage),
735 OPT_END() 753 OPT_END()
736}; 754};
737 755
738static double baseline_percent(struct hist_entry *he) 756static double baseline_percent(struct hist_entry *he)
739{ 757{
740 struct hists *hists = he->hists; 758 u64 total = hists__total_period(he->hists);
741 return 100.0 * he->stat.period / hists->stats.total_period; 759
760 return 100.0 * he->stat.period / total;
742} 761}
743 762
744static int hpp__color_baseline(struct perf_hpp_fmt *fmt, 763static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
@@ -1120,7 +1139,8 @@ static int data_init(int argc, const char **argv)
1120 1139
1121int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) 1140int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1122{ 1141{
1123 sort_order = diff__default_sort_order; 1142 perf_config(perf_default_config, NULL);
1143
1124 argc = parse_options(argc, argv, options, diff_usage, 0); 1144 argc = parse_options(argc, argv, options, diff_usage, 0);
1125 1145
1126 if (symbol__init() < 0) 1146 if (symbol__init() < 0)
@@ -1131,6 +1151,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1131 1151
1132 ui_init(); 1152 ui_init();
1133 1153
1154 sort__mode = SORT_MODE__DIFF;
1155
1134 if (setup_sorting() < 0) 1156 if (setup_sorting() < 0)
1135 usage_with_options(diff_usage, options); 1157 usage_with_options(diff_usage, options);
1136 1158
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 3a7387551369..6a3af0013d68 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -209,7 +209,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
209 209
210 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 210 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
211 211
212 thread = machine__findnew_thread(machine, sample->pid, sample->pid); 212 thread = machine__findnew_thread(machine, sample->pid, sample->tid);
213 if (thread == NULL) { 213 if (thread == NULL) {
214 pr_err("problem processing %d event, skipping it.\n", 214 pr_err("problem processing %d event, skipping it.\n",
215 event->header.type); 215 event->header.type);
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 929462aa4943..bef3376bfaf3 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -14,6 +14,7 @@
14#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/trace-event.h" 15#include "util/trace-event.h"
16#include "util/data.h" 16#include "util/data.h"
17#include "util/cpumap.h"
17 18
18#include "util/debug.h" 19#include "util/debug.h"
19 20
@@ -31,9 +32,6 @@ static int caller_lines = -1;
31 32
32static bool raw_ip; 33static bool raw_ip;
33 34
34static int *cpunode_map;
35static int max_cpu_num;
36
37struct alloc_stat { 35struct alloc_stat {
38 u64 call_site; 36 u64 call_site;
39 u64 ptr; 37 u64 ptr;
@@ -55,76 +53,6 @@ static struct rb_root root_caller_sorted;
55static unsigned long total_requested, total_allocated; 53static unsigned long total_requested, total_allocated;
56static unsigned long nr_allocs, nr_cross_allocs; 54static unsigned long nr_allocs, nr_cross_allocs;
57 55
58#define PATH_SYS_NODE "/sys/devices/system/node"
59
60static int init_cpunode_map(void)
61{
62 FILE *fp;
63 int i, err = -1;
64
65 fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
66 if (!fp) {
67 max_cpu_num = 4096;
68 return 0;
69 }
70
71 if (fscanf(fp, "%d", &max_cpu_num) < 1) {
72 pr_err("Failed to read 'kernel_max' from sysfs");
73 goto out_close;
74 }
75
76 max_cpu_num++;
77
78 cpunode_map = calloc(max_cpu_num, sizeof(int));
79 if (!cpunode_map) {
80 pr_err("%s: calloc failed\n", __func__);
81 goto out_close;
82 }
83
84 for (i = 0; i < max_cpu_num; i++)
85 cpunode_map[i] = -1;
86
87 err = 0;
88out_close:
89 fclose(fp);
90 return err;
91}
92
93static int setup_cpunode_map(void)
94{
95 struct dirent *dent1, *dent2;
96 DIR *dir1, *dir2;
97 unsigned int cpu, mem;
98 char buf[PATH_MAX];
99
100 if (init_cpunode_map())
101 return -1;
102
103 dir1 = opendir(PATH_SYS_NODE);
104 if (!dir1)
105 return 0;
106
107 while ((dent1 = readdir(dir1)) != NULL) {
108 if (dent1->d_type != DT_DIR ||
109 sscanf(dent1->d_name, "node%u", &mem) < 1)
110 continue;
111
112 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
113 dir2 = opendir(buf);
114 if (!dir2)
115 continue;
116 while ((dent2 = readdir(dir2)) != NULL) {
117 if (dent2->d_type != DT_LNK ||
118 sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
119 continue;
120 cpunode_map[cpu] = mem;
121 }
122 closedir(dir2);
123 }
124 closedir(dir1);
125 return 0;
126}
127
128static int insert_alloc_stat(unsigned long call_site, unsigned long ptr, 56static int insert_alloc_stat(unsigned long call_site, unsigned long ptr,
129 int bytes_req, int bytes_alloc, int cpu) 57 int bytes_req, int bytes_alloc, int cpu)
130{ 58{
@@ -235,7 +163,7 @@ static int perf_evsel__process_alloc_node_event(struct perf_evsel *evsel,
235 int ret = perf_evsel__process_alloc_event(evsel, sample); 163 int ret = perf_evsel__process_alloc_event(evsel, sample);
236 164
237 if (!ret) { 165 if (!ret) {
238 int node1 = cpunode_map[sample->cpu], 166 int node1 = cpu__get_node(sample->cpu),
239 node2 = perf_evsel__intval(evsel, sample, "node"); 167 node2 = perf_evsel__intval(evsel, sample, "node");
240 168
241 if (node1 != node2) 169 if (node1 != node2)
@@ -307,7 +235,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
307 struct machine *machine) 235 struct machine *machine)
308{ 236{
309 struct thread *thread = machine__findnew_thread(machine, sample->pid, 237 struct thread *thread = machine__findnew_thread(machine, sample->pid,
310 sample->pid); 238 sample->tid);
311 239
312 if (thread == NULL) { 240 if (thread == NULL) {
313 pr_debug("problem processing %d event, skipping it.\n", 241 pr_debug("problem processing %d event, skipping it.\n",
@@ -756,11 +684,13 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
756 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), 684 OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
757 OPT_END() 685 OPT_END()
758 }; 686 };
759 const char * const kmem_usage[] = { 687 const char *const kmem_subcommands[] = { "record", "stat", NULL };
760 "perf kmem [<options>] {record|stat}", 688 const char *kmem_usage[] = {
689 NULL,
761 NULL 690 NULL
762 }; 691 };
763 argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); 692 argc = parse_options_subcommand(argc, argv, kmem_options,
693 kmem_subcommands, kmem_usage, 0);
764 694
765 if (!argc) 695 if (!argc)
766 usage_with_options(kmem_usage, kmem_options); 696 usage_with_options(kmem_usage, kmem_options);
@@ -770,7 +700,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
770 if (!strncmp(argv[0], "rec", 3)) { 700 if (!strncmp(argv[0], "rec", 3)) {
771 return __cmd_record(argc, argv); 701 return __cmd_record(argc, argv);
772 } else if (!strcmp(argv[0], "stat")) { 702 } else if (!strcmp(argv[0], "stat")) {
773 if (setup_cpunode_map()) 703 if (cpu__setup_cpunode_map())
774 return -1; 704 return -1;
775 705
776 if (list_empty(&caller_sort)) 706 if (list_empty(&caller_sort))
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index c852c7a85d32..6148afc995c6 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -961,8 +961,10 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
961 "perf lock info [<options>]", 961 "perf lock info [<options>]",
962 NULL 962 NULL
963 }; 963 };
964 const char * const lock_usage[] = { 964 const char *const lock_subcommands[] = { "record", "report", "script",
965 "perf lock [<options>] {record|report|script|info}", 965 "info", NULL };
966 const char *lock_usage[] = {
967 NULL,
966 NULL 968 NULL
967 }; 969 };
968 const char * const report_usage[] = { 970 const char * const report_usage[] = {
@@ -976,8 +978,8 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
976 for (i = 0; i < LOCKHASH_SIZE; i++) 978 for (i = 0; i < LOCKHASH_SIZE; i++)
977 INIT_LIST_HEAD(lockhash_table + i); 979 INIT_LIST_HEAD(lockhash_table + i);
978 980
979 argc = parse_options(argc, argv, lock_options, lock_usage, 981 argc = parse_options_subcommand(argc, argv, lock_options, lock_subcommands,
980 PARSE_OPT_STOP_AT_NON_OPTION); 982 lock_usage, PARSE_OPT_STOP_AT_NON_OPTION);
981 if (!argc) 983 if (!argc)
982 usage_with_options(lock_usage, lock_options); 984 usage_with_options(lock_usage, lock_options);
983 985
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 2e3ade69a58e..4a1a6c94a5eb 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -21,11 +21,6 @@ struct perf_mem {
21 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 21 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
22}; 22};
23 23
24static const char * const mem_usage[] = {
25 "perf mem [<options>] {record <command> |report}",
26 NULL
27};
28
29static int __cmd_record(int argc, const char **argv) 24static int __cmd_record(int argc, const char **argv)
30{ 25{
31 int rec_argc, i = 0, j; 26 int rec_argc, i = 0, j;
@@ -220,9 +215,15 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
220 " between columns '.' is reserved."), 215 " between columns '.' is reserved."),
221 OPT_END() 216 OPT_END()
222 }; 217 };
218 const char *const mem_subcommands[] = { "record", "report", NULL };
219 const char *mem_usage[] = {
220 NULL,
221 NULL
222 };
223
223 224
224 argc = parse_options(argc, argv, mem_options, mem_usage, 225 argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands,
225 PARSE_OPT_STOP_AT_NON_OPTION); 226 mem_usage, PARSE_OPT_STOP_AT_NON_OPTION);
226 227
227 if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation)) 228 if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation))
228 usage_with_options(mem_usage, mem_options); 229 usage_with_options(mem_usage, mem_options);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8ce62ef7f6c3..e4c85b8f46c2 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -30,37 +30,6 @@
30#include <sched.h> 30#include <sched.h>
31#include <sys/mman.h> 31#include <sys/mman.h>
32 32
33#ifndef HAVE_ON_EXIT_SUPPORT
34#ifndef ATEXIT_MAX
35#define ATEXIT_MAX 32
36#endif
37static int __on_exit_count = 0;
38typedef void (*on_exit_func_t) (int, void *);
39static on_exit_func_t __on_exit_funcs[ATEXIT_MAX];
40static void *__on_exit_args[ATEXIT_MAX];
41static int __exitcode = 0;
42static void __handle_on_exit_funcs(void);
43static int on_exit(on_exit_func_t function, void *arg);
44#define exit(x) (exit)(__exitcode = (x))
45
46static int on_exit(on_exit_func_t function, void *arg)
47{
48 if (__on_exit_count == ATEXIT_MAX)
49 return -ENOMEM;
50 else if (__on_exit_count == 0)
51 atexit(__handle_on_exit_funcs);
52 __on_exit_funcs[__on_exit_count] = function;
53 __on_exit_args[__on_exit_count++] = arg;
54 return 0;
55}
56
57static void __handle_on_exit_funcs(void)
58{
59 int i;
60 for (i = 0; i < __on_exit_count; i++)
61 __on_exit_funcs[i] (__exitcode, __on_exit_args[i]);
62}
63#endif
64 33
65struct record { 34struct record {
66 struct perf_tool tool; 35 struct perf_tool tool;
@@ -147,29 +116,19 @@ static void sig_handler(int sig)
147{ 116{
148 if (sig == SIGCHLD) 117 if (sig == SIGCHLD)
149 child_finished = 1; 118 child_finished = 1;
119 else
120 signr = sig;
150 121
151 done = 1; 122 done = 1;
152 signr = sig;
153} 123}
154 124
155static void record__sig_exit(int exit_status __maybe_unused, void *arg) 125static void record__sig_exit(void)
156{ 126{
157 struct record *rec = arg; 127 if (signr == -1)
158 int status;
159
160 if (rec->evlist->workload.pid > 0) {
161 if (!child_finished)
162 kill(rec->evlist->workload.pid, SIGTERM);
163
164 wait(&status);
165 if (WIFSIGNALED(status))
166 psignal(WTERMSIG(status), rec->progname);
167 }
168
169 if (signr == -1 || signr == SIGUSR1)
170 return; 128 return;
171 129
172 signal(signr, SIG_DFL); 130 signal(signr, SIG_DFL);
131 raise(signr);
173} 132}
174 133
175static int record__open(struct record *rec) 134static int record__open(struct record *rec)
@@ -243,27 +202,6 @@ static int process_buildids(struct record *rec)
243 size, &build_id__mark_dso_hit_ops); 202 size, &build_id__mark_dso_hit_ops);
244} 203}
245 204
246static void record__exit(int status, void *arg)
247{
248 struct record *rec = arg;
249 struct perf_data_file *file = &rec->file;
250
251 if (status != 0)
252 return;
253
254 if (!file->is_pipe) {
255 rec->session->header.data_size += rec->bytes_written;
256
257 if (!rec->no_buildid)
258 process_buildids(rec);
259 perf_session__write_header(rec->session, rec->evlist,
260 file->fd, true);
261 perf_session__delete(rec->session);
262 perf_evlist__delete(rec->evlist);
263 symbol__exit();
264 }
265}
266
267static void perf_event__synthesize_guest_os(struct machine *machine, void *data) 205static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
268{ 206{
269 int err; 207 int err;
@@ -344,18 +282,19 @@ static volatile int workload_exec_errno;
344 * if the fork fails, since we asked by setting its 282 * if the fork fails, since we asked by setting its
345 * want_signal to true. 283 * want_signal to true.
346 */ 284 */
347static void workload_exec_failed_signal(int signo, siginfo_t *info, 285static void workload_exec_failed_signal(int signo __maybe_unused,
286 siginfo_t *info,
348 void *ucontext __maybe_unused) 287 void *ucontext __maybe_unused)
349{ 288{
350 workload_exec_errno = info->si_value.sival_int; 289 workload_exec_errno = info->si_value.sival_int;
351 done = 1; 290 done = 1;
352 signr = signo;
353 child_finished = 1; 291 child_finished = 1;
354} 292}
355 293
356static int __cmd_record(struct record *rec, int argc, const char **argv) 294static int __cmd_record(struct record *rec, int argc, const char **argv)
357{ 295{
358 int err; 296 int err;
297 int status = 0;
359 unsigned long waking = 0; 298 unsigned long waking = 0;
360 const bool forks = argc > 0; 299 const bool forks = argc > 0;
361 struct machine *machine; 300 struct machine *machine;
@@ -367,7 +306,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
367 306
368 rec->progname = argv[0]; 307 rec->progname = argv[0];
369 308
370 on_exit(record__sig_exit, rec); 309 atexit(record__sig_exit);
371 signal(SIGCHLD, sig_handler); 310 signal(SIGCHLD, sig_handler);
372 signal(SIGINT, sig_handler); 311 signal(SIGINT, sig_handler);
373 signal(SIGTERM, sig_handler); 312 signal(SIGTERM, sig_handler);
@@ -388,32 +327,28 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
388 workload_exec_failed_signal); 327 workload_exec_failed_signal);
389 if (err < 0) { 328 if (err < 0) {
390 pr_err("Couldn't run the workload!\n"); 329 pr_err("Couldn't run the workload!\n");
330 status = err;
391 goto out_delete_session; 331 goto out_delete_session;
392 } 332 }
393 } 333 }
394 334
395 if (record__open(rec) != 0) { 335 if (record__open(rec) != 0) {
396 err = -1; 336 err = -1;
397 goto out_delete_session; 337 goto out_child;
398 } 338 }
399 339
400 if (!rec->evlist->nr_groups) 340 if (!rec->evlist->nr_groups)
401 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); 341 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
402 342
403 /*
404 * perf_session__delete(session) will be called at record__exit()
405 */
406 on_exit(record__exit, rec);
407
408 if (file->is_pipe) { 343 if (file->is_pipe) {
409 err = perf_header__write_pipe(file->fd); 344 err = perf_header__write_pipe(file->fd);
410 if (err < 0) 345 if (err < 0)
411 goto out_delete_session; 346 goto out_child;
412 } else { 347 } else {
413 err = perf_session__write_header(session, rec->evlist, 348 err = perf_session__write_header(session, rec->evlist,
414 file->fd, false); 349 file->fd, false);
415 if (err < 0) 350 if (err < 0)
416 goto out_delete_session; 351 goto out_child;
417 } 352 }
418 353
419 if (!rec->no_buildid 354 if (!rec->no_buildid
@@ -421,7 +356,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
421 pr_err("Couldn't generate buildids. " 356 pr_err("Couldn't generate buildids. "
422 "Use --no-buildid to profile anyway.\n"); 357 "Use --no-buildid to profile anyway.\n");
423 err = -1; 358 err = -1;
424 goto out_delete_session; 359 goto out_child;
425 } 360 }
426 361
427 machine = &session->machines.host; 362 machine = &session->machines.host;
@@ -431,7 +366,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
431 process_synthesized_event); 366 process_synthesized_event);
432 if (err < 0) { 367 if (err < 0) {
433 pr_err("Couldn't synthesize attrs.\n"); 368 pr_err("Couldn't synthesize attrs.\n");
434 goto out_delete_session; 369 goto out_child;
435 } 370 }
436 371
437 if (have_tracepoints(&rec->evlist->entries)) { 372 if (have_tracepoints(&rec->evlist->entries)) {
@@ -447,7 +382,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
447 process_synthesized_event); 382 process_synthesized_event);
448 if (err <= 0) { 383 if (err <= 0) {
449 pr_err("Couldn't record tracing data.\n"); 384 pr_err("Couldn't record tracing data.\n");
450 goto out_delete_session; 385 goto out_child;
451 } 386 }
452 rec->bytes_written += err; 387 rec->bytes_written += err;
453 } 388 }
@@ -475,7 +410,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
475 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads, 410 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
476 process_synthesized_event, opts->sample_address); 411 process_synthesized_event, opts->sample_address);
477 if (err != 0) 412 if (err != 0)
478 goto out_delete_session; 413 goto out_child;
479 414
480 if (rec->realtime_prio) { 415 if (rec->realtime_prio) {
481 struct sched_param param; 416 struct sched_param param;
@@ -484,7 +419,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
484 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 419 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
485 pr_err("Could not set realtime priority.\n"); 420 pr_err("Could not set realtime priority.\n");
486 err = -1; 421 err = -1;
487 goto out_delete_session; 422 goto out_child;
488 } 423 }
489 } 424 }
490 425
@@ -512,13 +447,15 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
512 447
513 if (record__mmap_read_all(rec) < 0) { 448 if (record__mmap_read_all(rec) < 0) {
514 err = -1; 449 err = -1;
515 goto out_delete_session; 450 goto out_child;
516 } 451 }
517 452
518 if (hits == rec->samples) { 453 if (hits == rec->samples) {
519 if (done) 454 if (done)
520 break; 455 break;
521 err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1); 456 err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1);
457 if (err < 0 && errno == EINTR)
458 err = 0;
522 waking++; 459 waking++;
523 } 460 }
524 461
@@ -538,28 +475,52 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
538 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); 475 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
539 pr_err("Workload failed: %s\n", emsg); 476 pr_err("Workload failed: %s\n", emsg);
540 err = -1; 477 err = -1;
541 goto out_delete_session; 478 goto out_child;
542 } 479 }
543 480
544 if (quiet || signr == SIGUSR1) 481 if (!quiet) {
545 return 0; 482 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
546 483
547 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); 484 /*
485 * Approximate RIP event size: 24 bytes.
486 */
487 fprintf(stderr,
488 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
489 (double)rec->bytes_written / 1024.0 / 1024.0,
490 file->path,
491 rec->bytes_written / 24);
492 }
548 493
549 /* 494out_child:
550 * Approximate RIP event size: 24 bytes. 495 if (forks) {
551 */ 496 int exit_status;
552 fprintf(stderr,
553 "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
554 (double)rec->bytes_written / 1024.0 / 1024.0,
555 file->path,
556 rec->bytes_written / 24);
557 497
558 return 0; 498 if (!child_finished)
499 kill(rec->evlist->workload.pid, SIGTERM);
500
501 wait(&exit_status);
502
503 if (err < 0)
504 status = err;
505 else if (WIFEXITED(exit_status))
506 status = WEXITSTATUS(exit_status);
507 else if (WIFSIGNALED(exit_status))
508 signr = WTERMSIG(exit_status);
509 } else
510 status = err;
511
512 if (!err && !file->is_pipe) {
513 rec->session->header.data_size += rec->bytes_written;
514
515 if (!rec->no_buildid)
516 process_buildids(rec);
517 perf_session__write_header(rec->session, rec->evlist,
518 file->fd, true);
519 }
559 520
560out_delete_session: 521out_delete_session:
561 perf_session__delete(session); 522 perf_session__delete(session);
562 return err; 523 return status;
563} 524}
564 525
565#define BRANCH_OPT(n, m) \ 526#define BRANCH_OPT(n, m) \
@@ -988,6 +949,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
988 949
989 err = __cmd_record(&record, argc, argv); 950 err = __cmd_record(&record, argc, argv);
990out_symbol_exit: 951out_symbol_exit:
952 perf_evlist__delete(rec->evlist);
991 symbol__exit(); 953 symbol__exit();
992 return err; 954 return err;
993} 955}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index c8f21137dfd8..bc0eec1ce4be 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -57,6 +57,7 @@ struct report {
57 const char *cpu_list; 57 const char *cpu_list;
58 const char *symbol_filter_str; 58 const char *symbol_filter_str;
59 float min_percent; 59 float min_percent;
60 u64 nr_entries;
60 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 61 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
61}; 62};
62 63
@@ -75,6 +76,27 @@ static int report__config(const char *var, const char *value, void *cb)
75 return perf_default_config(var, value, cb); 76 return perf_default_config(var, value, cb);
76} 77}
77 78
79static void report__inc_stats(struct report *rep, struct hist_entry *he)
80{
81 /*
82 * The @he is either of a newly created one or an existing one
83 * merging current sample. We only want to count a new one so
84 * checking ->nr_events being 1.
85 */
86 if (he->stat.nr_events == 1)
87 rep->nr_entries++;
88
89 /*
90 * Only counts number of samples at this stage as it's more
91 * natural to do it here and non-sample events are also
92 * counted in perf_session_deliver_event(). The dump_trace
93 * requires this info is ready before going to the output tree.
94 */
95 hists__inc_nr_events(he->hists, PERF_RECORD_SAMPLE);
96 if (!he->filtered)
97 he->hists->stats.nr_non_filtered_samples++;
98}
99
78static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al, 100static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al,
79 struct perf_sample *sample, struct perf_evsel *evsel) 101 struct perf_sample *sample, struct perf_evsel *evsel)
80{ 102{
@@ -121,8 +143,8 @@ static int report__add_mem_hist_entry(struct report *rep, struct addr_location *
121 goto out; 143 goto out;
122 } 144 }
123 145
124 evsel->hists.stats.total_period += cost; 146 report__inc_stats(rep, he);
125 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 147
126 err = hist_entry__append_callchain(he, sample); 148 err = hist_entry__append_callchain(he, sample);
127out: 149out:
128 return err; 150 return err;
@@ -173,9 +195,7 @@ static int report__add_branch_hist_entry(struct report *rep, struct addr_locatio
173 if (err) 195 if (err)
174 goto out; 196 goto out;
175 } 197 }
176 198 report__inc_stats(rep, he);
177 evsel->hists.stats.total_period += 1;
178 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
179 } else 199 } else
180 goto out; 200 goto out;
181 } 201 }
@@ -208,8 +228,8 @@ static int report__add_hist_entry(struct report *rep, struct perf_evsel *evsel,
208 if (ui__has_annotation()) 228 if (ui__has_annotation())
209 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 229 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
210 230
211 evsel->hists.stats.total_period += sample->period; 231 report__inc_stats(rep, he);
212 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 232
213out: 233out:
214 return err; 234 return err;
215} 235}
@@ -337,6 +357,11 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
337 char buf[512]; 357 char buf[512];
338 size_t size = sizeof(buf); 358 size_t size = sizeof(buf);
339 359
360 if (symbol_conf.filter_relative) {
361 nr_samples = hists->stats.nr_non_filtered_samples;
362 nr_events = hists->stats.total_non_filtered_period;
363 }
364
340 if (perf_evsel__is_group_event(evsel)) { 365 if (perf_evsel__is_group_event(evsel)) {
341 struct perf_evsel *pos; 366 struct perf_evsel *pos;
342 367
@@ -344,8 +369,13 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
344 evname = buf; 369 evname = buf;
345 370
346 for_each_group_member(pos, evsel) { 371 for_each_group_member(pos, evsel) {
347 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 372 if (symbol_conf.filter_relative) {
348 nr_events += pos->hists.stats.total_period; 373 nr_samples += pos->hists.stats.nr_non_filtered_samples;
374 nr_events += pos->hists.stats.total_non_filtered_period;
375 } else {
376 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
377 nr_events += pos->hists.stats.total_period;
378 }
349 } 379 }
350 } 380 }
351 381
@@ -470,24 +500,12 @@ static int report__browse_hists(struct report *rep)
470 return ret; 500 return ret;
471} 501}
472 502
473static u64 report__collapse_hists(struct report *rep) 503static void report__collapse_hists(struct report *rep)
474{ 504{
475 struct ui_progress prog; 505 struct ui_progress prog;
476 struct perf_evsel *pos; 506 struct perf_evsel *pos;
477 u64 nr_samples = 0;
478 /*
479 * Count number of histogram entries to use when showing progress,
480 * reusing nr_samples variable.
481 */
482 evlist__for_each(rep->session->evlist, pos)
483 nr_samples += pos->hists.nr_entries;
484 507
485 ui_progress__init(&prog, nr_samples, "Merging related events..."); 508 ui_progress__init(&prog, rep->nr_entries, "Merging related events...");
486 /*
487 * Count total number of samples, will be used to check if this
488 * session had any.
489 */
490 nr_samples = 0;
491 509
492 evlist__for_each(rep->session->evlist, pos) { 510 evlist__for_each(rep->session->evlist, pos) {
493 struct hists *hists = &pos->hists; 511 struct hists *hists = &pos->hists;
@@ -496,7 +514,6 @@ static u64 report__collapse_hists(struct report *rep)
496 hists->symbol_filter_str = rep->symbol_filter_str; 514 hists->symbol_filter_str = rep->symbol_filter_str;
497 515
498 hists__collapse_resort(hists, &prog); 516 hists__collapse_resort(hists, &prog);
499 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
500 517
501 /* Non-group events are considered as leader */ 518 /* Non-group events are considered as leader */
502 if (symbol_conf.event_group && 519 if (symbol_conf.event_group &&
@@ -509,14 +526,11 @@ static u64 report__collapse_hists(struct report *rep)
509 } 526 }
510 527
511 ui_progress__finish(); 528 ui_progress__finish();
512
513 return nr_samples;
514} 529}
515 530
516static int __cmd_report(struct report *rep) 531static int __cmd_report(struct report *rep)
517{ 532{
518 int ret; 533 int ret;
519 u64 nr_samples;
520 struct perf_session *session = rep->session; 534 struct perf_session *session = rep->session;
521 struct perf_evsel *pos; 535 struct perf_evsel *pos;
522 struct perf_data_file *file = session->file; 536 struct perf_data_file *file = session->file;
@@ -556,12 +570,12 @@ static int __cmd_report(struct report *rep)
556 } 570 }
557 } 571 }
558 572
559 nr_samples = report__collapse_hists(rep); 573 report__collapse_hists(rep);
560 574
561 if (session_done()) 575 if (session_done())
562 return 0; 576 return 0;
563 577
564 if (nr_samples == 0) { 578 if (rep->nr_entries == 0) {
565 ui__error("The %s file has no samples!\n", file->path); 579 ui__error("The %s file has no samples!\n", file->path);
566 return 0; 580 return 0;
567 } 581 }
@@ -573,11 +587,9 @@ static int __cmd_report(struct report *rep)
573} 587}
574 588
575static int 589static int
576parse_callchain_opt(const struct option *opt, const char *arg, int unset) 590report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
577{ 591{
578 struct report *rep = (struct report *)opt->value; 592 struct report *rep = (struct report *)opt->value;
579 char *tok, *tok2;
580 char *endptr;
581 593
582 /* 594 /*
583 * --no-call-graph 595 * --no-call-graph
@@ -587,80 +599,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
587 return 0; 599 return 0;
588 } 600 }
589 601
590 symbol_conf.use_callchain = true; 602 return parse_callchain_report_opt(arg);
591
592 if (!arg)
593 return 0;
594
595 tok = strtok((char *)arg, ",");
596 if (!tok)
597 return -1;
598
599 /* get the output mode */
600 if (!strncmp(tok, "graph", strlen(arg)))
601 callchain_param.mode = CHAIN_GRAPH_ABS;
602
603 else if (!strncmp(tok, "flat", strlen(arg)))
604 callchain_param.mode = CHAIN_FLAT;
605
606 else if (!strncmp(tok, "fractal", strlen(arg)))
607 callchain_param.mode = CHAIN_GRAPH_REL;
608
609 else if (!strncmp(tok, "none", strlen(arg))) {
610 callchain_param.mode = CHAIN_NONE;
611 symbol_conf.use_callchain = false;
612
613 return 0;
614 }
615
616 else
617 return -1;
618
619 /* get the min percentage */
620 tok = strtok(NULL, ",");
621 if (!tok)
622 goto setup;
623
624 callchain_param.min_percent = strtod(tok, &endptr);
625 if (tok == endptr)
626 return -1;
627
628 /* get the print limit */
629 tok2 = strtok(NULL, ",");
630 if (!tok2)
631 goto setup;
632
633 if (tok2[0] != 'c') {
634 callchain_param.print_limit = strtoul(tok2, &endptr, 0);
635 tok2 = strtok(NULL, ",");
636 if (!tok2)
637 goto setup;
638 }
639
640 /* get the call chain order */
641 if (!strncmp(tok2, "caller", strlen("caller")))
642 callchain_param.order = ORDER_CALLER;
643 else if (!strncmp(tok2, "callee", strlen("callee")))
644 callchain_param.order = ORDER_CALLEE;
645 else
646 return -1;
647
648 /* Get the sort key */
649 tok2 = strtok(NULL, ",");
650 if (!tok2)
651 goto setup;
652 if (!strncmp(tok2, "function", strlen("function")))
653 callchain_param.key = CCKEY_FUNCTION;
654 else if (!strncmp(tok2, "address", strlen("address")))
655 callchain_param.key = CCKEY_ADDRESS;
656 else
657 return -1;
658setup:
659 if (callchain_register_param(&callchain_param) < 0) {
660 pr_err("Can't register callchain params\n");
661 return -1;
662 }
663 return 0;
664} 603}
665 604
666int 605int
@@ -760,10 +699,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
760 OPT_BOOLEAN(0, "header-only", &report.header_only, 699 OPT_BOOLEAN(0, "header-only", &report.header_only,
761 "Show only data header."), 700 "Show only data header."),
762 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 701 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
763 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," 702 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
764 " dso_to, dso_from, symbol_to, symbol_from, mispredict," 703 " Please refer the man page for the complete list."),
765 " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, " 704 OPT_STRING('F', "fields", &field_order, "key[,keys...]",
766 "snoop, locked, abort, in_tx, transaction"), 705 "output field(s): overhead, period, sample plus all of sort keys"),
767 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 706 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
768 "Show sample percentage for different cpu modes"), 707 "Show sample percentage for different cpu modes"),
769 OPT_STRING('p', "parent", &parent_pattern, "regex", 708 OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -772,7 +711,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
772 "Only display entries with parent-match"), 711 "Only display entries with parent-match"),
773 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", 712 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
774 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). " 713 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
775 "Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt), 714 "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt),
776 OPT_INTEGER(0, "max-stack", &report.max_stack, 715 OPT_INTEGER(0, "max-stack", &report.max_stack,
777 "Set the maximum stack depth when parsing the callchain, " 716 "Set the maximum stack depth when parsing the callchain, "
778 "anything beyond the specified depth will be ignored. " 717 "anything beyond the specified depth will be ignored. "
@@ -823,6 +762,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
823 OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"), 762 OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
824 OPT_CALLBACK(0, "percent-limit", &report, "percent", 763 OPT_CALLBACK(0, "percent-limit", &report, "percent",
825 "Don't show entries under that percent", parse_percent_limit), 764 "Don't show entries under that percent", parse_percent_limit),
765 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
766 "how to display percentage of filtered entries", parse_filter_percentage),
826 OPT_END() 767 OPT_END()
827 }; 768 };
828 struct perf_data_file file = { 769 struct perf_data_file file = {
@@ -866,52 +807,31 @@ repeat:
866 if (branch_mode == -1 && has_br_stack) 807 if (branch_mode == -1 && has_br_stack)
867 sort__mode = SORT_MODE__BRANCH; 808 sort__mode = SORT_MODE__BRANCH;
868 809
869 /* sort__mode could be NORMAL if --no-branch-stack */
870 if (sort__mode == SORT_MODE__BRANCH) {
871 /*
872 * if no sort_order is provided, then specify
873 * branch-mode specific order
874 */
875 if (sort_order == default_sort_order)
876 sort_order = "comm,dso_from,symbol_from,"
877 "dso_to,symbol_to";
878
879 }
880 if (report.mem_mode) { 810 if (report.mem_mode) {
881 if (sort__mode == SORT_MODE__BRANCH) { 811 if (sort__mode == SORT_MODE__BRANCH) {
882 pr_err("branch and mem mode incompatible\n"); 812 pr_err("branch and mem mode incompatible\n");
883 goto error; 813 goto error;
884 } 814 }
885 sort__mode = SORT_MODE__MEMORY; 815 sort__mode = SORT_MODE__MEMORY;
886
887 /*
888 * if no sort_order is provided, then specify
889 * branch-mode specific order
890 */
891 if (sort_order == default_sort_order)
892 sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
893 } 816 }
894 817
895 if (setup_sorting() < 0) { 818 if (setup_sorting() < 0) {
896 parse_options_usage(report_usage, options, "s", 1); 819 if (sort_order)
820 parse_options_usage(report_usage, options, "s", 1);
821 if (field_order)
822 parse_options_usage(sort_order ? NULL : report_usage,
823 options, "F", 1);
897 goto error; 824 goto error;
898 } 825 }
899 826
900 if (parent_pattern != default_parent_pattern) {
901 if (sort_dimension__add("parent") < 0)
902 goto error;
903 }
904
905 /* Force tty output for header output. */ 827 /* Force tty output for header output. */
906 if (report.header || report.header_only) 828 if (report.header || report.header_only)
907 use_browser = 0; 829 use_browser = 0;
908 830
909 if (strcmp(input_name, "-") != 0) 831 if (strcmp(input_name, "-") != 0)
910 setup_browser(true); 832 setup_browser(true);
911 else { 833 else
912 use_browser = 0; 834 use_browser = 0;
913 perf_hpp__init();
914 }
915 835
916 if (report.header || report.header_only) { 836 if (report.header || report.header_only) {
917 perf_session__fprintf_info(session, stdout, 837 perf_session__fprintf_info(session, stdout,
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 9ac0a495c954..d7176830b9b2 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -66,7 +66,7 @@ struct sched_atom {
66 struct task_desc *wakee; 66 struct task_desc *wakee;
67}; 67};
68 68
69#define TASK_STATE_TO_CHAR_STR "RSDTtZX" 69#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKWP"
70 70
71enum thread_state { 71enum thread_state {
72 THREAD_SLEEPING = 0, 72 THREAD_SLEEPING = 0,
@@ -149,7 +149,6 @@ struct perf_sched {
149 unsigned long nr_runs; 149 unsigned long nr_runs;
150 unsigned long nr_timestamps; 150 unsigned long nr_timestamps;
151 unsigned long nr_unordered_timestamps; 151 unsigned long nr_unordered_timestamps;
152 unsigned long nr_state_machine_bugs;
153 unsigned long nr_context_switch_bugs; 152 unsigned long nr_context_switch_bugs;
154 unsigned long nr_events; 153 unsigned long nr_events;
155 unsigned long nr_lost_chunks; 154 unsigned long nr_lost_chunks;
@@ -1007,17 +1006,12 @@ static int latency_wakeup_event(struct perf_sched *sched,
1007 struct perf_sample *sample, 1006 struct perf_sample *sample,
1008 struct machine *machine) 1007 struct machine *machine)
1009{ 1008{
1010 const u32 pid = perf_evsel__intval(evsel, sample, "pid"), 1009 const u32 pid = perf_evsel__intval(evsel, sample, "pid");
1011 success = perf_evsel__intval(evsel, sample, "success");
1012 struct work_atoms *atoms; 1010 struct work_atoms *atoms;
1013 struct work_atom *atom; 1011 struct work_atom *atom;
1014 struct thread *wakee; 1012 struct thread *wakee;
1015 u64 timestamp = sample->time; 1013 u64 timestamp = sample->time;
1016 1014
1017 /* Note for later, it may be interesting to observe the failing cases */
1018 if (!success)
1019 return 0;
1020
1021 wakee = machine__findnew_thread(machine, 0, pid); 1015 wakee = machine__findnew_thread(machine, 0, pid);
1022 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); 1016 atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
1023 if (!atoms) { 1017 if (!atoms) {
@@ -1037,12 +1031,18 @@ static int latency_wakeup_event(struct perf_sched *sched,
1037 atom = list_entry(atoms->work_list.prev, struct work_atom, list); 1031 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1038 1032
1039 /* 1033 /*
1034 * As we do not guarantee the wakeup event happens when
1035 * task is out of run queue, also may happen when task is
1036 * on run queue and wakeup only change ->state to TASK_RUNNING,
1037 * then we should not set the ->wake_up_time when wake up a
1038 * task which is on run queue.
1039 *
1040 * You WILL be missing events if you've recorded only 1040 * You WILL be missing events if you've recorded only
1041 * one CPU, or are only looking at only one, so don't 1041 * one CPU, or are only looking at only one, so don't
1042 * make useless noise. 1042 * skip in this case.
1043 */ 1043 */
1044 if (sched->profile_cpu == -1 && atom->state != THREAD_SLEEPING) 1044 if (sched->profile_cpu == -1 && atom->state != THREAD_SLEEPING)
1045 sched->nr_state_machine_bugs++; 1045 return 0;
1046 1046
1047 sched->nr_timestamps++; 1047 sched->nr_timestamps++;
1048 if (atom->sched_out_time > timestamp) { 1048 if (atom->sched_out_time > timestamp) {
@@ -1266,9 +1266,8 @@ static int process_sched_wakeup_event(struct perf_tool *tool,
1266static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, 1266static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1267 struct perf_sample *sample, struct machine *machine) 1267 struct perf_sample *sample, struct machine *machine)
1268{ 1268{
1269 const u32 prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"), 1269 const u32 next_pid = perf_evsel__intval(evsel, sample, "next_pid");
1270 next_pid = perf_evsel__intval(evsel, sample, "next_pid"); 1270 struct thread *sched_in;
1271 struct thread *sched_out __maybe_unused, *sched_in;
1272 int new_shortname; 1271 int new_shortname;
1273 u64 timestamp0, timestamp = sample->time; 1272 u64 timestamp0, timestamp = sample->time;
1274 s64 delta; 1273 s64 delta;
@@ -1291,7 +1290,6 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1291 return -1; 1290 return -1;
1292 } 1291 }
1293 1292
1294 sched_out = machine__findnew_thread(machine, 0, prev_pid);
1295 sched_in = machine__findnew_thread(machine, 0, next_pid); 1293 sched_in = machine__findnew_thread(machine, 0, next_pid);
1296 1294
1297 sched->curr_thread[this_cpu] = sched_in; 1295 sched->curr_thread[this_cpu] = sched_in;
@@ -1300,17 +1298,25 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1300 1298
1301 new_shortname = 0; 1299 new_shortname = 0;
1302 if (!sched_in->shortname[0]) { 1300 if (!sched_in->shortname[0]) {
1303 sched_in->shortname[0] = sched->next_shortname1; 1301 if (!strcmp(thread__comm_str(sched_in), "swapper")) {
1304 sched_in->shortname[1] = sched->next_shortname2; 1302 /*
1305 1303 * Don't allocate a letter-number for swapper:0
1306 if (sched->next_shortname1 < 'Z') { 1304 * as a shortname. Instead, we use '.' for it.
1307 sched->next_shortname1++; 1305 */
1306 sched_in->shortname[0] = '.';
1307 sched_in->shortname[1] = ' ';
1308 } else { 1308 } else {
1309 sched->next_shortname1='A'; 1309 sched_in->shortname[0] = sched->next_shortname1;
1310 if (sched->next_shortname2 < '9') { 1310 sched_in->shortname[1] = sched->next_shortname2;
1311 sched->next_shortname2++; 1311
1312 if (sched->next_shortname1 < 'Z') {
1313 sched->next_shortname1++;
1312 } else { 1314 } else {
1313 sched->next_shortname2='0'; 1315 sched->next_shortname1 = 'A';
1316 if (sched->next_shortname2 < '9')
1317 sched->next_shortname2++;
1318 else
1319 sched->next_shortname2 = '0';
1314 } 1320 }
1315 } 1321 }
1316 new_shortname = 1; 1322 new_shortname = 1;
@@ -1322,12 +1328,9 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
1322 else 1328 else
1323 printf("*"); 1329 printf("*");
1324 1330
1325 if (sched->curr_thread[cpu]) { 1331 if (sched->curr_thread[cpu])
1326 if (sched->curr_thread[cpu]->tid) 1332 printf("%2s ", sched->curr_thread[cpu]->shortname);
1327 printf("%2s ", sched->curr_thread[cpu]->shortname); 1333 else
1328 else
1329 printf(". ");
1330 } else
1331 printf(" "); 1334 printf(" ");
1332 } 1335 }
1333 1336
@@ -1496,14 +1499,6 @@ static void print_bad_events(struct perf_sched *sched)
1496 (double)sched->nr_lost_events/(double)sched->nr_events * 100.0, 1499 (double)sched->nr_lost_events/(double)sched->nr_events * 100.0,
1497 sched->nr_lost_events, sched->nr_events, sched->nr_lost_chunks); 1500 sched->nr_lost_events, sched->nr_events, sched->nr_lost_chunks);
1498 } 1501 }
1499 if (sched->nr_state_machine_bugs && sched->nr_timestamps) {
1500 printf(" INFO: %.3f%% state machine bugs (%ld out of %ld)",
1501 (double)sched->nr_state_machine_bugs/(double)sched->nr_timestamps*100.0,
1502 sched->nr_state_machine_bugs, sched->nr_timestamps);
1503 if (sched->nr_lost_events)
1504 printf(" (due to lost events?)");
1505 printf("\n");
1506 }
1507 if (sched->nr_context_switch_bugs && sched->nr_timestamps) { 1502 if (sched->nr_context_switch_bugs && sched->nr_timestamps) {
1508 printf(" INFO: %.3f%% context switch bugs (%ld out of %ld)", 1503 printf(" INFO: %.3f%% context switch bugs (%ld out of %ld)",
1509 (double)sched->nr_context_switch_bugs/(double)sched->nr_timestamps*100.0, 1504 (double)sched->nr_context_switch_bugs/(double)sched->nr_timestamps*100.0,
@@ -1635,6 +1630,7 @@ static int __cmd_record(int argc, const char **argv)
1635 "-e", "sched:sched_stat_runtime", 1630 "-e", "sched:sched_stat_runtime",
1636 "-e", "sched:sched_process_fork", 1631 "-e", "sched:sched_process_fork",
1637 "-e", "sched:sched_wakeup", 1632 "-e", "sched:sched_wakeup",
1633 "-e", "sched:sched_wakeup_new",
1638 "-e", "sched:sched_migrate_task", 1634 "-e", "sched:sched_migrate_task",
1639 }; 1635 };
1640 1636
@@ -1713,8 +1709,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1713 "perf sched replay [<options>]", 1709 "perf sched replay [<options>]",
1714 NULL 1710 NULL
1715 }; 1711 };
1716 const char * const sched_usage[] = { 1712 const char *const sched_subcommands[] = { "record", "latency", "map",
1717 "perf sched [<options>] {record|latency|map|replay|script}", 1713 "replay", "script", NULL };
1714 const char *sched_usage[] = {
1715 NULL,
1718 NULL 1716 NULL
1719 }; 1717 };
1720 struct trace_sched_handler lat_ops = { 1718 struct trace_sched_handler lat_ops = {
@@ -1736,8 +1734,8 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1736 for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++) 1734 for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++)
1737 sched.curr_pid[i] = -1; 1735 sched.curr_pid[i] = -1;
1738 1736
1739 argc = parse_options(argc, argv, sched_options, sched_usage, 1737 argc = parse_options_subcommand(argc, argv, sched_options, sched_subcommands,
1740 PARSE_OPT_STOP_AT_NON_OPTION); 1738 sched_usage, PARSE_OPT_STOP_AT_NON_OPTION);
1741 if (!argc) 1739 if (!argc)
1742 usage_with_options(sched_usage, sched_options); 1740 usage_with_options(sched_usage, sched_options);
1743 1741
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 65aaa5bbf7ec..5b389ce4cd15 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -253,6 +253,9 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
253 return NULL; 253 return NULL;
254 254
255 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 255 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
256 if (!he->filtered)
257 evsel->hists.stats.nr_non_filtered_samples++;
258
256 return he; 259 return he;
257} 260}
258 261
@@ -694,8 +697,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
694 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) 697 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
695 top->exact_samples++; 698 top->exact_samples++;
696 699
697 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0 || 700 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0)
698 al.filtered)
699 return; 701 return;
700 702
701 if (!top->kptr_restrict_warned && 703 if (!top->kptr_restrict_warned &&
@@ -1081,8 +1083,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1081 OPT_INCR('v', "verbose", &verbose, 1083 OPT_INCR('v', "verbose", &verbose,
1082 "be more verbose (show counter open errors, etc)"), 1084 "be more verbose (show counter open errors, etc)"),
1083 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1085 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1084 "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight," 1086 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
1085 " abort, in_tx, transaction"), 1087 " Please refer the man page for the complete list."),
1088 OPT_STRING(0, "fields", &field_order, "key[,keys...]",
1089 "output field(s): overhead, period, sample plus all of sort keys"),
1086 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1090 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1087 "Show a column with the number of samples"), 1091 "Show a column with the number of samples"),
1088 OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts, 1092 OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts,
@@ -1116,6 +1120,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1116 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), 1120 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
1117 OPT_CALLBACK(0, "percent-limit", &top, "percent", 1121 OPT_CALLBACK(0, "percent-limit", &top, "percent",
1118 "Don't show entries under that percent", parse_percent_limit), 1122 "Don't show entries under that percent", parse_percent_limit),
1123 OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
1124 "How to display percentage of filtered entries", parse_filter_percentage),
1119 OPT_END() 1125 OPT_END()
1120 }; 1126 };
1121 const char * const top_usage[] = { 1127 const char * const top_usage[] = {
@@ -1133,17 +1139,19 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1133 if (argc) 1139 if (argc)
1134 usage_with_options(top_usage, options); 1140 usage_with_options(top_usage, options);
1135 1141
1136 if (sort_order == default_sort_order) 1142 sort__mode = SORT_MODE__TOP;
1137 sort_order = "dso,symbol"; 1143 /* display thread wants entries to be collapsed in a different tree */
1144 sort__need_collapse = 1;
1138 1145
1139 if (setup_sorting() < 0) { 1146 if (setup_sorting() < 0) {
1140 parse_options_usage(top_usage, options, "s", 1); 1147 if (sort_order)
1148 parse_options_usage(top_usage, options, "s", 1);
1149 if (field_order)
1150 parse_options_usage(sort_order ? NULL : top_usage,
1151 options, "fields", 0);
1141 goto out_delete_evlist; 1152 goto out_delete_evlist;
1142 } 1153 }
1143 1154
1144 /* display thread wants entries to be collapsed in a different tree */
1145 sort__need_collapse = 1;
1146
1147 if (top.use_stdio) 1155 if (top.use_stdio)
1148 use_browser = 0; 1156 use_browser = 0;
1149 else if (top.use_tui) 1157 else if (top.use_tui)
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 802cf544202b..729bbdf5cec7 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -29,16 +29,22 @@ ifeq ($(ARCH),x86)
29 endif 29 endif
30 NO_PERF_REGS := 0 30 NO_PERF_REGS := 0
31endif 31endif
32
32ifeq ($(ARCH),arm) 33ifeq ($(ARCH),arm)
33 NO_PERF_REGS := 0 34 NO_PERF_REGS := 0
34 LIBUNWIND_LIBS = -lunwind -lunwind-arm 35 LIBUNWIND_LIBS = -lunwind -lunwind-arm
35endif 36endif
36 37
37# So far there's only x86 libdw unwind support merged in perf. 38ifeq ($(ARCH),arm64)
39 NO_PERF_REGS := 0
40 LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
41endif
42
43# So far there's only x86 and arm libdw unwind support merged in perf.
38# Disable it on all other architectures in case libdw unwind 44# Disable it on all other architectures in case libdw unwind
39# support is detected in system. Add supported architectures 45# support is detected in system. Add supported architectures
40# to the check. 46# to the check.
41ifneq ($(ARCH),x86) 47ifneq ($(ARCH),$(filter $(ARCH),x86 arm))
42 NO_LIBDW_DWARF_UNWIND := 1 48 NO_LIBDW_DWARF_UNWIND := 1
43endif 49endif
44 50
@@ -168,7 +174,6 @@ CORE_FEATURE_TESTS = \
168 libpython-version \ 174 libpython-version \
169 libslang \ 175 libslang \
170 libunwind \ 176 libunwind \
171 on-exit \
172 stackprotector-all \ 177 stackprotector-all \
173 timerfd \ 178 timerfd \
174 libdw-dwarf-unwind 179 libdw-dwarf-unwind
@@ -194,7 +199,6 @@ VF_FEATURE_TESTS = \
194 libelf-getphdrnum \ 199 libelf-getphdrnum \
195 libelf-mmap \ 200 libelf-mmap \
196 libpython-version \ 201 libpython-version \
197 on-exit \
198 stackprotector-all \ 202 stackprotector-all \
199 timerfd \ 203 timerfd \
200 libunwind-debug-frame \ 204 libunwind-debug-frame \
@@ -370,7 +374,7 @@ else
370endif 374endif
371 375
372ifndef NO_LIBUNWIND 376ifndef NO_LIBUNWIND
373 ifeq ($(ARCH),arm) 377 ifeq ($(ARCH),$(filter $(ARCH),arm arm64))
374 $(call feature_check,libunwind-debug-frame) 378 $(call feature_check,libunwind-debug-frame)
375 ifneq ($(feature-libunwind-debug-frame), 1) 379 ifneq ($(feature-libunwind-debug-frame), 1)
376 msg := $(warning No debug_frame support found in libunwind); 380 msg := $(warning No debug_frame support found in libunwind);
@@ -565,12 +569,6 @@ ifneq ($(filter -lbfd,$(EXTLIBS)),)
565 CFLAGS += -DHAVE_LIBBFD_SUPPORT 569 CFLAGS += -DHAVE_LIBBFD_SUPPORT
566endif 570endif
567 571
568ifndef NO_ON_EXIT
569 ifeq ($(feature-on-exit), 1)
570 CFLAGS += -DHAVE_ON_EXIT_SUPPORT
571 endif
572endif
573
574ifndef NO_BACKTRACE 572ifndef NO_BACKTRACE
575 ifeq ($(feature-backtrace), 1) 573 ifeq ($(feature-backtrace), 1)
576 CFLAGS += -DHAVE_BACKTRACE_SUPPORT 574 CFLAGS += -DHAVE_BACKTRACE_SUPPORT
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 2da103c53f89..64c84e5f0514 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -24,7 +24,6 @@ FILES= \
24 test-libslang.bin \ 24 test-libslang.bin \
25 test-libunwind.bin \ 25 test-libunwind.bin \
26 test-libunwind-debug-frame.bin \ 26 test-libunwind-debug-frame.bin \
27 test-on-exit.bin \
28 test-stackprotector-all.bin \ 27 test-stackprotector-all.bin \
29 test-timerfd.bin \ 28 test-timerfd.bin \
30 test-libdw-dwarf-unwind.bin 29 test-libdw-dwarf-unwind.bin
@@ -133,9 +132,6 @@ test-liberty-z.bin:
133test-cplus-demangle.bin: 132test-cplus-demangle.bin:
134 $(BUILD) -liberty 133 $(BUILD) -liberty
135 134
136test-on-exit.bin:
137 $(BUILD)
138
139test-backtrace.bin: 135test-backtrace.bin:
140 $(BUILD) 136 $(BUILD)
141 137
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index fc37eb3ca17b..fe5c1e5c952f 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -69,10 +69,6 @@
69# include "test-libbfd.c" 69# include "test-libbfd.c"
70#undef main 70#undef main
71 71
72#define main main_test_on_exit
73# include "test-on-exit.c"
74#undef main
75
76#define main main_test_backtrace 72#define main main_test_backtrace
77# include "test-backtrace.c" 73# include "test-backtrace.c"
78#undef main 74#undef main
@@ -110,7 +106,6 @@ int main(int argc, char *argv[])
110 main_test_gtk2(argc, argv); 106 main_test_gtk2(argc, argv);
111 main_test_gtk2_infobar(argc, argv); 107 main_test_gtk2_infobar(argc, argv);
112 main_test_libbfd(); 108 main_test_libbfd();
113 main_test_on_exit();
114 main_test_backtrace(); 109 main_test_backtrace();
115 main_test_libnuma(); 110 main_test_libnuma();
116 main_test_timerfd(); 111 main_test_timerfd();
diff --git a/tools/perf/config/feature-checks/test-on-exit.c b/tools/perf/config/feature-checks/test-on-exit.c
deleted file mode 100644
index 8e88b16e6ded..000000000000
--- a/tools/perf/config/feature-checks/test-on-exit.c
+++ /dev/null
@@ -1,16 +0,0 @@
1#include <stdio.h>
2#include <stdlib.h>
3
4static void exit_fn(int status, void *__data)
5{
6 printf("exit status: %d, data: %d\n", status, *(int *)__data);
7}
8
9static int data = 123;
10
11int main(void)
12{
13 on_exit(exit_fn, &data);
14
15 return 321;
16}
diff --git a/tools/perf/perf-completion.sh b/tools/perf/perf-completion.sh
index ae3a57694b6b..33569847fdcc 100644
--- a/tools/perf/perf-completion.sh
+++ b/tools/perf/perf-completion.sh
@@ -121,8 +121,8 @@ __perf_main ()
121 elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then 121 elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then
122 evts=$($cmd list --raw-dump) 122 evts=$($cmd list --raw-dump)
123 __perfcomp_colon "$evts" "$cur" 123 __perfcomp_colon "$evts" "$cur"
124 # List subcommands for 'perf kvm' 124 # List subcommands for perf commands
125 elif [[ $prev == "kvm" ]]; then 125 elif [[ $prev == @(kvm|kmem|mem|lock|sched) ]]; then
126 subcmds=$($cmd $prev --list-cmds) 126 subcmds=$($cmd $prev --list-cmds)
127 __perfcomp_colon "$subcmds" "$cur" 127 __perfcomp_colon "$subcmds" "$cur"
128 # List long option names 128 # List long option names
diff --git a/tools/perf/perf-sys.h b/tools/perf/perf-sys.h
new file mode 100644
index 000000000000..5268a1481d23
--- /dev/null
+++ b/tools/perf/perf-sys.h
@@ -0,0 +1,190 @@
1#ifndef _PERF_SYS_H
2#define _PERF_SYS_H
3
4#include <unistd.h>
5#include <sys/types.h>
6#include <sys/syscall.h>
7#include <linux/types.h>
8#include <linux/perf_event.h>
9#include <asm/unistd.h>
10
11#if defined(__i386__)
12#define mb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
13#define wmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
14#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
15#define cpu_relax() asm volatile("rep; nop" ::: "memory");
16#define CPUINFO_PROC "model name"
17#ifndef __NR_perf_event_open
18# define __NR_perf_event_open 336
19#endif
20#ifndef __NR_futex
21# define __NR_futex 240
22#endif
23#ifndef __NR_gettid
24# define __NR_gettid 224
25#endif
26#endif
27
28#if defined(__x86_64__)
29#define mb() asm volatile("mfence" ::: "memory")
30#define wmb() asm volatile("sfence" ::: "memory")
31#define rmb() asm volatile("lfence" ::: "memory")
32#define cpu_relax() asm volatile("rep; nop" ::: "memory");
33#define CPUINFO_PROC "model name"
34#ifndef __NR_perf_event_open
35# define __NR_perf_event_open 298
36#endif
37#ifndef __NR_futex
38# define __NR_futex 202
39#endif
40#ifndef __NR_gettid
41# define __NR_gettid 186
42#endif
43#endif
44
45#ifdef __powerpc__
46#include "../../arch/powerpc/include/uapi/asm/unistd.h"
47#define mb() asm volatile ("sync" ::: "memory")
48#define wmb() asm volatile ("sync" ::: "memory")
49#define rmb() asm volatile ("sync" ::: "memory")
50#define CPUINFO_PROC "cpu"
51#endif
52
53#ifdef __s390__
54#define mb() asm volatile("bcr 15,0" ::: "memory")
55#define wmb() asm volatile("bcr 15,0" ::: "memory")
56#define rmb() asm volatile("bcr 15,0" ::: "memory")
57#endif
58
59#ifdef __sh__
60#if defined(__SH4A__) || defined(__SH5__)
61# define mb() asm volatile("synco" ::: "memory")
62# define wmb() asm volatile("synco" ::: "memory")
63# define rmb() asm volatile("synco" ::: "memory")
64#else
65# define mb() asm volatile("" ::: "memory")
66# define wmb() asm volatile("" ::: "memory")
67# define rmb() asm volatile("" ::: "memory")
68#endif
69#define CPUINFO_PROC "cpu type"
70#endif
71
72#ifdef __hppa__
73#define mb() asm volatile("" ::: "memory")
74#define wmb() asm volatile("" ::: "memory")
75#define rmb() asm volatile("" ::: "memory")
76#define CPUINFO_PROC "cpu"
77#endif
78
79#ifdef __sparc__
80#ifdef __LP64__
81#define mb() asm volatile("ba,pt %%xcc, 1f\n" \
82 "membar #StoreLoad\n" \
83 "1:\n":::"memory")
84#else
85#define mb() asm volatile("":::"memory")
86#endif
87#define wmb() asm volatile("":::"memory")
88#define rmb() asm volatile("":::"memory")
89#define CPUINFO_PROC "cpu"
90#endif
91
92#ifdef __alpha__
93#define mb() asm volatile("mb" ::: "memory")
94#define wmb() asm volatile("wmb" ::: "memory")
95#define rmb() asm volatile("mb" ::: "memory")
96#define CPUINFO_PROC "cpu model"
97#endif
98
99#ifdef __ia64__
100#define mb() asm volatile ("mf" ::: "memory")
101#define wmb() asm volatile ("mf" ::: "memory")
102#define rmb() asm volatile ("mf" ::: "memory")
103#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
104#define CPUINFO_PROC "model name"
105#endif
106
107#ifdef __arm__
108/*
109 * Use the __kuser_memory_barrier helper in the CPU helper page. See
110 * arch/arm/kernel/entry-armv.S in the kernel source for details.
111 */
112#define mb() ((void(*)(void))0xffff0fa0)()
113#define wmb() ((void(*)(void))0xffff0fa0)()
114#define rmb() ((void(*)(void))0xffff0fa0)()
115#define CPUINFO_PROC "Processor"
116#endif
117
118#ifdef __aarch64__
119#define mb() asm volatile("dmb ish" ::: "memory")
120#define wmb() asm volatile("dmb ishst" ::: "memory")
121#define rmb() asm volatile("dmb ishld" ::: "memory")
122#define cpu_relax() asm volatile("yield" ::: "memory")
123#endif
124
125#ifdef __mips__
126#define mb() asm volatile( \
127 ".set mips2\n\t" \
128 "sync\n\t" \
129 ".set mips0" \
130 : /* no output */ \
131 : /* no input */ \
132 : "memory")
133#define wmb() mb()
134#define rmb() mb()
135#define CPUINFO_PROC "cpu model"
136#endif
137
138#ifdef __arc__
139#define mb() asm volatile("" ::: "memory")
140#define wmb() asm volatile("" ::: "memory")
141#define rmb() asm volatile("" ::: "memory")
142#define CPUINFO_PROC "Processor"
143#endif
144
145#ifdef __metag__
146#define mb() asm volatile("" ::: "memory")
147#define wmb() asm volatile("" ::: "memory")
148#define rmb() asm volatile("" ::: "memory")
149#define CPUINFO_PROC "CPU"
150#endif
151
152#ifdef __xtensa__
153#define mb() asm volatile("memw" ::: "memory")
154#define wmb() asm volatile("memw" ::: "memory")
155#define rmb() asm volatile("" ::: "memory")
156#define CPUINFO_PROC "core ID"
157#endif
158
159#ifdef __tile__
160#define mb() asm volatile ("mf" ::: "memory")
161#define wmb() asm volatile ("mf" ::: "memory")
162#define rmb() asm volatile ("mf" ::: "memory")
163#define cpu_relax() asm volatile ("mfspr zero, PASS" ::: "memory")
164#define CPUINFO_PROC "model name"
165#endif
166
167#define barrier() asm volatile ("" ::: "memory")
168
169#ifndef cpu_relax
170#define cpu_relax() barrier()
171#endif
172
173static inline int
174sys_perf_event_open(struct perf_event_attr *attr,
175 pid_t pid, int cpu, int group_fd,
176 unsigned long flags)
177{
178 int fd;
179
180 fd = syscall(__NR_perf_event_open, attr, pid, cpu,
181 group_fd, flags);
182
183#ifdef HAVE_ATTR_TEST
184 if (unlikely(test_attr__enabled))
185 test_attr__open(attr, pid, cpu, fd, group_fd, flags);
186#endif
187 return fd;
188}
189
190#endif /* _PERF_SYS_H */
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 5c11ecad02a9..510c65f72858 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -1,182 +1,18 @@
1#ifndef _PERF_PERF_H 1#ifndef _PERF_PERF_H
2#define _PERF_PERF_H 2#define _PERF_PERF_H
3 3
4#include <asm/unistd.h>
5
6#if defined(__i386__)
7#define mb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
8#define wmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
9#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
10#define cpu_relax() asm volatile("rep; nop" ::: "memory");
11#define CPUINFO_PROC "model name"
12#ifndef __NR_perf_event_open
13# define __NR_perf_event_open 336
14#endif
15#ifndef __NR_futex
16# define __NR_futex 240
17#endif
18#endif
19
20#if defined(__x86_64__)
21#define mb() asm volatile("mfence" ::: "memory")
22#define wmb() asm volatile("sfence" ::: "memory")
23#define rmb() asm volatile("lfence" ::: "memory")
24#define cpu_relax() asm volatile("rep; nop" ::: "memory");
25#define CPUINFO_PROC "model name"
26#ifndef __NR_perf_event_open
27# define __NR_perf_event_open 298
28#endif
29#ifndef __NR_futex
30# define __NR_futex 202
31#endif
32#endif
33
34#ifdef __powerpc__
35#include "../../arch/powerpc/include/uapi/asm/unistd.h"
36#define mb() asm volatile ("sync" ::: "memory")
37#define wmb() asm volatile ("sync" ::: "memory")
38#define rmb() asm volatile ("sync" ::: "memory")
39#define CPUINFO_PROC "cpu"
40#endif
41
42#ifdef __s390__
43#define mb() asm volatile("bcr 15,0" ::: "memory")
44#define wmb() asm volatile("bcr 15,0" ::: "memory")
45#define rmb() asm volatile("bcr 15,0" ::: "memory")
46#endif
47
48#ifdef __sh__
49#if defined(__SH4A__) || defined(__SH5__)
50# define mb() asm volatile("synco" ::: "memory")
51# define wmb() asm volatile("synco" ::: "memory")
52# define rmb() asm volatile("synco" ::: "memory")
53#else
54# define mb() asm volatile("" ::: "memory")
55# define wmb() asm volatile("" ::: "memory")
56# define rmb() asm volatile("" ::: "memory")
57#endif
58#define CPUINFO_PROC "cpu type"
59#endif
60
61#ifdef __hppa__
62#define mb() asm volatile("" ::: "memory")
63#define wmb() asm volatile("" ::: "memory")
64#define rmb() asm volatile("" ::: "memory")
65#define CPUINFO_PROC "cpu"
66#endif
67
68#ifdef __sparc__
69#ifdef __LP64__
70#define mb() asm volatile("ba,pt %%xcc, 1f\n" \
71 "membar #StoreLoad\n" \
72 "1:\n":::"memory")
73#else
74#define mb() asm volatile("":::"memory")
75#endif
76#define wmb() asm volatile("":::"memory")
77#define rmb() asm volatile("":::"memory")
78#define CPUINFO_PROC "cpu"
79#endif
80
81#ifdef __alpha__
82#define mb() asm volatile("mb" ::: "memory")
83#define wmb() asm volatile("wmb" ::: "memory")
84#define rmb() asm volatile("mb" ::: "memory")
85#define CPUINFO_PROC "cpu model"
86#endif
87
88#ifdef __ia64__
89#define mb() asm volatile ("mf" ::: "memory")
90#define wmb() asm volatile ("mf" ::: "memory")
91#define rmb() asm volatile ("mf" ::: "memory")
92#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
93#define CPUINFO_PROC "model name"
94#endif
95
96#ifdef __arm__
97/*
98 * Use the __kuser_memory_barrier helper in the CPU helper page. See
99 * arch/arm/kernel/entry-armv.S in the kernel source for details.
100 */
101#define mb() ((void(*)(void))0xffff0fa0)()
102#define wmb() ((void(*)(void))0xffff0fa0)()
103#define rmb() ((void(*)(void))0xffff0fa0)()
104#define CPUINFO_PROC "Processor"
105#endif
106
107#ifdef __aarch64__
108#define mb() asm volatile("dmb ish" ::: "memory")
109#define wmb() asm volatile("dmb ishst" ::: "memory")
110#define rmb() asm volatile("dmb ishld" ::: "memory")
111#define cpu_relax() asm volatile("yield" ::: "memory")
112#endif
113
114#ifdef __mips__
115#define mb() asm volatile( \
116 ".set mips2\n\t" \
117 "sync\n\t" \
118 ".set mips0" \
119 : /* no output */ \
120 : /* no input */ \
121 : "memory")
122#define wmb() mb()
123#define rmb() mb()
124#define CPUINFO_PROC "cpu model"
125#endif
126
127#ifdef __arc__
128#define mb() asm volatile("" ::: "memory")
129#define wmb() asm volatile("" ::: "memory")
130#define rmb() asm volatile("" ::: "memory")
131#define CPUINFO_PROC "Processor"
132#endif
133
134#ifdef __metag__
135#define mb() asm volatile("" ::: "memory")
136#define wmb() asm volatile("" ::: "memory")
137#define rmb() asm volatile("" ::: "memory")
138#define CPUINFO_PROC "CPU"
139#endif
140
141#ifdef __xtensa__
142#define mb() asm volatile("memw" ::: "memory")
143#define wmb() asm volatile("memw" ::: "memory")
144#define rmb() asm volatile("" ::: "memory")
145#define CPUINFO_PROC "core ID"
146#endif
147
148#ifdef __tile__
149#define mb() asm volatile ("mf" ::: "memory")
150#define wmb() asm volatile ("mf" ::: "memory")
151#define rmb() asm volatile ("mf" ::: "memory")
152#define cpu_relax() asm volatile ("mfspr zero, PASS" ::: "memory")
153#define CPUINFO_PROC "model name"
154#endif
155
156#define barrier() asm volatile ("" ::: "memory")
157
158#ifndef cpu_relax
159#define cpu_relax() barrier()
160#endif
161
162#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
163
164
165#include <time.h> 4#include <time.h>
166#include <unistd.h>
167#include <sys/types.h>
168#include <sys/syscall.h>
169
170#include <linux/perf_event.h>
171#include "util/types.h"
172#include <stdbool.h> 5#include <stdbool.h>
6#include <linux/types.h>
7#include <linux/perf_event.h>
173 8
174/* 9extern bool test_attr__enabled;
175 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all 10void test_attr__init(void);
176 * counters in the current task. 11void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
177 */ 12 int fd, int group_fd, unsigned long flags);
178#define PR_TASK_PERF_EVENTS_DISABLE 31 13
179#define PR_TASK_PERF_EVENTS_ENABLE 32 14#define HAVE_ATTR_TEST
15#include "perf-sys.h"
180 16
181#ifndef NSEC_PER_SEC 17#ifndef NSEC_PER_SEC
182# define NSEC_PER_SEC 1000000000ULL 18# define NSEC_PER_SEC 1000000000ULL
@@ -193,67 +29,8 @@ static inline unsigned long long rdclock(void)
193 return ts.tv_sec * 1000000000ULL + ts.tv_nsec; 29 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
194} 30}
195 31
196/*
197 * Pick up some kernel type conventions:
198 */
199#define __user
200#define asmlinkage
201
202#define unlikely(x) __builtin_expect(!!(x), 0)
203#define min(x, y) ({ \
204 typeof(x) _min1 = (x); \
205 typeof(y) _min2 = (y); \
206 (void) (&_min1 == &_min2); \
207 _min1 < _min2 ? _min1 : _min2; })
208
209extern bool test_attr__enabled;
210void test_attr__init(void);
211void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
212 int fd, int group_fd, unsigned long flags);
213
214static inline int
215sys_perf_event_open(struct perf_event_attr *attr,
216 pid_t pid, int cpu, int group_fd,
217 unsigned long flags)
218{
219 int fd;
220
221 fd = syscall(__NR_perf_event_open, attr, pid, cpu,
222 group_fd, flags);
223
224 if (unlikely(test_attr__enabled))
225 test_attr__open(attr, pid, cpu, fd, group_fd, flags);
226
227 return fd;
228}
229
230#define MAX_COUNTERS 256
231#define MAX_NR_CPUS 256 32#define MAX_NR_CPUS 256
232 33
233struct ip_callchain {
234 u64 nr;
235 u64 ips[0];
236};
237
238struct branch_flags {
239 u64 mispred:1;
240 u64 predicted:1;
241 u64 in_tx:1;
242 u64 abort:1;
243 u64 reserved:60;
244};
245
246struct branch_entry {
247 u64 from;
248 u64 to;
249 struct branch_flags flags;
250};
251
252struct branch_stack {
253 u64 nr;
254 struct branch_entry entries[0];
255};
256
257extern const char *input_name; 34extern const char *input_name;
258extern bool perf_host, perf_guest; 35extern bool perf_host, perf_guest;
259extern const char perf_version_string[]; 36extern const char perf_version_string[];
@@ -262,13 +39,6 @@ void pthread__unblock_sigwinch(void);
262 39
263#include "util/target.h" 40#include "util/target.h"
264 41
265enum perf_call_graph_mode {
266 CALLCHAIN_NONE,
267 CALLCHAIN_FP,
268 CALLCHAIN_DWARF,
269 CALLCHAIN_MAX
270};
271
272struct record_opts { 42struct record_opts {
273 struct target target; 43 struct target target;
274 int call_graph; 44 int call_graph;
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
index 00218f503b2e..2dfc9ad0e6f2 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -1,4 +1,3 @@
1
2/* 1/*
3 * The struct perf_event_attr test support. 2 * The struct perf_event_attr test support.
4 * 3 *
@@ -19,14 +18,8 @@
19 * permissions. All the event text files are stored there. 18 * permissions. All the event text files are stored there.
20 */ 19 */
21 20
22/*
23 * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
24 * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
25 */
26#define __SANE_USERSPACE_TYPES__
27#include <stdlib.h> 21#include <stdlib.h>
28#include <stdio.h> 22#include <stdio.h>
29#include <inttypes.h>
30#include <linux/types.h> 23#include <linux/types.h>
31#include <linux/kernel.h> 24#include <linux/kernel.h>
32#include "../perf.h" 25#include "../perf.h"
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index b11bf8a08430..831f52cae197 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -115,7 +115,7 @@ static struct test {
115 .desc = "Test parsing with no sample_id_all bit set", 115 .desc = "Test parsing with no sample_id_all bit set",
116 .func = test__parse_no_sample_id_all, 116 .func = test__parse_no_sample_id_all,
117 }, 117 },
118#if defined(__x86_64__) || defined(__i386__) 118#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
119#ifdef HAVE_DWARF_UNWIND_SUPPORT 119#ifdef HAVE_DWARF_UNWIND_SUPPORT
120 { 120 {
121 .desc = "Test dwarf unwind", 121 .desc = "Test dwarf unwind",
@@ -124,6 +124,22 @@ static struct test {
124#endif 124#endif
125#endif 125#endif
126 { 126 {
127 .desc = "Test filtering hist entries",
128 .func = test__hists_filter,
129 },
130 {
131 .desc = "Test mmap thread lookup",
132 .func = test__mmap_thread_lookup,
133 },
134 {
135 .desc = "Test thread mg sharing",
136 .func = test__thread_mg_share,
137 },
138 {
139 .desc = "Test output sorting of hist entries",
140 .func = test__hists_output,
141 },
142 {
127 .func = NULL, 143 .func = NULL,
128 }, 144 },
129}; 145};
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index bfb186900ac0..67f2d6323558 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -1,8 +1,7 @@
1#include <sys/types.h> 1#include <linux/types.h>
2#include <stdlib.h> 2#include <stdlib.h>
3#include <unistd.h> 3#include <unistd.h>
4#include <stdio.h> 4#include <stdio.h>
5#include <inttypes.h>
6#include <ctype.h> 5#include <ctype.h>
7#include <string.h> 6#include <string.h>
8 7
@@ -257,7 +256,7 @@ static int process_sample_event(struct machine *machine,
257 return -1; 256 return -1;
258 } 257 }
259 258
260 thread = machine__findnew_thread(machine, sample.pid, sample.pid); 259 thread = machine__findnew_thread(machine, sample.pid, sample.tid);
261 if (!thread) { 260 if (!thread) {
262 pr_debug("machine__findnew_thread failed\n"); 261 pr_debug("machine__findnew_thread failed\n");
263 return -1; 262 return -1;
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index 9cc81a3eb9b4..3e6cb171e3d3 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -1,7 +1,7 @@
1#include "util.h" 1#include "util.h"
2 2
3#include <stdlib.h> 3#include <stdlib.h>
4#include <sys/types.h> 4#include <linux/types.h>
5#include <sys/stat.h> 5#include <sys/stat.h>
6#include <fcntl.h> 6#include <fcntl.h>
7#include <string.h> 7#include <string.h>
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index c059ee81c038..108f0cd49f4e 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -1,5 +1,5 @@
1#include <linux/compiler.h> 1#include <linux/compiler.h>
2#include <sys/types.h> 2#include <linux/types.h>
3#include <unistd.h> 3#include <unistd.h>
4#include "tests.h" 4#include "tests.h"
5#include "debug.h" 5#include "debug.h"
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index 4774f7fbb758..35d7fdb2328d 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -74,9 +74,6 @@ int test__perf_evsel__tp_sched_test(void)
74 if (perf_evsel__test_field(evsel, "prio", 4, true)) 74 if (perf_evsel__test_field(evsel, "prio", 4, true))
75 ret = -1; 75 ret = -1;
76 76
77 if (perf_evsel__test_field(evsel, "success", 4, true))
78 ret = -1;
79
80 if (perf_evsel__test_field(evsel, "target_cpu", 4, true)) 77 if (perf_evsel__test_field(evsel, "target_cpu", 4, true))
81 ret = -1; 78 ret = -1;
82 79
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
new file mode 100644
index 000000000000..e4e01aadc3be
--- /dev/null
+++ b/tools/perf/tests/hists_common.c
@@ -0,0 +1,205 @@
1#include "perf.h"
2#include "util/debug.h"
3#include "util/symbol.h"
4#include "util/sort.h"
5#include "util/evsel.h"
6#include "util/evlist.h"
7#include "util/machine.h"
8#include "util/thread.h"
9#include "tests/hists_common.h"
10
11static struct {
12 u32 pid;
13 const char *comm;
14} fake_threads[] = {
15 { 100, "perf" },
16 { 200, "perf" },
17 { 300, "bash" },
18};
19
20static struct {
21 u32 pid;
22 u64 start;
23 const char *filename;
24} fake_mmap_info[] = {
25 { 100, 0x40000, "perf" },
26 { 100, 0x50000, "libc" },
27 { 100, 0xf0000, "[kernel]" },
28 { 200, 0x40000, "perf" },
29 { 200, 0x50000, "libc" },
30 { 200, 0xf0000, "[kernel]" },
31 { 300, 0x40000, "bash" },
32 { 300, 0x50000, "libc" },
33 { 300, 0xf0000, "[kernel]" },
34};
35
36struct fake_sym {
37 u64 start;
38 u64 length;
39 const char *name;
40};
41
42static struct fake_sym perf_syms[] = {
43 { 700, 100, "main" },
44 { 800, 100, "run_command" },
45 { 900, 100, "cmd_record" },
46};
47
48static struct fake_sym bash_syms[] = {
49 { 700, 100, "main" },
50 { 800, 100, "xmalloc" },
51 { 900, 100, "xfree" },
52};
53
54static struct fake_sym libc_syms[] = {
55 { 700, 100, "malloc" },
56 { 800, 100, "free" },
57 { 900, 100, "realloc" },
58};
59
60static struct fake_sym kernel_syms[] = {
61 { 700, 100, "schedule" },
62 { 800, 100, "page_fault" },
63 { 900, 100, "sys_perf_event_open" },
64};
65
66static struct {
67 const char *dso_name;
68 struct fake_sym *syms;
69 size_t nr_syms;
70} fake_symbols[] = {
71 { "perf", perf_syms, ARRAY_SIZE(perf_syms) },
72 { "bash", bash_syms, ARRAY_SIZE(bash_syms) },
73 { "libc", libc_syms, ARRAY_SIZE(libc_syms) },
74 { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) },
75};
76
77struct machine *setup_fake_machine(struct machines *machines)
78{
79 struct machine *machine = machines__find(machines, HOST_KERNEL_ID);
80 size_t i;
81
82 if (machine == NULL) {
83 pr_debug("Not enough memory for machine setup\n");
84 return NULL;
85 }
86
87 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
88 struct thread *thread;
89
90 thread = machine__findnew_thread(machine, fake_threads[i].pid,
91 fake_threads[i].pid);
92 if (thread == NULL)
93 goto out;
94
95 thread__set_comm(thread, fake_threads[i].comm, 0);
96 }
97
98 for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) {
99 union perf_event fake_mmap_event = {
100 .mmap = {
101 .header = { .misc = PERF_RECORD_MISC_USER, },
102 .pid = fake_mmap_info[i].pid,
103 .tid = fake_mmap_info[i].pid,
104 .start = fake_mmap_info[i].start,
105 .len = 0x1000ULL,
106 .pgoff = 0ULL,
107 },
108 };
109
110 strcpy(fake_mmap_event.mmap.filename,
111 fake_mmap_info[i].filename);
112
113 machine__process_mmap_event(machine, &fake_mmap_event, NULL);
114 }
115
116 for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
117 size_t k;
118 struct dso *dso;
119
120 dso = __dsos__findnew(&machine->user_dsos,
121 fake_symbols[i].dso_name);
122 if (dso == NULL)
123 goto out;
124
125 /* emulate dso__load() */
126 dso__set_loaded(dso, MAP__FUNCTION);
127
128 for (k = 0; k < fake_symbols[i].nr_syms; k++) {
129 struct symbol *sym;
130 struct fake_sym *fsym = &fake_symbols[i].syms[k];
131
132 sym = symbol__new(fsym->start, fsym->length,
133 STB_GLOBAL, fsym->name);
134 if (sym == NULL)
135 goto out;
136
137 symbols__insert(&dso->symbols[MAP__FUNCTION], sym);
138 }
139 }
140
141 return machine;
142
143out:
144 pr_debug("Not enough memory for machine setup\n");
145 machine__delete_threads(machine);
146 machine__delete(machine);
147 return NULL;
148}
149
150void print_hists_in(struct hists *hists)
151{
152 int i = 0;
153 struct rb_root *root;
154 struct rb_node *node;
155
156 if (sort__need_collapse)
157 root = &hists->entries_collapsed;
158 else
159 root = hists->entries_in;
160
161 pr_info("----- %s --------\n", __func__);
162 node = rb_first(root);
163 while (node) {
164 struct hist_entry *he;
165
166 he = rb_entry(node, struct hist_entry, rb_node_in);
167
168 if (!he->filtered) {
169 pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
170 i, thread__comm_str(he->thread),
171 he->ms.map->dso->short_name,
172 he->ms.sym->name, he->stat.period);
173 }
174
175 i++;
176 node = rb_next(node);
177 }
178}
179
180void print_hists_out(struct hists *hists)
181{
182 int i = 0;
183 struct rb_root *root;
184 struct rb_node *node;
185
186 root = &hists->entries;
187
188 pr_info("----- %s --------\n", __func__);
189 node = rb_first(root);
190 while (node) {
191 struct hist_entry *he;
192
193 he = rb_entry(node, struct hist_entry, rb_node);
194
195 if (!he->filtered) {
196 pr_info("%2d: entry: %8s:%5d [%-8s] %20s: period = %"PRIu64"\n",
197 i, thread__comm_str(he->thread), he->thread->tid,
198 he->ms.map->dso->short_name,
199 he->ms.sym->name, he->stat.period);
200 }
201
202 i++;
203 node = rb_next(node);
204 }
205}
diff --git a/tools/perf/tests/hists_common.h b/tools/perf/tests/hists_common.h
new file mode 100644
index 000000000000..1415ae69d7b6
--- /dev/null
+++ b/tools/perf/tests/hists_common.h
@@ -0,0 +1,47 @@
1#ifndef __PERF_TESTS__HISTS_COMMON_H__
2#define __PERF_TESTS__HISTS_COMMON_H__
3
4struct machine;
5struct machines;
6
7/*
8 * The setup_fake_machine() provides a test environment which consists
9 * of 3 processes that have 3 mappings and in turn, have 3 symbols
10 * respectively. See below table:
11 *
12 * Command: Pid Shared Object Symbol
13 * ............. ............. ...................
14 * perf: 100 perf main
15 * perf: 100 perf run_command
16 * perf: 100 perf comd_record
17 * perf: 100 libc malloc
18 * perf: 100 libc free
19 * perf: 100 libc realloc
20 * perf: 100 [kernel] schedule
21 * perf: 100 [kernel] page_fault
22 * perf: 100 [kernel] sys_perf_event_open
23 * perf: 200 perf main
24 * perf: 200 perf run_command
25 * perf: 200 perf comd_record
26 * perf: 200 libc malloc
27 * perf: 200 libc free
28 * perf: 200 libc realloc
29 * perf: 200 [kernel] schedule
30 * perf: 200 [kernel] page_fault
31 * perf: 200 [kernel] sys_perf_event_open
32 * bash: 300 bash main
33 * bash: 300 bash xmalloc
34 * bash: 300 bash xfree
35 * bash: 300 libc malloc
36 * bash: 300 libc free
37 * bash: 300 libc realloc
38 * bash: 300 [kernel] schedule
39 * bash: 300 [kernel] page_fault
40 * bash: 300 [kernel] sys_perf_event_open
41 */
42struct machine *setup_fake_machine(struct machines *machines);
43
44void print_hists_in(struct hists *hists);
45void print_hists_out(struct hists *hists);
46
47#endif /* __PERF_TESTS__HISTS_COMMON_H__ */
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
new file mode 100644
index 000000000000..c5ba924a3581
--- /dev/null
+++ b/tools/perf/tests/hists_filter.c
@@ -0,0 +1,290 @@
1#include "perf.h"
2#include "util/debug.h"
3#include "util/symbol.h"
4#include "util/sort.h"
5#include "util/evsel.h"
6#include "util/evlist.h"
7#include "util/machine.h"
8#include "util/thread.h"
9#include "util/parse-events.h"
10#include "tests/tests.h"
11#include "tests/hists_common.h"
12
13struct sample {
14 u32 pid;
15 u64 ip;
16 struct thread *thread;
17 struct map *map;
18 struct symbol *sym;
19};
20
21/* For the numbers, see hists_common.c */
22static struct sample fake_samples[] = {
23 /* perf [kernel] schedule() */
24 { .pid = 100, .ip = 0xf0000 + 700, },
25 /* perf [perf] main() */
26 { .pid = 100, .ip = 0x40000 + 700, },
27 /* perf [libc] malloc() */
28 { .pid = 100, .ip = 0x50000 + 700, },
29 /* perf [perf] main() */
30 { .pid = 200, .ip = 0x40000 + 700, }, /* will be merged */
31 /* perf [perf] cmd_record() */
32 { .pid = 200, .ip = 0x40000 + 900, },
33 /* perf [kernel] page_fault() */
34 { .pid = 200, .ip = 0xf0000 + 800, },
35 /* bash [bash] main() */
36 { .pid = 300, .ip = 0x40000 + 700, },
37 /* bash [bash] xmalloc() */
38 { .pid = 300, .ip = 0x40000 + 800, },
39 /* bash [libc] malloc() */
40 { .pid = 300, .ip = 0x50000 + 700, },
41 /* bash [kernel] page_fault() */
42 { .pid = 300, .ip = 0xf0000 + 800, },
43};
44
45static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
46{
47 struct perf_evsel *evsel;
48 struct addr_location al;
49 struct hist_entry *he;
50 struct perf_sample sample = { .cpu = 0, };
51 size_t i;
52
53 /*
54 * each evsel will have 10 samples but the 4th sample
55 * (perf [perf] main) will be collapsed to an existing entry
56 * so total 9 entries will be in the tree.
57 */
58 evlist__for_each(evlist, evsel) {
59 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
60 const union perf_event event = {
61 .header = {
62 .misc = PERF_RECORD_MISC_USER,
63 },
64 };
65
66 /* make sure it has no filter at first */
67 evsel->hists.thread_filter = NULL;
68 evsel->hists.dso_filter = NULL;
69 evsel->hists.symbol_filter_str = NULL;
70
71 sample.pid = fake_samples[i].pid;
72 sample.tid = fake_samples[i].pid;
73 sample.ip = fake_samples[i].ip;
74
75 if (perf_event__preprocess_sample(&event, machine, &al,
76 &sample) < 0)
77 goto out;
78
79 he = __hists__add_entry(&evsel->hists, &al, NULL,
80 NULL, NULL, 100, 1, 0);
81 if (he == NULL)
82 goto out;
83
84 fake_samples[i].thread = al.thread;
85 fake_samples[i].map = al.map;
86 fake_samples[i].sym = al.sym;
87
88 hists__inc_nr_events(he->hists, PERF_RECORD_SAMPLE);
89 if (!he->filtered)
90 he->hists->stats.nr_non_filtered_samples++;
91 }
92 }
93
94 return 0;
95
96out:
97 pr_debug("Not enough memory for adding a hist entry\n");
98 return TEST_FAIL;
99}
100
101int test__hists_filter(void)
102{
103 int err = TEST_FAIL;
104 struct machines machines;
105 struct machine *machine;
106 struct perf_evsel *evsel;
107 struct perf_evlist *evlist = perf_evlist__new();
108
109 TEST_ASSERT_VAL("No memory", evlist);
110
111 err = parse_events(evlist, "cpu-clock");
112 if (err)
113 goto out;
114 err = parse_events(evlist, "task-clock");
115 if (err)
116 goto out;
117
118 /* default sort order (comm,dso,sym) will be used */
119 if (setup_sorting() < 0)
120 goto out;
121
122 machines__init(&machines);
123
124 /* setup threads/dso/map/symbols also */
125 machine = setup_fake_machine(&machines);
126 if (!machine)
127 goto out;
128
129 if (verbose > 1)
130 machine__fprintf(machine, stderr);
131
132 /* process sample events */
133 err = add_hist_entries(evlist, machine);
134 if (err < 0)
135 goto out;
136
137 evlist__for_each(evlist, evsel) {
138 struct hists *hists = &evsel->hists;
139
140 hists__collapse_resort(hists, NULL);
141 hists__output_resort(hists);
142
143 if (verbose > 2) {
144 pr_info("Normal histogram\n");
145 print_hists_out(hists);
146 }
147
148 TEST_ASSERT_VAL("Invalid nr samples",
149 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
150 TEST_ASSERT_VAL("Invalid nr hist entries",
151 hists->nr_entries == 9);
152 TEST_ASSERT_VAL("Invalid total period",
153 hists->stats.total_period == 1000);
154 TEST_ASSERT_VAL("Unmatched nr samples",
155 hists->stats.nr_events[PERF_RECORD_SAMPLE] ==
156 hists->stats.nr_non_filtered_samples);
157 TEST_ASSERT_VAL("Unmatched nr hist entries",
158 hists->nr_entries == hists->nr_non_filtered_entries);
159 TEST_ASSERT_VAL("Unmatched total period",
160 hists->stats.total_period ==
161 hists->stats.total_non_filtered_period);
162
163 /* now applying thread filter for 'bash' */
164 evsel->hists.thread_filter = fake_samples[9].thread;
165 hists__filter_by_thread(hists);
166
167 if (verbose > 2) {
168 pr_info("Histogram for thread filter\n");
169 print_hists_out(hists);
170 }
171
172 /* normal stats should be invariant */
173 TEST_ASSERT_VAL("Invalid nr samples",
174 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
175 TEST_ASSERT_VAL("Invalid nr hist entries",
176 hists->nr_entries == 9);
177 TEST_ASSERT_VAL("Invalid total period",
178 hists->stats.total_period == 1000);
179
180 /* but filter stats are changed */
181 TEST_ASSERT_VAL("Unmatched nr samples for thread filter",
182 hists->stats.nr_non_filtered_samples == 4);
183 TEST_ASSERT_VAL("Unmatched nr hist entries for thread filter",
184 hists->nr_non_filtered_entries == 4);
185 TEST_ASSERT_VAL("Unmatched total period for thread filter",
186 hists->stats.total_non_filtered_period == 400);
187
188 /* remove thread filter first */
189 evsel->hists.thread_filter = NULL;
190 hists__filter_by_thread(hists);
191
192 /* now applying dso filter for 'kernel' */
193 evsel->hists.dso_filter = fake_samples[0].map->dso;
194 hists__filter_by_dso(hists);
195
196 if (verbose > 2) {
197 pr_info("Histogram for dso filter\n");
198 print_hists_out(hists);
199 }
200
201 /* normal stats should be invariant */
202 TEST_ASSERT_VAL("Invalid nr samples",
203 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
204 TEST_ASSERT_VAL("Invalid nr hist entries",
205 hists->nr_entries == 9);
206 TEST_ASSERT_VAL("Invalid total period",
207 hists->stats.total_period == 1000);
208
209 /* but filter stats are changed */
210 TEST_ASSERT_VAL("Unmatched nr samples for dso filter",
211 hists->stats.nr_non_filtered_samples == 3);
212 TEST_ASSERT_VAL("Unmatched nr hist entries for dso filter",
213 hists->nr_non_filtered_entries == 3);
214 TEST_ASSERT_VAL("Unmatched total period for dso filter",
215 hists->stats.total_non_filtered_period == 300);
216
217 /* remove dso filter first */
218 evsel->hists.dso_filter = NULL;
219 hists__filter_by_dso(hists);
220
221 /*
222 * now applying symbol filter for 'main'. Also note that
223 * there's 3 samples that have 'main' symbol but the 4th
224 * entry of fake_samples was collapsed already so it won't
225 * be counted as a separate entry but the sample count and
226 * total period will be remained.
227 */
228 evsel->hists.symbol_filter_str = "main";
229 hists__filter_by_symbol(hists);
230
231 if (verbose > 2) {
232 pr_info("Histogram for symbol filter\n");
233 print_hists_out(hists);
234 }
235
236 /* normal stats should be invariant */
237 TEST_ASSERT_VAL("Invalid nr samples",
238 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
239 TEST_ASSERT_VAL("Invalid nr hist entries",
240 hists->nr_entries == 9);
241 TEST_ASSERT_VAL("Invalid total period",
242 hists->stats.total_period == 1000);
243
244 /* but filter stats are changed */
245 TEST_ASSERT_VAL("Unmatched nr samples for symbol filter",
246 hists->stats.nr_non_filtered_samples == 3);
247 TEST_ASSERT_VAL("Unmatched nr hist entries for symbol filter",
248 hists->nr_non_filtered_entries == 2);
249 TEST_ASSERT_VAL("Unmatched total period for symbol filter",
250 hists->stats.total_non_filtered_period == 300);
251
252 /* now applying all filters at once. */
253 evsel->hists.thread_filter = fake_samples[1].thread;
254 evsel->hists.dso_filter = fake_samples[1].map->dso;
255 hists__filter_by_thread(hists);
256 hists__filter_by_dso(hists);
257
258 if (verbose > 2) {
259 pr_info("Histogram for all filters\n");
260 print_hists_out(hists);
261 }
262
263 /* normal stats should be invariant */
264 TEST_ASSERT_VAL("Invalid nr samples",
265 hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
266 TEST_ASSERT_VAL("Invalid nr hist entries",
267 hists->nr_entries == 9);
268 TEST_ASSERT_VAL("Invalid total period",
269 hists->stats.total_period == 1000);
270
271 /* but filter stats are changed */
272 TEST_ASSERT_VAL("Unmatched nr samples for all filter",
273 hists->stats.nr_non_filtered_samples == 2);
274 TEST_ASSERT_VAL("Unmatched nr hist entries for all filter",
275 hists->nr_non_filtered_entries == 1);
276 TEST_ASSERT_VAL("Unmatched total period for all filter",
277 hists->stats.total_non_filtered_period == 200);
278 }
279
280
281 err = TEST_OK;
282
283out:
284 /* tear down everything */
285 perf_evlist__delete(evlist);
286 reset_output_field();
287 machines__exit(&machines);
288
289 return err;
290}
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 7ccbc7b6ae77..5ffa2c3eb77d 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -8,145 +8,7 @@
8#include "machine.h" 8#include "machine.h"
9#include "thread.h" 9#include "thread.h"
10#include "parse-events.h" 10#include "parse-events.h"
11 11#include "hists_common.h"
12static struct {
13 u32 pid;
14 const char *comm;
15} fake_threads[] = {
16 { 100, "perf" },
17 { 200, "perf" },
18 { 300, "bash" },
19};
20
21static struct {
22 u32 pid;
23 u64 start;
24 const char *filename;
25} fake_mmap_info[] = {
26 { 100, 0x40000, "perf" },
27 { 100, 0x50000, "libc" },
28 { 100, 0xf0000, "[kernel]" },
29 { 200, 0x40000, "perf" },
30 { 200, 0x50000, "libc" },
31 { 200, 0xf0000, "[kernel]" },
32 { 300, 0x40000, "bash" },
33 { 300, 0x50000, "libc" },
34 { 300, 0xf0000, "[kernel]" },
35};
36
37struct fake_sym {
38 u64 start;
39 u64 length;
40 const char *name;
41};
42
43static struct fake_sym perf_syms[] = {
44 { 700, 100, "main" },
45 { 800, 100, "run_command" },
46 { 900, 100, "cmd_record" },
47};
48
49static struct fake_sym bash_syms[] = {
50 { 700, 100, "main" },
51 { 800, 100, "xmalloc" },
52 { 900, 100, "xfree" },
53};
54
55static struct fake_sym libc_syms[] = {
56 { 700, 100, "malloc" },
57 { 800, 100, "free" },
58 { 900, 100, "realloc" },
59};
60
61static struct fake_sym kernel_syms[] = {
62 { 700, 100, "schedule" },
63 { 800, 100, "page_fault" },
64 { 900, 100, "sys_perf_event_open" },
65};
66
67static struct {
68 const char *dso_name;
69 struct fake_sym *syms;
70 size_t nr_syms;
71} fake_symbols[] = {
72 { "perf", perf_syms, ARRAY_SIZE(perf_syms) },
73 { "bash", bash_syms, ARRAY_SIZE(bash_syms) },
74 { "libc", libc_syms, ARRAY_SIZE(libc_syms) },
75 { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) },
76};
77
78static struct machine *setup_fake_machine(struct machines *machines)
79{
80 struct machine *machine = machines__find(machines, HOST_KERNEL_ID);
81 size_t i;
82
83 if (machine == NULL) {
84 pr_debug("Not enough memory for machine setup\n");
85 return NULL;
86 }
87
88 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
89 struct thread *thread;
90
91 thread = machine__findnew_thread(machine, fake_threads[i].pid,
92 fake_threads[i].pid);
93 if (thread == NULL)
94 goto out;
95
96 thread__set_comm(thread, fake_threads[i].comm, 0);
97 }
98
99 for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) {
100 union perf_event fake_mmap_event = {
101 .mmap = {
102 .header = { .misc = PERF_RECORD_MISC_USER, },
103 .pid = fake_mmap_info[i].pid,
104 .tid = fake_mmap_info[i].pid,
105 .start = fake_mmap_info[i].start,
106 .len = 0x1000ULL,
107 .pgoff = 0ULL,
108 },
109 };
110
111 strcpy(fake_mmap_event.mmap.filename,
112 fake_mmap_info[i].filename);
113
114 machine__process_mmap_event(machine, &fake_mmap_event, NULL);
115 }
116
117 for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
118 size_t k;
119 struct dso *dso;
120
121 dso = __dsos__findnew(&machine->user_dsos,
122 fake_symbols[i].dso_name);
123 if (dso == NULL)
124 goto out;
125
126 /* emulate dso__load() */
127 dso__set_loaded(dso, MAP__FUNCTION);
128
129 for (k = 0; k < fake_symbols[i].nr_syms; k++) {
130 struct symbol *sym;
131 struct fake_sym *fsym = &fake_symbols[i].syms[k];
132
133 sym = symbol__new(fsym->start, fsym->length,
134 STB_GLOBAL, fsym->name);
135 if (sym == NULL)
136 goto out;
137
138 symbols__insert(&dso->symbols[MAP__FUNCTION], sym);
139 }
140 }
141
142 return machine;
143
144out:
145 pr_debug("Not enough memory for machine setup\n");
146 machine__delete_threads(machine);
147 machine__delete(machine);
148 return NULL;
149}
150 12
151struct sample { 13struct sample {
152 u32 pid; 14 u32 pid;
@@ -156,6 +18,7 @@ struct sample {
156 struct symbol *sym; 18 struct symbol *sym;
157}; 19};
158 20
21/* For the numbers, see hists_common.c */
159static struct sample fake_common_samples[] = { 22static struct sample fake_common_samples[] = {
160 /* perf [kernel] schedule() */ 23 /* perf [kernel] schedule() */
161 { .pid = 100, .ip = 0xf0000 + 700, }, 24 { .pid = 100, .ip = 0xf0000 + 700, },
@@ -218,6 +81,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
218 }; 81 };
219 82
220 sample.pid = fake_common_samples[k].pid; 83 sample.pid = fake_common_samples[k].pid;
84 sample.tid = fake_common_samples[k].pid;
221 sample.ip = fake_common_samples[k].ip; 85 sample.ip = fake_common_samples[k].ip;
222 if (perf_event__preprocess_sample(&event, machine, &al, 86 if (perf_event__preprocess_sample(&event, machine, &al,
223 &sample) < 0) 87 &sample) < 0)
@@ -241,6 +105,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
241 }; 105 };
242 106
243 sample.pid = fake_samples[i][k].pid; 107 sample.pid = fake_samples[i][k].pid;
108 sample.tid = fake_samples[i][k].pid;
244 sample.ip = fake_samples[i][k].ip; 109 sample.ip = fake_samples[i][k].ip;
245 if (perf_event__preprocess_sample(&event, machine, &al, 110 if (perf_event__preprocess_sample(&event, machine, &al,
246 &sample) < 0) 111 &sample) < 0)
@@ -403,33 +268,6 @@ static int validate_link(struct hists *leader, struct hists *other)
403 return __validate_link(leader, 0) || __validate_link(other, 1); 268 return __validate_link(leader, 0) || __validate_link(other, 1);
404} 269}
405 270
406static void print_hists(struct hists *hists)
407{
408 int i = 0;
409 struct rb_root *root;
410 struct rb_node *node;
411
412 if (sort__need_collapse)
413 root = &hists->entries_collapsed;
414 else
415 root = hists->entries_in;
416
417 pr_info("----- %s --------\n", __func__);
418 node = rb_first(root);
419 while (node) {
420 struct hist_entry *he;
421
422 he = rb_entry(node, struct hist_entry, rb_node_in);
423
424 pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
425 i, thread__comm_str(he->thread), he->ms.map->dso->short_name,
426 he->ms.sym->name, he->stat.period);
427
428 i++;
429 node = rb_next(node);
430 }
431}
432
433int test__hists_link(void) 271int test__hists_link(void)
434{ 272{
435 int err = -1; 273 int err = -1;
@@ -471,7 +309,7 @@ int test__hists_link(void)
471 hists__collapse_resort(&evsel->hists, NULL); 309 hists__collapse_resort(&evsel->hists, NULL);
472 310
473 if (verbose > 2) 311 if (verbose > 2)
474 print_hists(&evsel->hists); 312 print_hists_in(&evsel->hists);
475 } 313 }
476 314
477 first = perf_evlist__first(evlist); 315 first = perf_evlist__first(evlist);
@@ -494,6 +332,7 @@ int test__hists_link(void)
494out: 332out:
495 /* tear down everything */ 333 /* tear down everything */
496 perf_evlist__delete(evlist); 334 perf_evlist__delete(evlist);
335 reset_output_field();
497 machines__exit(&machines); 336 machines__exit(&machines);
498 337
499 return err; 338 return err;
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
new file mode 100644
index 000000000000..a16850551797
--- /dev/null
+++ b/tools/perf/tests/hists_output.c
@@ -0,0 +1,618 @@
1#include "perf.h"
2#include "util/debug.h"
3#include "util/symbol.h"
4#include "util/sort.h"
5#include "util/evsel.h"
6#include "util/evlist.h"
7#include "util/machine.h"
8#include "util/thread.h"
9#include "util/parse-events.h"
10#include "tests/tests.h"
11#include "tests/hists_common.h"
12
13struct sample {
14 u32 cpu;
15 u32 pid;
16 u64 ip;
17 struct thread *thread;
18 struct map *map;
19 struct symbol *sym;
20};
21
22/* For the numbers, see hists_common.c */
23static struct sample fake_samples[] = {
24 /* perf [kernel] schedule() */
25 { .cpu = 0, .pid = 100, .ip = 0xf0000 + 700, },
26 /* perf [perf] main() */
27 { .cpu = 1, .pid = 100, .ip = 0x40000 + 700, },
28 /* perf [perf] cmd_record() */
29 { .cpu = 1, .pid = 100, .ip = 0x40000 + 900, },
30 /* perf [libc] malloc() */
31 { .cpu = 1, .pid = 100, .ip = 0x50000 + 700, },
32 /* perf [libc] free() */
33 { .cpu = 2, .pid = 100, .ip = 0x50000 + 800, },
34 /* perf [perf] main() */
35 { .cpu = 2, .pid = 200, .ip = 0x40000 + 700, },
36 /* perf [kernel] page_fault() */
37 { .cpu = 2, .pid = 200, .ip = 0xf0000 + 800, },
38 /* bash [bash] main() */
39 { .cpu = 3, .pid = 300, .ip = 0x40000 + 700, },
40 /* bash [bash] xmalloc() */
41 { .cpu = 0, .pid = 300, .ip = 0x40000 + 800, },
42 /* bash [kernel] page_fault() */
43 { .cpu = 1, .pid = 300, .ip = 0xf0000 + 800, },
44};
45
46static int add_hist_entries(struct hists *hists, struct machine *machine)
47{
48 struct addr_location al;
49 struct hist_entry *he;
50 struct perf_sample sample = { .period = 100, };
51 size_t i;
52
53 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
54 const union perf_event event = {
55 .header = {
56 .misc = PERF_RECORD_MISC_USER,
57 },
58 };
59
60 sample.cpu = fake_samples[i].cpu;
61 sample.pid = fake_samples[i].pid;
62 sample.tid = fake_samples[i].pid;
63 sample.ip = fake_samples[i].ip;
64
65 if (perf_event__preprocess_sample(&event, machine, &al,
66 &sample) < 0)
67 goto out;
68
69 he = __hists__add_entry(hists, &al, NULL, NULL, NULL,
70 sample.period, 1, 0);
71 if (he == NULL)
72 goto out;
73
74 fake_samples[i].thread = al.thread;
75 fake_samples[i].map = al.map;
76 fake_samples[i].sym = al.sym;
77 }
78
79 return TEST_OK;
80
81out:
82 pr_debug("Not enough memory for adding a hist entry\n");
83 return TEST_FAIL;
84}
85
86static void del_hist_entries(struct hists *hists)
87{
88 struct hist_entry *he;
89 struct rb_root *root_in;
90 struct rb_root *root_out;
91 struct rb_node *node;
92
93 if (sort__need_collapse)
94 root_in = &hists->entries_collapsed;
95 else
96 root_in = hists->entries_in;
97
98 root_out = &hists->entries;
99
100 while (!RB_EMPTY_ROOT(root_out)) {
101 node = rb_first(root_out);
102
103 he = rb_entry(node, struct hist_entry, rb_node);
104 rb_erase(node, root_out);
105 rb_erase(&he->rb_node_in, root_in);
106 hist_entry__free(he);
107 }
108}
109
110typedef int (*test_fn_t)(struct perf_evsel *, struct machine *);
111
112#define COMM(he) (thread__comm_str(he->thread))
113#define DSO(he) (he->ms.map->dso->short_name)
114#define SYM(he) (he->ms.sym->name)
115#define CPU(he) (he->cpu)
116#define PID(he) (he->thread->tid)
117
118/* default sort keys (no field) */
119static int test1(struct perf_evsel *evsel, struct machine *machine)
120{
121 int err;
122 struct hists *hists = &evsel->hists;
123 struct hist_entry *he;
124 struct rb_root *root;
125 struct rb_node *node;
126
127 field_order = NULL;
128 sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */
129
130 setup_sorting();
131
132 /*
133 * expected output:
134 *
135 * Overhead Command Shared Object Symbol
136 * ======== ======= ============= ==============
137 * 20.00% perf perf [.] main
138 * 10.00% bash [kernel] [k] page_fault
139 * 10.00% bash bash [.] main
140 * 10.00% bash bash [.] xmalloc
141 * 10.00% perf [kernel] [k] page_fault
142 * 10.00% perf [kernel] [k] schedule
143 * 10.00% perf libc [.] free
144 * 10.00% perf libc [.] malloc
145 * 10.00% perf perf [.] cmd_record
146 */
147 err = add_hist_entries(hists, machine);
148 if (err < 0)
149 goto out;
150
151 hists__collapse_resort(hists, NULL);
152 hists__output_resort(hists);
153
154 if (verbose > 2) {
155 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
156 print_hists_out(hists);
157 }
158
159 root = &evsel->hists.entries;
160 node = rb_first(root);
161 he = rb_entry(node, struct hist_entry, rb_node);
162 TEST_ASSERT_VAL("Invalid hist entry",
163 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
164 !strcmp(SYM(he), "main") && he->stat.period == 200);
165
166 node = rb_next(node);
167 he = rb_entry(node, struct hist_entry, rb_node);
168 TEST_ASSERT_VAL("Invalid hist entry",
169 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
170 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
171
172 node = rb_next(node);
173 he = rb_entry(node, struct hist_entry, rb_node);
174 TEST_ASSERT_VAL("Invalid hist entry",
175 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
176 !strcmp(SYM(he), "main") && he->stat.period == 100);
177
178 node = rb_next(node);
179 he = rb_entry(node, struct hist_entry, rb_node);
180 TEST_ASSERT_VAL("Invalid hist entry",
181 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
182 !strcmp(SYM(he), "xmalloc") && he->stat.period == 100);
183
184 node = rb_next(node);
185 he = rb_entry(node, struct hist_entry, rb_node);
186 TEST_ASSERT_VAL("Invalid hist entry",
187 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
188 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
189
190 node = rb_next(node);
191 he = rb_entry(node, struct hist_entry, rb_node);
192 TEST_ASSERT_VAL("Invalid hist entry",
193 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
194 !strcmp(SYM(he), "schedule") && he->stat.period == 100);
195
196 node = rb_next(node);
197 he = rb_entry(node, struct hist_entry, rb_node);
198 TEST_ASSERT_VAL("Invalid hist entry",
199 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
200 !strcmp(SYM(he), "free") && he->stat.period == 100);
201
202 node = rb_next(node);
203 he = rb_entry(node, struct hist_entry, rb_node);
204 TEST_ASSERT_VAL("Invalid hist entry",
205 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
206 !strcmp(SYM(he), "malloc") && he->stat.period == 100);
207
208 node = rb_next(node);
209 he = rb_entry(node, struct hist_entry, rb_node);
210 TEST_ASSERT_VAL("Invalid hist entry",
211 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
212 !strcmp(SYM(he), "cmd_record") && he->stat.period == 100);
213
214out:
215 del_hist_entries(hists);
216 reset_output_field();
217 return err;
218}
219
220/* mixed fields and sort keys */
221static int test2(struct perf_evsel *evsel, struct machine *machine)
222{
223 int err;
224 struct hists *hists = &evsel->hists;
225 struct hist_entry *he;
226 struct rb_root *root;
227 struct rb_node *node;
228
229 field_order = "overhead,cpu";
230 sort_order = "pid";
231
232 setup_sorting();
233
234 /*
235 * expected output:
236 *
237 * Overhead CPU Command: Pid
238 * ======== === =============
239 * 30.00% 1 perf : 100
240 * 10.00% 0 perf : 100
241 * 10.00% 2 perf : 100
242 * 20.00% 2 perf : 200
243 * 10.00% 0 bash : 300
244 * 10.00% 1 bash : 300
245 * 10.00% 3 bash : 300
246 */
247 err = add_hist_entries(hists, machine);
248 if (err < 0)
249 goto out;
250
251 hists__collapse_resort(hists, NULL);
252 hists__output_resort(hists);
253
254 if (verbose > 2) {
255 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
256 print_hists_out(hists);
257 }
258
259 root = &evsel->hists.entries;
260 node = rb_first(root);
261 he = rb_entry(node, struct hist_entry, rb_node);
262 TEST_ASSERT_VAL("Invalid hist entry",
263 CPU(he) == 1 && PID(he) == 100 && he->stat.period == 300);
264
265 node = rb_next(node);
266 he = rb_entry(node, struct hist_entry, rb_node);
267 TEST_ASSERT_VAL("Invalid hist entry",
268 CPU(he) == 0 && PID(he) == 100 && he->stat.period == 100);
269
270out:
271 del_hist_entries(hists);
272 reset_output_field();
273 return err;
274}
275
276/* fields only (no sort key) */
277static int test3(struct perf_evsel *evsel, struct machine *machine)
278{
279 int err;
280 struct hists *hists = &evsel->hists;
281 struct hist_entry *he;
282 struct rb_root *root;
283 struct rb_node *node;
284
285 field_order = "comm,overhead,dso";
286 sort_order = NULL;
287
288 setup_sorting();
289
290 /*
291 * expected output:
292 *
293 * Command Overhead Shared Object
294 * ======= ======== =============
295 * bash 20.00% bash
296 * bash 10.00% [kernel]
297 * perf 30.00% perf
298 * perf 20.00% [kernel]
299 * perf 20.00% libc
300 */
301 err = add_hist_entries(hists, machine);
302 if (err < 0)
303 goto out;
304
305 hists__collapse_resort(hists, NULL);
306 hists__output_resort(hists);
307
308 if (verbose > 2) {
309 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
310 print_hists_out(hists);
311 }
312
313 root = &evsel->hists.entries;
314 node = rb_first(root);
315 he = rb_entry(node, struct hist_entry, rb_node);
316 TEST_ASSERT_VAL("Invalid hist entry",
317 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
318 he->stat.period == 200);
319
320 node = rb_next(node);
321 he = rb_entry(node, struct hist_entry, rb_node);
322 TEST_ASSERT_VAL("Invalid hist entry",
323 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
324 he->stat.period == 100);
325
326 node = rb_next(node);
327 he = rb_entry(node, struct hist_entry, rb_node);
328 TEST_ASSERT_VAL("Invalid hist entry",
329 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
330 he->stat.period == 300);
331
332 node = rb_next(node);
333 he = rb_entry(node, struct hist_entry, rb_node);
334 TEST_ASSERT_VAL("Invalid hist entry",
335 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
336 he->stat.period == 200);
337
338 node = rb_next(node);
339 he = rb_entry(node, struct hist_entry, rb_node);
340 TEST_ASSERT_VAL("Invalid hist entry",
341 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
342 he->stat.period == 200);
343
344out:
345 del_hist_entries(hists);
346 reset_output_field();
347 return err;
348}
349
350/* handle duplicate 'dso' field */
351static int test4(struct perf_evsel *evsel, struct machine *machine)
352{
353 int err;
354 struct hists *hists = &evsel->hists;
355 struct hist_entry *he;
356 struct rb_root *root;
357 struct rb_node *node;
358
359 field_order = "dso,sym,comm,overhead,dso";
360 sort_order = "sym";
361
362 setup_sorting();
363
364 /*
365 * expected output:
366 *
367 * Shared Object Symbol Command Overhead
368 * ============= ============== ======= ========
369 * perf [.] cmd_record perf 10.00%
370 * libc [.] free perf 10.00%
371 * bash [.] main bash 10.00%
372 * perf [.] main perf 20.00%
373 * libc [.] malloc perf 10.00%
374 * [kernel] [k] page_fault bash 10.00%
375 * [kernel] [k] page_fault perf 10.00%
376 * [kernel] [k] schedule perf 10.00%
377 * bash [.] xmalloc bash 10.00%
378 */
379 err = add_hist_entries(hists, machine);
380 if (err < 0)
381 goto out;
382
383 hists__collapse_resort(hists, NULL);
384 hists__output_resort(hists);
385
386 if (verbose > 2) {
387 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
388 print_hists_out(hists);
389 }
390
391 root = &evsel->hists.entries;
392 node = rb_first(root);
393 he = rb_entry(node, struct hist_entry, rb_node);
394 TEST_ASSERT_VAL("Invalid hist entry",
395 !strcmp(DSO(he), "perf") && !strcmp(SYM(he), "cmd_record") &&
396 !strcmp(COMM(he), "perf") && he->stat.period == 100);
397
398 node = rb_next(node);
399 he = rb_entry(node, struct hist_entry, rb_node);
400 TEST_ASSERT_VAL("Invalid hist entry",
401 !strcmp(DSO(he), "libc") && !strcmp(SYM(he), "free") &&
402 !strcmp(COMM(he), "perf") && he->stat.period == 100);
403
404 node = rb_next(node);
405 he = rb_entry(node, struct hist_entry, rb_node);
406 TEST_ASSERT_VAL("Invalid hist entry",
407 !strcmp(DSO(he), "bash") && !strcmp(SYM(he), "main") &&
408 !strcmp(COMM(he), "bash") && he->stat.period == 100);
409
410 node = rb_next(node);
411 he = rb_entry(node, struct hist_entry, rb_node);
412 TEST_ASSERT_VAL("Invalid hist entry",
413 !strcmp(DSO(he), "perf") && !strcmp(SYM(he), "main") &&
414 !strcmp(COMM(he), "perf") && he->stat.period == 200);
415
416 node = rb_next(node);
417 he = rb_entry(node, struct hist_entry, rb_node);
418 TEST_ASSERT_VAL("Invalid hist entry",
419 !strcmp(DSO(he), "libc") && !strcmp(SYM(he), "malloc") &&
420 !strcmp(COMM(he), "perf") && he->stat.period == 100);
421
422 node = rb_next(node);
423 he = rb_entry(node, struct hist_entry, rb_node);
424 TEST_ASSERT_VAL("Invalid hist entry",
425 !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "page_fault") &&
426 !strcmp(COMM(he), "bash") && he->stat.period == 100);
427
428 node = rb_next(node);
429 he = rb_entry(node, struct hist_entry, rb_node);
430 TEST_ASSERT_VAL("Invalid hist entry",
431 !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "page_fault") &&
432 !strcmp(COMM(he), "perf") && he->stat.period == 100);
433
434 node = rb_next(node);
435 he = rb_entry(node, struct hist_entry, rb_node);
436 TEST_ASSERT_VAL("Invalid hist entry",
437 !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "schedule") &&
438 !strcmp(COMM(he), "perf") && he->stat.period == 100);
439
440 node = rb_next(node);
441 he = rb_entry(node, struct hist_entry, rb_node);
442 TEST_ASSERT_VAL("Invalid hist entry",
443 !strcmp(DSO(he), "bash") && !strcmp(SYM(he), "xmalloc") &&
444 !strcmp(COMM(he), "bash") && he->stat.period == 100);
445
446out:
447 del_hist_entries(hists);
448 reset_output_field();
449 return err;
450}
451
452/* full sort keys w/o overhead field */
453static int test5(struct perf_evsel *evsel, struct machine *machine)
454{
455 int err;
456 struct hists *hists = &evsel->hists;
457 struct hist_entry *he;
458 struct rb_root *root;
459 struct rb_node *node;
460
461 field_order = "cpu,pid,comm,dso,sym";
462 sort_order = "dso,pid";
463
464 setup_sorting();
465
466 /*
467 * expected output:
468 *
469 * CPU Command: Pid Command Shared Object Symbol
470 * === ============= ======= ============= ==============
471 * 0 perf: 100 perf [kernel] [k] schedule
472 * 2 perf: 200 perf [kernel] [k] page_fault
473 * 1 bash: 300 bash [kernel] [k] page_fault
474 * 0 bash: 300 bash bash [.] xmalloc
475 * 3 bash: 300 bash bash [.] main
476 * 1 perf: 100 perf libc [.] malloc
477 * 2 perf: 100 perf libc [.] free
478 * 1 perf: 100 perf perf [.] cmd_record
479 * 1 perf: 100 perf perf [.] main
480 * 2 perf: 200 perf perf [.] main
481 */
482 err = add_hist_entries(hists, machine);
483 if (err < 0)
484 goto out;
485
486 hists__collapse_resort(hists, NULL);
487 hists__output_resort(hists);
488
489 if (verbose > 2) {
490 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
491 print_hists_out(hists);
492 }
493
494 root = &evsel->hists.entries;
495 node = rb_first(root);
496 he = rb_entry(node, struct hist_entry, rb_node);
497
498 TEST_ASSERT_VAL("Invalid hist entry",
499 CPU(he) == 0 && PID(he) == 100 &&
500 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
501 !strcmp(SYM(he), "schedule") && he->stat.period == 100);
502
503 node = rb_next(node);
504 he = rb_entry(node, struct hist_entry, rb_node);
505 TEST_ASSERT_VAL("Invalid hist entry",
506 CPU(he) == 2 && PID(he) == 200 &&
507 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
508 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
509
510 node = rb_next(node);
511 he = rb_entry(node, struct hist_entry, rb_node);
512 TEST_ASSERT_VAL("Invalid hist entry",
513 CPU(he) == 1 && PID(he) == 300 &&
514 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
515 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
516
517 node = rb_next(node);
518 he = rb_entry(node, struct hist_entry, rb_node);
519 TEST_ASSERT_VAL("Invalid hist entry",
520 CPU(he) == 0 && PID(he) == 300 &&
521 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
522 !strcmp(SYM(he), "xmalloc") && he->stat.period == 100);
523
524 node = rb_next(node);
525 he = rb_entry(node, struct hist_entry, rb_node);
526 TEST_ASSERT_VAL("Invalid hist entry",
527 CPU(he) == 3 && PID(he) == 300 &&
528 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
529 !strcmp(SYM(he), "main") && he->stat.period == 100);
530
531 node = rb_next(node);
532 he = rb_entry(node, struct hist_entry, rb_node);
533 TEST_ASSERT_VAL("Invalid hist entry",
534 CPU(he) == 1 && PID(he) == 100 &&
535 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
536 !strcmp(SYM(he), "malloc") && he->stat.period == 100);
537
538 node = rb_next(node);
539 he = rb_entry(node, struct hist_entry, rb_node);
540 TEST_ASSERT_VAL("Invalid hist entry",
541 CPU(he) == 2 && PID(he) == 100 &&
542 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
543 !strcmp(SYM(he), "free") && he->stat.period == 100);
544
545 node = rb_next(node);
546 he = rb_entry(node, struct hist_entry, rb_node);
547 TEST_ASSERT_VAL("Invalid hist entry",
548 CPU(he) == 1 && PID(he) == 100 &&
549 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
550 !strcmp(SYM(he), "cmd_record") && he->stat.period == 100);
551
552 node = rb_next(node);
553 he = rb_entry(node, struct hist_entry, rb_node);
554 TEST_ASSERT_VAL("Invalid hist entry",
555 CPU(he) == 1 && PID(he) == 100 &&
556 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
557 !strcmp(SYM(he), "main") && he->stat.period == 100);
558
559 node = rb_next(node);
560 he = rb_entry(node, struct hist_entry, rb_node);
561 TEST_ASSERT_VAL("Invalid hist entry",
562 CPU(he) == 2 && PID(he) == 200 &&
563 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
564 !strcmp(SYM(he), "main") && he->stat.period == 100);
565
566out:
567 del_hist_entries(hists);
568 reset_output_field();
569 return err;
570}
571
572int test__hists_output(void)
573{
574 int err = TEST_FAIL;
575 struct machines machines;
576 struct machine *machine;
577 struct perf_evsel *evsel;
578 struct perf_evlist *evlist = perf_evlist__new();
579 size_t i;
580 test_fn_t testcases[] = {
581 test1,
582 test2,
583 test3,
584 test4,
585 test5,
586 };
587
588 TEST_ASSERT_VAL("No memory", evlist);
589
590 err = parse_events(evlist, "cpu-clock");
591 if (err)
592 goto out;
593
594 machines__init(&machines);
595
596 /* setup threads/dso/map/symbols also */
597 machine = setup_fake_machine(&machines);
598 if (!machine)
599 goto out;
600
601 if (verbose > 1)
602 machine__fprintf(machine, stderr);
603
604 evsel = perf_evlist__first(evlist);
605
606 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
607 err = testcases[i](evsel, machine);
608 if (err < 0)
609 break;
610 }
611
612out:
613 /* tear down everything */
614 perf_evlist__delete(evlist);
615 machines__exit(&machines);
616
617 return err;
618}
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index 497957f269d8..7a5ab7b0b8f6 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -1,4 +1,4 @@
1#include <sys/types.h> 1#include <linux/types.h>
2#include <unistd.h> 2#include <unistd.h>
3#include <sys/prctl.h> 3#include <sys/prctl.h>
4 4
diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c
new file mode 100644
index 000000000000..4a456fef66ca
--- /dev/null
+++ b/tools/perf/tests/mmap-thread-lookup.c
@@ -0,0 +1,233 @@
1#include <unistd.h>
2#include <sys/syscall.h>
3#include <sys/types.h>
4#include <sys/mman.h>
5#include <pthread.h>
6#include <stdlib.h>
7#include <stdio.h>
8#include "debug.h"
9#include "tests.h"
10#include "machine.h"
11#include "thread_map.h"
12#include "symbol.h"
13#include "thread.h"
14
15#define THREADS 4
16
17static int go_away;
18
19struct thread_data {
20 pthread_t pt;
21 pid_t tid;
22 void *map;
23 int ready[2];
24};
25
26static struct thread_data threads[THREADS];
27
28static int thread_init(struct thread_data *td)
29{
30 void *map;
31
32 map = mmap(NULL, page_size,
33 PROT_READ|PROT_WRITE|PROT_EXEC,
34 MAP_SHARED|MAP_ANONYMOUS, -1, 0);
35
36 if (map == MAP_FAILED) {
37 perror("mmap failed");
38 return -1;
39 }
40
41 td->map = map;
42 td->tid = syscall(SYS_gettid);
43
44 pr_debug("tid = %d, map = %p\n", td->tid, map);
45 return 0;
46}
47
48static void *thread_fn(void *arg)
49{
50 struct thread_data *td = arg;
51 ssize_t ret;
52 int go;
53
54 if (thread_init(td))
55 return NULL;
56
57 /* Signal thread_create thread is initialized. */
58 ret = write(td->ready[1], &go, sizeof(int));
59 if (ret != sizeof(int)) {
60 pr_err("failed to notify\n");
61 return NULL;
62 }
63
64 while (!go_away) {
65 /* Waiting for main thread to kill us. */
66 usleep(100);
67 }
68
69 munmap(td->map, page_size);
70 return NULL;
71}
72
73static int thread_create(int i)
74{
75 struct thread_data *td = &threads[i];
76 int err, go;
77
78 if (pipe(td->ready))
79 return -1;
80
81 err = pthread_create(&td->pt, NULL, thread_fn, td);
82 if (!err) {
83 /* Wait for thread initialization. */
84 ssize_t ret = read(td->ready[0], &go, sizeof(int));
85 err = ret != sizeof(int);
86 }
87
88 close(td->ready[0]);
89 close(td->ready[1]);
90 return err;
91}
92
93static int threads_create(void)
94{
95 struct thread_data *td0 = &threads[0];
96 int i, err = 0;
97
98 go_away = 0;
99
100 /* 0 is main thread */
101 if (thread_init(td0))
102 return -1;
103
104 for (i = 1; !err && i < THREADS; i++)
105 err = thread_create(i);
106
107 return err;
108}
109
110static int threads_destroy(void)
111{
112 struct thread_data *td0 = &threads[0];
113 int i, err = 0;
114
115 /* cleanup the main thread */
116 munmap(td0->map, page_size);
117
118 go_away = 1;
119
120 for (i = 1; !err && i < THREADS; i++)
121 err = pthread_join(threads[i].pt, NULL);
122
123 return err;
124}
125
126typedef int (*synth_cb)(struct machine *machine);
127
128static int synth_all(struct machine *machine)
129{
130 return perf_event__synthesize_threads(NULL,
131 perf_event__process,
132 machine, 0);
133}
134
135static int synth_process(struct machine *machine)
136{
137 struct thread_map *map;
138 int err;
139
140 map = thread_map__new_by_pid(getpid());
141
142 err = perf_event__synthesize_thread_map(NULL, map,
143 perf_event__process,
144 machine, 0);
145
146 thread_map__delete(map);
147 return err;
148}
149
150static int mmap_events(synth_cb synth)
151{
152 struct machines machines;
153 struct machine *machine;
154 int err, i;
155
156 /*
157 * The threads_create will not return before all threads
158 * are spawned and all created memory map.
159 *
160 * They will loop until threads_destroy is called, so we
161 * can safely run synthesizing function.
162 */
163 TEST_ASSERT_VAL("failed to create threads", !threads_create());
164
165 machines__init(&machines);
166 machine = &machines.host;
167
168 dump_trace = verbose > 1 ? 1 : 0;
169
170 err = synth(machine);
171
172 dump_trace = 0;
173
174 TEST_ASSERT_VAL("failed to destroy threads", !threads_destroy());
175 TEST_ASSERT_VAL("failed to synthesize maps", !err);
176
177 /*
178 * All data is synthesized, try to find map for each
179 * thread object.
180 */
181 for (i = 0; i < THREADS; i++) {
182 struct thread_data *td = &threads[i];
183 struct addr_location al;
184 struct thread *thread;
185
186 thread = machine__findnew_thread(machine, getpid(), td->tid);
187
188 pr_debug("looking for map %p\n", td->map);
189
190 thread__find_addr_map(thread, machine,
191 PERF_RECORD_MISC_USER, MAP__FUNCTION,
192 (unsigned long) (td->map + 1), &al);
193
194 if (!al.map) {
195 pr_debug("failed, couldn't find map\n");
196 err = -1;
197 break;
198 }
199
200 pr_debug("map %p, addr %" PRIx64 "\n", al.map, al.map->start);
201 }
202
203 machine__delete_threads(machine);
204 machines__exit(&machines);
205 return err;
206}
207
208/*
209 * This test creates 'THREADS' number of threads (including
210 * main thread) and each thread creates memory map.
211 *
212 * When threads are created, we synthesize them with both
213 * (separate tests):
214 * perf_event__synthesize_thread_map (process based)
215 * perf_event__synthesize_threads (global)
216 *
217 * We test we can find all memory maps via:
218 * thread__find_addr_map
219 *
220 * by using all thread objects.
221 */
222int test__mmap_thread_lookup(void)
223{
224 /* perf_event__synthesize_threads synthesize */
225 TEST_ASSERT_VAL("failed with sythesizing all",
226 !mmap_events(synth_all));
227
228 /* perf_event__synthesize_thread_map synthesize */
229 TEST_ASSERT_VAL("failed with sythesizing process",
230 !mmap_events(synth_process));
231
232 return 0;
233}
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 8605ff5572ae..deba66955f8c 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1174,188 +1174,240 @@ static int test__all_tracepoints(struct perf_evlist *evlist)
1174struct evlist_test { 1174struct evlist_test {
1175 const char *name; 1175 const char *name;
1176 __u32 type; 1176 __u32 type;
1177 const int id;
1177 int (*check)(struct perf_evlist *evlist); 1178 int (*check)(struct perf_evlist *evlist);
1178}; 1179};
1179 1180
1180static struct evlist_test test__events[] = { 1181static struct evlist_test test__events[] = {
1181 [0] = { 1182 {
1182 .name = "syscalls:sys_enter_open", 1183 .name = "syscalls:sys_enter_open",
1183 .check = test__checkevent_tracepoint, 1184 .check = test__checkevent_tracepoint,
1185 .id = 0,
1184 }, 1186 },
1185 [1] = { 1187 {
1186 .name = "syscalls:*", 1188 .name = "syscalls:*",
1187 .check = test__checkevent_tracepoint_multi, 1189 .check = test__checkevent_tracepoint_multi,
1190 .id = 1,
1188 }, 1191 },
1189 [2] = { 1192 {
1190 .name = "r1a", 1193 .name = "r1a",
1191 .check = test__checkevent_raw, 1194 .check = test__checkevent_raw,
1195 .id = 2,
1192 }, 1196 },
1193 [3] = { 1197 {
1194 .name = "1:1", 1198 .name = "1:1",
1195 .check = test__checkevent_numeric, 1199 .check = test__checkevent_numeric,
1200 .id = 3,
1196 }, 1201 },
1197 [4] = { 1202 {
1198 .name = "instructions", 1203 .name = "instructions",
1199 .check = test__checkevent_symbolic_name, 1204 .check = test__checkevent_symbolic_name,
1205 .id = 4,
1200 }, 1206 },
1201 [5] = { 1207 {
1202 .name = "cycles/period=100000,config2/", 1208 .name = "cycles/period=100000,config2/",
1203 .check = test__checkevent_symbolic_name_config, 1209 .check = test__checkevent_symbolic_name_config,
1210 .id = 5,
1204 }, 1211 },
1205 [6] = { 1212 {
1206 .name = "faults", 1213 .name = "faults",
1207 .check = test__checkevent_symbolic_alias, 1214 .check = test__checkevent_symbolic_alias,
1215 .id = 6,
1208 }, 1216 },
1209 [7] = { 1217 {
1210 .name = "L1-dcache-load-miss", 1218 .name = "L1-dcache-load-miss",
1211 .check = test__checkevent_genhw, 1219 .check = test__checkevent_genhw,
1220 .id = 7,
1212 }, 1221 },
1213 [8] = { 1222 {
1214 .name = "mem:0", 1223 .name = "mem:0",
1215 .check = test__checkevent_breakpoint, 1224 .check = test__checkevent_breakpoint,
1225 .id = 8,
1216 }, 1226 },
1217 [9] = { 1227 {
1218 .name = "mem:0:x", 1228 .name = "mem:0:x",
1219 .check = test__checkevent_breakpoint_x, 1229 .check = test__checkevent_breakpoint_x,
1230 .id = 9,
1220 }, 1231 },
1221 [10] = { 1232 {
1222 .name = "mem:0:r", 1233 .name = "mem:0:r",
1223 .check = test__checkevent_breakpoint_r, 1234 .check = test__checkevent_breakpoint_r,
1235 .id = 10,
1224 }, 1236 },
1225 [11] = { 1237 {
1226 .name = "mem:0:w", 1238 .name = "mem:0:w",
1227 .check = test__checkevent_breakpoint_w, 1239 .check = test__checkevent_breakpoint_w,
1240 .id = 11,
1228 }, 1241 },
1229 [12] = { 1242 {
1230 .name = "syscalls:sys_enter_open:k", 1243 .name = "syscalls:sys_enter_open:k",
1231 .check = test__checkevent_tracepoint_modifier, 1244 .check = test__checkevent_tracepoint_modifier,
1245 .id = 12,
1232 }, 1246 },
1233 [13] = { 1247 {
1234 .name = "syscalls:*:u", 1248 .name = "syscalls:*:u",
1235 .check = test__checkevent_tracepoint_multi_modifier, 1249 .check = test__checkevent_tracepoint_multi_modifier,
1250 .id = 13,
1236 }, 1251 },
1237 [14] = { 1252 {
1238 .name = "r1a:kp", 1253 .name = "r1a:kp",
1239 .check = test__checkevent_raw_modifier, 1254 .check = test__checkevent_raw_modifier,
1255 .id = 14,
1240 }, 1256 },
1241 [15] = { 1257 {
1242 .name = "1:1:hp", 1258 .name = "1:1:hp",
1243 .check = test__checkevent_numeric_modifier, 1259 .check = test__checkevent_numeric_modifier,
1260 .id = 15,
1244 }, 1261 },
1245 [16] = { 1262 {
1246 .name = "instructions:h", 1263 .name = "instructions:h",
1247 .check = test__checkevent_symbolic_name_modifier, 1264 .check = test__checkevent_symbolic_name_modifier,
1265 .id = 16,
1248 }, 1266 },
1249 [17] = { 1267 {
1250 .name = "faults:u", 1268 .name = "faults:u",
1251 .check = test__checkevent_symbolic_alias_modifier, 1269 .check = test__checkevent_symbolic_alias_modifier,
1270 .id = 17,
1252 }, 1271 },
1253 [18] = { 1272 {
1254 .name = "L1-dcache-load-miss:kp", 1273 .name = "L1-dcache-load-miss:kp",
1255 .check = test__checkevent_genhw_modifier, 1274 .check = test__checkevent_genhw_modifier,
1275 .id = 18,
1256 }, 1276 },
1257 [19] = { 1277 {
1258 .name = "mem:0:u", 1278 .name = "mem:0:u",
1259 .check = test__checkevent_breakpoint_modifier, 1279 .check = test__checkevent_breakpoint_modifier,
1280 .id = 19,
1260 }, 1281 },
1261 [20] = { 1282 {
1262 .name = "mem:0:x:k", 1283 .name = "mem:0:x:k",
1263 .check = test__checkevent_breakpoint_x_modifier, 1284 .check = test__checkevent_breakpoint_x_modifier,
1285 .id = 20,
1264 }, 1286 },
1265 [21] = { 1287 {
1266 .name = "mem:0:r:hp", 1288 .name = "mem:0:r:hp",
1267 .check = test__checkevent_breakpoint_r_modifier, 1289 .check = test__checkevent_breakpoint_r_modifier,
1290 .id = 21,
1268 }, 1291 },
1269 [22] = { 1292 {
1270 .name = "mem:0:w:up", 1293 .name = "mem:0:w:up",
1271 .check = test__checkevent_breakpoint_w_modifier, 1294 .check = test__checkevent_breakpoint_w_modifier,
1295 .id = 22,
1272 }, 1296 },
1273 [23] = { 1297 {
1274 .name = "r1,syscalls:sys_enter_open:k,1:1:hp", 1298 .name = "r1,syscalls:sys_enter_open:k,1:1:hp",
1275 .check = test__checkevent_list, 1299 .check = test__checkevent_list,
1300 .id = 23,
1276 }, 1301 },
1277 [24] = { 1302 {
1278 .name = "instructions:G", 1303 .name = "instructions:G",
1279 .check = test__checkevent_exclude_host_modifier, 1304 .check = test__checkevent_exclude_host_modifier,
1305 .id = 24,
1280 }, 1306 },
1281 [25] = { 1307 {
1282 .name = "instructions:H", 1308 .name = "instructions:H",
1283 .check = test__checkevent_exclude_guest_modifier, 1309 .check = test__checkevent_exclude_guest_modifier,
1310 .id = 25,
1284 }, 1311 },
1285 [26] = { 1312 {
1286 .name = "mem:0:rw", 1313 .name = "mem:0:rw",
1287 .check = test__checkevent_breakpoint_rw, 1314 .check = test__checkevent_breakpoint_rw,
1315 .id = 26,
1288 }, 1316 },
1289 [27] = { 1317 {
1290 .name = "mem:0:rw:kp", 1318 .name = "mem:0:rw:kp",
1291 .check = test__checkevent_breakpoint_rw_modifier, 1319 .check = test__checkevent_breakpoint_rw_modifier,
1320 .id = 27,
1292 }, 1321 },
1293 [28] = { 1322 {
1294 .name = "{instructions:k,cycles:upp}", 1323 .name = "{instructions:k,cycles:upp}",
1295 .check = test__group1, 1324 .check = test__group1,
1325 .id = 28,
1296 }, 1326 },
1297 [29] = { 1327 {
1298 .name = "{faults:k,cache-references}:u,cycles:k", 1328 .name = "{faults:k,cache-references}:u,cycles:k",
1299 .check = test__group2, 1329 .check = test__group2,
1330 .id = 29,
1300 }, 1331 },
1301 [30] = { 1332 {
1302 .name = "group1{syscalls:sys_enter_open:H,cycles:kppp},group2{cycles,1:3}:G,instructions:u", 1333 .name = "group1{syscalls:sys_enter_open:H,cycles:kppp},group2{cycles,1:3}:G,instructions:u",
1303 .check = test__group3, 1334 .check = test__group3,
1335 .id = 30,
1304 }, 1336 },
1305 [31] = { 1337 {
1306 .name = "{cycles:u,instructions:kp}:p", 1338 .name = "{cycles:u,instructions:kp}:p",
1307 .check = test__group4, 1339 .check = test__group4,
1340 .id = 31,
1308 }, 1341 },
1309 [32] = { 1342 {
1310 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles", 1343 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles",
1311 .check = test__group5, 1344 .check = test__group5,
1345 .id = 32,
1312 }, 1346 },
1313 [33] = { 1347 {
1314 .name = "*:*", 1348 .name = "*:*",
1315 .check = test__all_tracepoints, 1349 .check = test__all_tracepoints,
1350 .id = 33,
1316 }, 1351 },
1317 [34] = { 1352 {
1318 .name = "{cycles,cache-misses:G}:H", 1353 .name = "{cycles,cache-misses:G}:H",
1319 .check = test__group_gh1, 1354 .check = test__group_gh1,
1355 .id = 34,
1320 }, 1356 },
1321 [35] = { 1357 {
1322 .name = "{cycles,cache-misses:H}:G", 1358 .name = "{cycles,cache-misses:H}:G",
1323 .check = test__group_gh2, 1359 .check = test__group_gh2,
1360 .id = 35,
1324 }, 1361 },
1325 [36] = { 1362 {
1326 .name = "{cycles:G,cache-misses:H}:u", 1363 .name = "{cycles:G,cache-misses:H}:u",
1327 .check = test__group_gh3, 1364 .check = test__group_gh3,
1365 .id = 36,
1328 }, 1366 },
1329 [37] = { 1367 {
1330 .name = "{cycles:G,cache-misses:H}:uG", 1368 .name = "{cycles:G,cache-misses:H}:uG",
1331 .check = test__group_gh4, 1369 .check = test__group_gh4,
1370 .id = 37,
1332 }, 1371 },
1333 [38] = { 1372 {
1334 .name = "{cycles,cache-misses,branch-misses}:S", 1373 .name = "{cycles,cache-misses,branch-misses}:S",
1335 .check = test__leader_sample1, 1374 .check = test__leader_sample1,
1375 .id = 38,
1336 }, 1376 },
1337 [39] = { 1377 {
1338 .name = "{instructions,branch-misses}:Su", 1378 .name = "{instructions,branch-misses}:Su",
1339 .check = test__leader_sample2, 1379 .check = test__leader_sample2,
1380 .id = 39,
1340 }, 1381 },
1341 [40] = { 1382 {
1342 .name = "instructions:uDp", 1383 .name = "instructions:uDp",
1343 .check = test__checkevent_pinned_modifier, 1384 .check = test__checkevent_pinned_modifier,
1385 .id = 40,
1344 }, 1386 },
1345 [41] = { 1387 {
1346 .name = "{cycles,cache-misses,branch-misses}:D", 1388 .name = "{cycles,cache-misses,branch-misses}:D",
1347 .check = test__pinned_group, 1389 .check = test__pinned_group,
1390 .id = 41,
1391 },
1392#if defined(__s390x__)
1393 {
1394 .name = "kvm-s390:kvm_s390_create_vm",
1395 .check = test__checkevent_tracepoint,
1396 .id = 100,
1348 }, 1397 },
1398#endif
1349}; 1399};
1350 1400
1351static struct evlist_test test__events_pmu[] = { 1401static struct evlist_test test__events_pmu[] = {
1352 [0] = { 1402 {
1353 .name = "cpu/config=10,config1,config2=3,period=1000/u", 1403 .name = "cpu/config=10,config1,config2=3,period=1000/u",
1354 .check = test__checkevent_pmu, 1404 .check = test__checkevent_pmu,
1405 .id = 0,
1355 }, 1406 },
1356 [1] = { 1407 {
1357 .name = "cpu/config=1,name=krava/u,cpu/config=2/u", 1408 .name = "cpu/config=1,name=krava/u,cpu/config=2/u",
1358 .check = test__checkevent_pmu_name, 1409 .check = test__checkevent_pmu_name,
1410 .id = 1,
1359 }, 1411 },
1360}; 1412};
1361 1413
@@ -1402,7 +1454,7 @@ static int test_events(struct evlist_test *events, unsigned cnt)
1402 for (i = 0; i < cnt; i++) { 1454 for (i = 0; i < cnt; i++) {
1403 struct evlist_test *e = &events[i]; 1455 struct evlist_test *e = &events[i];
1404 1456
1405 pr_debug("running test %d '%s'\n", i, e->name); 1457 pr_debug("running test %d '%s'\n", e->id, e->name);
1406 ret1 = test_event(e); 1458 ret1 = test_event(e);
1407 if (ret1) 1459 if (ret1)
1408 ret2 = ret1; 1460 ret2 = ret1;
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
index e117b6c6a248..905019f9b740 100644
--- a/tools/perf/tests/parse-no-sample-id-all.c
+++ b/tools/perf/tests/parse-no-sample-id-all.c
@@ -1,4 +1,4 @@
1#include <sys/types.h> 1#include <linux/types.h>
2#include <stddef.h> 2#include <stddef.h>
3 3
4#include "tests.h" 4#include "tests.h"
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index 47146d388dbf..3b7cd4d32dcb 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -1,7 +1,6 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <sys/types.h>
3#include <unistd.h> 2#include <unistd.h>
4#include <inttypes.h> 3#include <linux/types.h>
5#include <sys/prctl.h> 4#include <sys/prctl.h>
6 5
7#include "parse-events.h" 6#include "parse-events.h"
diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/tests/rdpmc.c
index 46649c25fa5e..e59143fd9e71 100644
--- a/tools/perf/tests/rdpmc.c
+++ b/tools/perf/tests/rdpmc.c
@@ -2,7 +2,7 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include <signal.h> 3#include <signal.h>
4#include <sys/mman.h> 4#include <sys/mman.h>
5#include "types.h" 5#include <linux/types.h>
6#include "perf.h" 6#include "perf.h"
7#include "debug.h" 7#include "debug.h"
8#include "tests.h" 8#include "tests.h"
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 0014d3c8c21c..7ae8d17db3d9 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -1,5 +1,5 @@
1#include <stdbool.h> 1#include <stdbool.h>
2#include <inttypes.h> 2#include <linux/types.h>
3 3
4#include "util.h" 4#include "util.h"
5#include "event.h" 5#include "event.h"
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index a24795ca002d..d76c0e2e6635 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -41,8 +41,12 @@ int test__sample_parsing(void);
41int test__keep_tracking(void); 41int test__keep_tracking(void);
42int test__parse_no_sample_id_all(void); 42int test__parse_no_sample_id_all(void);
43int test__dwarf_unwind(void); 43int test__dwarf_unwind(void);
44int test__hists_filter(void);
45int test__mmap_thread_lookup(void);
46int test__thread_mg_share(void);
47int test__hists_output(void);
44 48
45#if defined(__x86_64__) || defined(__i386__) 49#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
46#ifdef HAVE_DWARF_UNWIND_SUPPORT 50#ifdef HAVE_DWARF_UNWIND_SUPPORT
47struct thread; 51struct thread;
48struct perf_sample; 52struct perf_sample;
diff --git a/tools/perf/tests/thread-mg-share.c b/tools/perf/tests/thread-mg-share.c
new file mode 100644
index 000000000000..2b2e0dbe114f
--- /dev/null
+++ b/tools/perf/tests/thread-mg-share.c
@@ -0,0 +1,90 @@
1#include "tests.h"
2#include "machine.h"
3#include "thread.h"
4#include "map.h"
5
6int test__thread_mg_share(void)
7{
8 struct machines machines;
9 struct machine *machine;
10
11 /* thread group */
12 struct thread *leader;
13 struct thread *t1, *t2, *t3;
14 struct map_groups *mg;
15
16 /* other process */
17 struct thread *other, *other_leader;
18 struct map_groups *other_mg;
19
20 /*
21 * This test create 2 processes abstractions (struct thread)
22 * with several threads and checks they properly share and
23 * maintain map groups info (struct map_groups).
24 *
25 * thread group (pid: 0, tids: 0, 1, 2, 3)
26 * other group (pid: 4, tids: 4, 5)
27 */
28
29 machines__init(&machines);
30 machine = &machines.host;
31
32 /* create process with 4 threads */
33 leader = machine__findnew_thread(machine, 0, 0);
34 t1 = machine__findnew_thread(machine, 0, 1);
35 t2 = machine__findnew_thread(machine, 0, 2);
36 t3 = machine__findnew_thread(machine, 0, 3);
37
38 /* and create 1 separated process, without thread leader */
39 other = machine__findnew_thread(machine, 4, 5);
40
41 TEST_ASSERT_VAL("failed to create threads",
42 leader && t1 && t2 && t3 && other);
43
44 mg = leader->mg;
45 TEST_ASSERT_VAL("wrong refcnt", mg->refcnt == 4);
46
47 /* test the map groups pointer is shared */
48 TEST_ASSERT_VAL("map groups don't match", mg == t1->mg);
49 TEST_ASSERT_VAL("map groups don't match", mg == t2->mg);
50 TEST_ASSERT_VAL("map groups don't match", mg == t3->mg);
51
52 /*
53 * Verify the other leader was created by previous call.
54 * It should have shared map groups with no change in
55 * refcnt.
56 */
57 other_leader = machine__find_thread(machine, 4, 4);
58 TEST_ASSERT_VAL("failed to find other leader", other_leader);
59
60 other_mg = other->mg;
61 TEST_ASSERT_VAL("wrong refcnt", other_mg->refcnt == 2);
62
63 TEST_ASSERT_VAL("map groups don't match", other_mg == other_leader->mg);
64
65 /* release thread group */
66 thread__delete(leader);
67 TEST_ASSERT_VAL("wrong refcnt", mg->refcnt == 3);
68
69 thread__delete(t1);
70 TEST_ASSERT_VAL("wrong refcnt", mg->refcnt == 2);
71
72 thread__delete(t2);
73 TEST_ASSERT_VAL("wrong refcnt", mg->refcnt == 1);
74
75 thread__delete(t3);
76
77 /* release other group */
78 thread__delete(other_leader);
79 TEST_ASSERT_VAL("wrong refcnt", other_mg->refcnt == 1);
80
81 thread__delete(other);
82
83 /*
84 * Cannot call machine__delete_threads(machine) now,
85 * because we've already released all the threads.
86 */
87
88 machines__exit(&machines);
89 return 0;
90}
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index 118cca29dd26..03d4d6295f10 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -1,9 +1,7 @@
1#ifndef _PERF_UI_BROWSER_H_ 1#ifndef _PERF_UI_BROWSER_H_
2#define _PERF_UI_BROWSER_H_ 1 2#define _PERF_UI_BROWSER_H_ 1
3 3
4#include <stdbool.h> 4#include <linux/types.h>
5#include <sys/types.h>
6#include "../types.h"
7 5
8#define HE_COLORSET_TOP 50 6#define HE_COLORSET_TOP 50
9#define HE_COLORSET_MEDIUM 51 7#define HE_COLORSET_MEDIUM 51
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 7ec871af3f6f..1c331b934ffc 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -26,13 +26,36 @@ struct hist_browser {
26 int print_seq; 26 int print_seq;
27 bool show_dso; 27 bool show_dso;
28 float min_pcnt; 28 float min_pcnt;
29 u64 nr_pcnt_entries; 29 u64 nr_non_filtered_entries;
30 u64 nr_callchain_rows;
30}; 31};
31 32
32extern void hist_browser__init_hpp(void); 33extern void hist_browser__init_hpp(void);
33 34
34static int hists__browser_title(struct hists *hists, char *bf, size_t size, 35static int hists__browser_title(struct hists *hists, char *bf, size_t size,
35 const char *ev_name); 36 const char *ev_name);
37static void hist_browser__update_nr_entries(struct hist_browser *hb);
38
39static struct rb_node *hists__filter_entries(struct rb_node *nd,
40 struct hists *hists,
41 float min_pcnt);
42
43static bool hist_browser__has_filter(struct hist_browser *hb)
44{
45 return hists__has_filter(hb->hists) || hb->min_pcnt;
46}
47
48static u32 hist_browser__nr_entries(struct hist_browser *hb)
49{
50 u32 nr_entries;
51
52 if (hist_browser__has_filter(hb))
53 nr_entries = hb->nr_non_filtered_entries;
54 else
55 nr_entries = hb->hists->nr_entries;
56
57 return nr_entries + hb->nr_callchain_rows;
58}
36 59
37static void hist_browser__refresh_dimensions(struct hist_browser *browser) 60static void hist_browser__refresh_dimensions(struct hist_browser *browser)
38{ 61{
@@ -43,7 +66,14 @@ static void hist_browser__refresh_dimensions(struct hist_browser *browser)
43 66
44static void hist_browser__reset(struct hist_browser *browser) 67static void hist_browser__reset(struct hist_browser *browser)
45{ 68{
46 browser->b.nr_entries = browser->hists->nr_entries; 69 /*
70 * The hists__remove_entry_filter() already folds non-filtered
71 * entries so we can assume it has 0 callchain rows.
72 */
73 browser->nr_callchain_rows = 0;
74
75 hist_browser__update_nr_entries(browser);
76 browser->b.nr_entries = hist_browser__nr_entries(browser);
47 hist_browser__refresh_dimensions(browser); 77 hist_browser__refresh_dimensions(browser);
48 ui_browser__reset_index(&browser->b); 78 ui_browser__reset_index(&browser->b);
49} 79}
@@ -198,14 +228,16 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
198 struct hist_entry *he = browser->he_selection; 228 struct hist_entry *he = browser->he_selection;
199 229
200 hist_entry__init_have_children(he); 230 hist_entry__init_have_children(he);
201 browser->hists->nr_entries -= he->nr_rows; 231 browser->b.nr_entries -= he->nr_rows;
232 browser->nr_callchain_rows -= he->nr_rows;
202 233
203 if (he->ms.unfolded) 234 if (he->ms.unfolded)
204 he->nr_rows = callchain__count_rows(&he->sorted_chain); 235 he->nr_rows = callchain__count_rows(&he->sorted_chain);
205 else 236 else
206 he->nr_rows = 0; 237 he->nr_rows = 0;
207 browser->hists->nr_entries += he->nr_rows; 238
208 browser->b.nr_entries = browser->hists->nr_entries; 239 browser->b.nr_entries += he->nr_rows;
240 browser->nr_callchain_rows += he->nr_rows;
209 241
210 return true; 242 return true;
211 } 243 }
@@ -280,23 +312,27 @@ static void hist_entry__set_folding(struct hist_entry *he, bool unfold)
280 he->nr_rows = 0; 312 he->nr_rows = 0;
281} 313}
282 314
283static void hists__set_folding(struct hists *hists, bool unfold) 315static void
316__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
284{ 317{
285 struct rb_node *nd; 318 struct rb_node *nd;
319 struct hists *hists = browser->hists;
286 320
287 hists->nr_entries = 0; 321 for (nd = rb_first(&hists->entries);
288 322 (nd = hists__filter_entries(nd, hists, browser->min_pcnt)) != NULL;
289 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 323 nd = rb_next(nd)) {
290 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 324 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
291 hist_entry__set_folding(he, unfold); 325 hist_entry__set_folding(he, unfold);
292 hists->nr_entries += 1 + he->nr_rows; 326 browser->nr_callchain_rows += he->nr_rows;
293 } 327 }
294} 328}
295 329
296static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 330static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
297{ 331{
298 hists__set_folding(browser->hists, unfold); 332 browser->nr_callchain_rows = 0;
299 browser->b.nr_entries = browser->hists->nr_entries; 333 __hist_browser__set_folding(browser, unfold);
334
335 browser->b.nr_entries = hist_browser__nr_entries(browser);
300 /* Go to the start, we may be way after valid entries after a collapse */ 336 /* Go to the start, we may be way after valid entries after a collapse */
301 ui_browser__reset_index(&browser->b); 337 ui_browser__reset_index(&browser->b);
302} 338}
@@ -310,8 +346,6 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
310 "Or reduce the sampling frequency."); 346 "Or reduce the sampling frequency.");
311} 347}
312 348
313static void hist_browser__update_pcnt_entries(struct hist_browser *hb);
314
315static int hist_browser__run(struct hist_browser *browser, const char *ev_name, 349static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
316 struct hist_browser_timer *hbt) 350 struct hist_browser_timer *hbt)
317{ 351{
@@ -320,9 +354,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
320 int delay_secs = hbt ? hbt->refresh : 0; 354 int delay_secs = hbt ? hbt->refresh : 0;
321 355
322 browser->b.entries = &browser->hists->entries; 356 browser->b.entries = &browser->hists->entries;
323 browser->b.nr_entries = browser->hists->nr_entries; 357 browser->b.nr_entries = hist_browser__nr_entries(browser);
324 if (browser->min_pcnt)
325 browser->b.nr_entries = browser->nr_pcnt_entries;
326 358
327 hist_browser__refresh_dimensions(browser); 359 hist_browser__refresh_dimensions(browser);
328 hists__browser_title(browser->hists, title, sizeof(title), ev_name); 360 hists__browser_title(browser->hists, title, sizeof(title), ev_name);
@@ -339,13 +371,10 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
339 u64 nr_entries; 371 u64 nr_entries;
340 hbt->timer(hbt->arg); 372 hbt->timer(hbt->arg);
341 373
342 if (browser->min_pcnt) { 374 if (hist_browser__has_filter(browser))
343 hist_browser__update_pcnt_entries(browser); 375 hist_browser__update_nr_entries(browser);
344 nr_entries = browser->nr_pcnt_entries;
345 } else {
346 nr_entries = browser->hists->nr_entries;
347 }
348 376
377 nr_entries = hist_browser__nr_entries(browser);
349 ui_browser__update_nr_entries(&browser->b, nr_entries); 378 ui_browser__update_nr_entries(&browser->b, nr_entries);
350 379
351 if (browser->hists->stats.nr_lost_warned != 380 if (browser->hists->stats.nr_lost_warned !=
@@ -587,35 +616,6 @@ struct hpp_arg {
587 bool current_entry; 616 bool current_entry;
588}; 617};
589 618
590static int __hpp__overhead_callback(struct perf_hpp *hpp, bool front)
591{
592 struct hpp_arg *arg = hpp->ptr;
593
594 if (arg->current_entry && arg->b->navkeypressed)
595 ui_browser__set_color(arg->b, HE_COLORSET_SELECTED);
596 else
597 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
598
599 if (front) {
600 if (!symbol_conf.use_callchain)
601 return 0;
602
603 slsmg_printf("%c ", arg->folded_sign);
604 return 2;
605 }
606
607 return 0;
608}
609
610static int __hpp__color_callback(struct perf_hpp *hpp, bool front __maybe_unused)
611{
612 struct hpp_arg *arg = hpp->ptr;
613
614 if (!arg->current_entry || !arg->b->navkeypressed)
615 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
616 return 0;
617}
618
619static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) 619static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
620{ 620{
621 struct hpp_arg *arg = hpp->ptr; 621 struct hpp_arg *arg = hpp->ptr;
@@ -636,7 +636,7 @@ static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
636 return ret; 636 return ret;
637} 637}
638 638
639#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \ 639#define __HPP_COLOR_PERCENT_FN(_type, _field) \
640static u64 __hpp_get_##_field(struct hist_entry *he) \ 640static u64 __hpp_get_##_field(struct hist_entry *he) \
641{ \ 641{ \
642 return he->stat._field; \ 642 return he->stat._field; \
@@ -647,22 +647,20 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
647 struct perf_hpp *hpp, \ 647 struct perf_hpp *hpp, \
648 struct hist_entry *he) \ 648 struct hist_entry *he) \
649{ \ 649{ \
650 return __hpp__fmt(hpp, he, __hpp_get_##_field, _cb, " %6.2f%%", \ 650 return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \
651 __hpp__slsmg_color_printf, true); \ 651 __hpp__slsmg_color_printf, true); \
652} 652}
653 653
654__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__overhead_callback) 654__HPP_COLOR_PERCENT_FN(overhead, period)
655__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, __hpp__color_callback) 655__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
656__HPP_COLOR_PERCENT_FN(overhead_us, period_us, __hpp__color_callback) 656__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
657__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, __hpp__color_callback) 657__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
658__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, __hpp__color_callback) 658__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
659 659
660#undef __HPP_COLOR_PERCENT_FN 660#undef __HPP_COLOR_PERCENT_FN
661 661
662void hist_browser__init_hpp(void) 662void hist_browser__init_hpp(void)
663{ 663{
664 perf_hpp__init();
665
666 perf_hpp__format[PERF_HPP__OVERHEAD].color = 664 perf_hpp__format[PERF_HPP__OVERHEAD].color =
667 hist_browser__hpp_color_overhead; 665 hist_browser__hpp_color_overhead;
668 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 666 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
@@ -700,7 +698,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
700 698
701 if (row_offset == 0) { 699 if (row_offset == 0) {
702 struct hpp_arg arg = { 700 struct hpp_arg arg = {
703 .b = &browser->b, 701 .b = &browser->b,
704 .folded_sign = folded_sign, 702 .folded_sign = folded_sign,
705 .current_entry = current_entry, 703 .current_entry = current_entry,
706 }; 704 };
@@ -713,11 +711,27 @@ static int hist_browser__show_entry(struct hist_browser *browser,
713 ui_browser__gotorc(&browser->b, row, 0); 711 ui_browser__gotorc(&browser->b, row, 0);
714 712
715 perf_hpp__for_each_format(fmt) { 713 perf_hpp__for_each_format(fmt) {
716 if (!first) { 714 if (perf_hpp__should_skip(fmt))
715 continue;
716
717 if (current_entry && browser->b.navkeypressed) {
718 ui_browser__set_color(&browser->b,
719 HE_COLORSET_SELECTED);
720 } else {
721 ui_browser__set_color(&browser->b,
722 HE_COLORSET_NORMAL);
723 }
724
725 if (first) {
726 if (symbol_conf.use_callchain) {
727 slsmg_printf("%c ", folded_sign);
728 width -= 2;
729 }
730 first = false;
731 } else {
717 slsmg_printf(" "); 732 slsmg_printf(" ");
718 width -= 2; 733 width -= 2;
719 } 734 }
720 first = false;
721 735
722 if (fmt->color) { 736 if (fmt->color) {
723 width -= fmt->color(fmt, &hpp, entry); 737 width -= fmt->color(fmt, &hpp, entry);
@@ -731,8 +745,8 @@ static int hist_browser__show_entry(struct hist_browser *browser,
731 if (!browser->b.navkeypressed) 745 if (!browser->b.navkeypressed)
732 width += 1; 746 width += 1;
733 747
734 hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists); 748 slsmg_write_nstring("", width);
735 slsmg_write_nstring(s, width); 749
736 ++row; 750 ++row;
737 ++printed; 751 ++printed;
738 } else 752 } else
@@ -769,12 +783,15 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
769 783
770 for (nd = browser->top; nd; nd = rb_next(nd)) { 784 for (nd = browser->top; nd; nd = rb_next(nd)) {
771 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 785 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
772 float percent = h->stat.period * 100.0 / 786 u64 total = hists__total_period(h->hists);
773 hb->hists->stats.total_period; 787 float percent = 0.0;
774 788
775 if (h->filtered) 789 if (h->filtered)
776 continue; 790 continue;
777 791
792 if (total)
793 percent = h->stat.period * 100.0 / total;
794
778 if (percent < hb->min_pcnt) 795 if (percent < hb->min_pcnt)
779 continue; 796 continue;
780 797
@@ -792,13 +809,13 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,
792{ 809{
793 while (nd != NULL) { 810 while (nd != NULL) {
794 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 811 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
795 float percent = h->stat.period * 100.0 / 812 u64 total = hists__total_period(hists);
796 hists->stats.total_period; 813 float percent = 0.0;
797 814
798 if (percent < min_pcnt) 815 if (total)
799 return NULL; 816 percent = h->stat.period * 100.0 / total;
800 817
801 if (!h->filtered) 818 if (!h->filtered && percent >= min_pcnt)
802 return nd; 819 return nd;
803 820
804 nd = rb_next(nd); 821 nd = rb_next(nd);
@@ -813,8 +830,11 @@ static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
813{ 830{
814 while (nd != NULL) { 831 while (nd != NULL) {
815 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 832 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
816 float percent = h->stat.period * 100.0 / 833 u64 total = hists__total_period(hists);
817 hists->stats.total_period; 834 float percent = 0.0;
835
836 if (total)
837 percent = h->stat.period * 100.0 / total;
818 838
819 if (!h->filtered && percent >= min_pcnt) 839 if (!h->filtered && percent >= min_pcnt)
820 return nd; 840 return nd;
@@ -1066,27 +1086,35 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1066 struct hist_entry *he, FILE *fp) 1086 struct hist_entry *he, FILE *fp)
1067{ 1087{
1068 char s[8192]; 1088 char s[8192];
1069 double percent;
1070 int printed = 0; 1089 int printed = 0;
1071 char folded_sign = ' '; 1090 char folded_sign = ' ';
1091 struct perf_hpp hpp = {
1092 .buf = s,
1093 .size = sizeof(s),
1094 };
1095 struct perf_hpp_fmt *fmt;
1096 bool first = true;
1097 int ret;
1072 1098
1073 if (symbol_conf.use_callchain) 1099 if (symbol_conf.use_callchain)
1074 folded_sign = hist_entry__folded(he); 1100 folded_sign = hist_entry__folded(he);
1075 1101
1076 hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
1077 percent = (he->stat.period * 100.0) / browser->hists->stats.total_period;
1078
1079 if (symbol_conf.use_callchain) 1102 if (symbol_conf.use_callchain)
1080 printed += fprintf(fp, "%c ", folded_sign); 1103 printed += fprintf(fp, "%c ", folded_sign);
1081 1104
1082 printed += fprintf(fp, " %5.2f%%", percent); 1105 perf_hpp__for_each_format(fmt) {
1083 1106 if (perf_hpp__should_skip(fmt))
1084 if (symbol_conf.show_nr_samples) 1107 continue;
1085 printed += fprintf(fp, " %11u", he->stat.nr_events);
1086 1108
1087 if (symbol_conf.show_total_period) 1109 if (!first) {
1088 printed += fprintf(fp, " %12" PRIu64, he->stat.period); 1110 ret = scnprintf(hpp.buf, hpp.size, " ");
1111 advance_hpp(&hpp, ret);
1112 } else
1113 first = false;
1089 1114
1115 ret = fmt->entry(fmt, &hpp, he);
1116 advance_hpp(&hpp, ret);
1117 }
1090 printed += fprintf(fp, "%s\n", rtrim(s)); 1118 printed += fprintf(fp, "%s\n", rtrim(s));
1091 1119
1092 if (folded_sign == '-') 1120 if (folded_sign == '-')
@@ -1189,6 +1217,11 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1189 char buf[512]; 1217 char buf[512];
1190 size_t buflen = sizeof(buf); 1218 size_t buflen = sizeof(buf);
1191 1219
1220 if (symbol_conf.filter_relative) {
1221 nr_samples = hists->stats.nr_non_filtered_samples;
1222 nr_events = hists->stats.total_non_filtered_period;
1223 }
1224
1192 if (perf_evsel__is_group_event(evsel)) { 1225 if (perf_evsel__is_group_event(evsel)) {
1193 struct perf_evsel *pos; 1226 struct perf_evsel *pos;
1194 1227
@@ -1196,8 +1229,13 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1196 ev_name = buf; 1229 ev_name = buf;
1197 1230
1198 for_each_group_member(pos, evsel) { 1231 for_each_group_member(pos, evsel) {
1199 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1232 if (symbol_conf.filter_relative) {
1200 nr_events += pos->hists.stats.total_period; 1233 nr_samples += pos->hists.stats.nr_non_filtered_samples;
1234 nr_events += pos->hists.stats.total_non_filtered_period;
1235 } else {
1236 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1237 nr_events += pos->hists.stats.total_period;
1238 }
1201 } 1239 }
1202 } 1240 }
1203 1241
@@ -1324,18 +1362,23 @@ close_file_and_continue:
1324 return ret; 1362 return ret;
1325} 1363}
1326 1364
1327static void hist_browser__update_pcnt_entries(struct hist_browser *hb) 1365static void hist_browser__update_nr_entries(struct hist_browser *hb)
1328{ 1366{
1329 u64 nr_entries = 0; 1367 u64 nr_entries = 0;
1330 struct rb_node *nd = rb_first(&hb->hists->entries); 1368 struct rb_node *nd = rb_first(&hb->hists->entries);
1331 1369
1332 while (nd) { 1370 if (hb->min_pcnt == 0) {
1371 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1372 return;
1373 }
1374
1375 while ((nd = hists__filter_entries(nd, hb->hists,
1376 hb->min_pcnt)) != NULL) {
1333 nr_entries++; 1377 nr_entries++;
1334 nd = hists__filter_entries(rb_next(nd), hb->hists, 1378 nd = rb_next(nd);
1335 hb->min_pcnt);
1336 } 1379 }
1337 1380
1338 hb->nr_pcnt_entries = nr_entries; 1381 hb->nr_non_filtered_entries = nr_entries;
1339} 1382}
1340 1383
1341static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1384static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
@@ -1370,6 +1413,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1370 "C Collapse all callchains\n" \ 1413 "C Collapse all callchains\n" \
1371 "d Zoom into current DSO\n" \ 1414 "d Zoom into current DSO\n" \
1372 "E Expand all callchains\n" \ 1415 "E Expand all callchains\n" \
1416 "F Toggle percentage of filtered entries\n" \
1373 1417
1374 /* help messages are sorted by lexical order of the hotkey */ 1418 /* help messages are sorted by lexical order of the hotkey */
1375 const char report_help[] = HIST_BROWSER_HELP_COMMON 1419 const char report_help[] = HIST_BROWSER_HELP_COMMON
@@ -1391,7 +1435,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1391 1435
1392 if (min_pcnt) { 1436 if (min_pcnt) {
1393 browser->min_pcnt = min_pcnt; 1437 browser->min_pcnt = min_pcnt;
1394 hist_browser__update_pcnt_entries(browser); 1438 hist_browser__update_nr_entries(browser);
1395 } 1439 }
1396 1440
1397 fstack = pstack__new(2); 1441 fstack = pstack__new(2);
@@ -1475,6 +1519,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1475 if (env->arch) 1519 if (env->arch)
1476 tui__header_window(env); 1520 tui__header_window(env);
1477 continue; 1521 continue;
1522 case 'F':
1523 symbol_conf.filter_relative ^= 1;
1524 continue;
1478 case K_F1: 1525 case K_F1:
1479 case 'h': 1526 case 'h':
1480 case '?': 1527 case '?':
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index e395ef9b0ae0..9d90683914d4 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -43,7 +43,7 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,
43 struct perf_hpp *hpp, \ 43 struct perf_hpp *hpp, \
44 struct hist_entry *he) \ 44 struct hist_entry *he) \
45{ \ 45{ \
46 return __hpp__fmt(hpp, he, he_get_##_field, NULL, " %6.2f%%", \ 46 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
47 __percent_color_snprintf, true); \ 47 __percent_color_snprintf, true); \
48} 48}
49 49
@@ -58,8 +58,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
58 58
59void perf_gtk__init_hpp(void) 59void perf_gtk__init_hpp(void)
60{ 60{
61 perf_hpp__init();
62
63 perf_hpp__format[PERF_HPP__OVERHEAD].color = 61 perf_hpp__format[PERF_HPP__OVERHEAD].color =
64 perf_gtk__hpp_color_overhead; 62 perf_gtk__hpp_color_overhead;
65 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = 63 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
@@ -153,7 +151,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
153 struct perf_hpp_fmt *fmt; 151 struct perf_hpp_fmt *fmt;
154 GType col_types[MAX_COLUMNS]; 152 GType col_types[MAX_COLUMNS];
155 GtkCellRenderer *renderer; 153 GtkCellRenderer *renderer;
156 struct sort_entry *se;
157 GtkTreeStore *store; 154 GtkTreeStore *store;
158 struct rb_node *nd; 155 struct rb_node *nd;
159 GtkWidget *view; 156 GtkWidget *view;
@@ -172,16 +169,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
172 perf_hpp__for_each_format(fmt) 169 perf_hpp__for_each_format(fmt)
173 col_types[nr_cols++] = G_TYPE_STRING; 170 col_types[nr_cols++] = G_TYPE_STRING;
174 171
175 list_for_each_entry(se, &hist_entry__sort_list, list) {
176 if (se->elide)
177 continue;
178
179 if (se == &sort_sym)
180 sym_col = nr_cols;
181
182 col_types[nr_cols++] = G_TYPE_STRING;
183 }
184
185 store = gtk_tree_store_newv(nr_cols, col_types); 172 store = gtk_tree_store_newv(nr_cols, col_types);
186 173
187 view = gtk_tree_view_new(); 174 view = gtk_tree_view_new();
@@ -191,6 +178,9 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
191 col_idx = 0; 178 col_idx = 0;
192 179
193 perf_hpp__for_each_format(fmt) { 180 perf_hpp__for_each_format(fmt) {
181 if (perf_hpp__should_skip(fmt))
182 continue;
183
194 fmt->header(fmt, &hpp, hists_to_evsel(hists)); 184 fmt->header(fmt, &hpp, hists_to_evsel(hists));
195 185
196 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 186 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
@@ -199,16 +189,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
199 col_idx++, NULL); 189 col_idx++, NULL);
200 } 190 }
201 191
202 list_for_each_entry(se, &hist_entry__sort_list, list) {
203 if (se->elide)
204 continue;
205
206 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
207 -1, se->se_header,
208 renderer, "text",
209 col_idx++, NULL);
210 }
211
212 for (col_idx = 0; col_idx < nr_cols; col_idx++) { 192 for (col_idx = 0; col_idx < nr_cols; col_idx++) {
213 GtkTreeViewColumn *column; 193 GtkTreeViewColumn *column;
214 194
@@ -228,12 +208,15 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
228 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 208 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
229 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 209 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
230 GtkTreeIter iter; 210 GtkTreeIter iter;
231 float percent = h->stat.period * 100.0 / 211 u64 total = hists__total_period(h->hists);
232 hists->stats.total_period; 212 float percent = 0.0;
233 213
234 if (h->filtered) 214 if (h->filtered)
235 continue; 215 continue;
236 216
217 if (total)
218 percent = h->stat.period * 100.0 / total;
219
237 if (percent < min_pcnt) 220 if (percent < min_pcnt)
238 continue; 221 continue;
239 222
@@ -242,6 +225,9 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
242 col_idx = 0; 225 col_idx = 0;
243 226
244 perf_hpp__for_each_format(fmt) { 227 perf_hpp__for_each_format(fmt) {
228 if (perf_hpp__should_skip(fmt))
229 continue;
230
245 if (fmt->color) 231 if (fmt->color)
246 fmt->color(fmt, &hpp, h); 232 fmt->color(fmt, &hpp, h);
247 else 233 else
@@ -250,23 +236,9 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
250 gtk_tree_store_set(store, &iter, col_idx++, s, -1); 236 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
251 } 237 }
252 238
253 list_for_each_entry(se, &hist_entry__sort_list, list) {
254 if (se->elide)
255 continue;
256
257 se->se_snprintf(h, s, ARRAY_SIZE(s),
258 hists__col_len(hists, se->se_width_idx));
259
260 gtk_tree_store_set(store, &iter, col_idx++, s, -1);
261 }
262
263 if (symbol_conf.use_callchain && sort__has_sym) { 239 if (symbol_conf.use_callchain && sort__has_sym) {
264 u64 total;
265
266 if (callchain_param.mode == CHAIN_GRAPH_REL) 240 if (callchain_param.mode == CHAIN_GRAPH_REL)
267 total = h->stat.period; 241 total = h->stat.period;
268 else
269 total = hists->stats.total_period;
270 242
271 perf_gtk__add_callchain(&h->sorted_chain, store, &iter, 243 perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
272 sym_col, total); 244 sym_col, total);
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 0f403b83e9d1..4484f5bd1b14 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -16,30 +16,25 @@
16}) 16})
17 17
18int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 18int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
19 hpp_field_fn get_field, hpp_callback_fn callback, 19 hpp_field_fn get_field, const char *fmt,
20 const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent) 20 hpp_snprint_fn print_fn, bool fmt_percent)
21{ 21{
22 int ret = 0; 22 int ret;
23 struct hists *hists = he->hists; 23 struct hists *hists = he->hists;
24 struct perf_evsel *evsel = hists_to_evsel(hists); 24 struct perf_evsel *evsel = hists_to_evsel(hists);
25 char *buf = hpp->buf; 25 char *buf = hpp->buf;
26 size_t size = hpp->size; 26 size_t size = hpp->size;
27 27
28 if (callback) {
29 ret = callback(hpp, true);
30 advance_hpp(hpp, ret);
31 }
32
33 if (fmt_percent) { 28 if (fmt_percent) {
34 double percent = 0.0; 29 double percent = 0.0;
30 u64 total = hists__total_period(hists);
35 31
36 if (hists->stats.total_period) 32 if (total)
37 percent = 100.0 * get_field(he) / 33 percent = 100.0 * get_field(he) / total;
38 hists->stats.total_period;
39 34
40 ret += hpp__call_print_fn(hpp, print_fn, fmt, percent); 35 ret = hpp__call_print_fn(hpp, print_fn, fmt, percent);
41 } else 36 } else
42 ret += hpp__call_print_fn(hpp, print_fn, fmt, get_field(he)); 37 ret = hpp__call_print_fn(hpp, print_fn, fmt, get_field(he));
43 38
44 if (perf_evsel__is_group_event(evsel)) { 39 if (perf_evsel__is_group_event(evsel)) {
45 int prev_idx, idx_delta; 40 int prev_idx, idx_delta;
@@ -50,7 +45,7 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
50 45
51 list_for_each_entry(pair, &he->pairs.head, pairs.node) { 46 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
52 u64 period = get_field(pair); 47 u64 period = get_field(pair);
53 u64 total = pair->hists->stats.total_period; 48 u64 total = hists__total_period(pair->hists);
54 49
55 if (!total) 50 if (!total)
56 continue; 51 continue;
@@ -99,13 +94,6 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
99 } 94 }
100 } 95 }
101 96
102 if (callback) {
103 int __ret = callback(hpp, false);
104
105 advance_hpp(hpp, __ret);
106 ret += __ret;
107 }
108
109 /* 97 /*
110 * Restore original buf and size as it's where caller expects 98 * Restore original buf and size as it's where caller expects
111 * the result will be saved. 99 * the result will be saved.
@@ -116,6 +104,62 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
116 return ret; 104 return ret;
117} 105}
118 106
107static int field_cmp(u64 field_a, u64 field_b)
108{
109 if (field_a > field_b)
110 return 1;
111 if (field_a < field_b)
112 return -1;
113 return 0;
114}
115
116static int __hpp__sort(struct hist_entry *a, struct hist_entry *b,
117 hpp_field_fn get_field)
118{
119 s64 ret;
120 int i, nr_members;
121 struct perf_evsel *evsel;
122 struct hist_entry *pair;
123 u64 *fields_a, *fields_b;
124
125 ret = field_cmp(get_field(a), get_field(b));
126 if (ret || !symbol_conf.event_group)
127 return ret;
128
129 evsel = hists_to_evsel(a->hists);
130 if (!perf_evsel__is_group_event(evsel))
131 return ret;
132
133 nr_members = evsel->nr_members;
134 fields_a = calloc(sizeof(*fields_a), nr_members);
135 fields_b = calloc(sizeof(*fields_b), nr_members);
136
137 if (!fields_a || !fields_b)
138 goto out;
139
140 list_for_each_entry(pair, &a->pairs.head, pairs.node) {
141 evsel = hists_to_evsel(pair->hists);
142 fields_a[perf_evsel__group_idx(evsel)] = get_field(pair);
143 }
144
145 list_for_each_entry(pair, &b->pairs.head, pairs.node) {
146 evsel = hists_to_evsel(pair->hists);
147 fields_b[perf_evsel__group_idx(evsel)] = get_field(pair);
148 }
149
150 for (i = 1; i < nr_members; i++) {
151 ret = field_cmp(fields_a[i], fields_b[i]);
152 if (ret)
153 break;
154 }
155
156out:
157 free(fields_a);
158 free(fields_b);
159
160 return ret;
161}
162
119#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 163#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
120static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 164static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
121 struct perf_hpp *hpp, \ 165 struct perf_hpp *hpp, \
@@ -179,7 +223,7 @@ static u64 he_get_##_field(struct hist_entry *he) \
179static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 223static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
180 struct perf_hpp *hpp, struct hist_entry *he) \ 224 struct perf_hpp *hpp, struct hist_entry *he) \
181{ \ 225{ \
182 return __hpp__fmt(hpp, he, he_get_##_field, NULL, " %6.2f%%", \ 226 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
183 hpp_color_scnprintf, true); \ 227 hpp_color_scnprintf, true); \
184} 228}
185 229
@@ -188,10 +232,16 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
188 struct perf_hpp *hpp, struct hist_entry *he) \ 232 struct perf_hpp *hpp, struct hist_entry *he) \
189{ \ 233{ \
190 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ 234 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
191 return __hpp__fmt(hpp, he, he_get_##_field, NULL, fmt, \ 235 return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
192 hpp_entry_scnprintf, true); \ 236 hpp_entry_scnprintf, true); \
193} 237}
194 238
239#define __HPP_SORT_FN(_type, _field) \
240static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \
241{ \
242 return __hpp__sort(a, b, he_get_##_field); \
243}
244
195#define __HPP_ENTRY_RAW_FN(_type, _field) \ 245#define __HPP_ENTRY_RAW_FN(_type, _field) \
196static u64 he_get_raw_##_field(struct hist_entry *he) \ 246static u64 he_get_raw_##_field(struct hist_entry *he) \
197{ \ 247{ \
@@ -202,20 +252,29 @@ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
202 struct perf_hpp *hpp, struct hist_entry *he) \ 252 struct perf_hpp *hpp, struct hist_entry *he) \
203{ \ 253{ \
204 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ 254 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
205 return __hpp__fmt(hpp, he, he_get_raw_##_field, NULL, fmt, \ 255 return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, \
206 hpp_entry_scnprintf, false); \ 256 hpp_entry_scnprintf, false); \
207} 257}
208 258
259#define __HPP_SORT_RAW_FN(_type, _field) \
260static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \
261{ \
262 return __hpp__sort(a, b, he_get_raw_##_field); \
263}
264
265
209#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ 266#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \
210__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 267__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
211__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ 268__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
212__HPP_COLOR_PERCENT_FN(_type, _field) \ 269__HPP_COLOR_PERCENT_FN(_type, _field) \
213__HPP_ENTRY_PERCENT_FN(_type, _field) 270__HPP_ENTRY_PERCENT_FN(_type, _field) \
271__HPP_SORT_FN(_type, _field)
214 272
215#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ 273#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \
216__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 274__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
217__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ 275__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
218__HPP_ENTRY_RAW_FN(_type, _field) 276__HPP_ENTRY_RAW_FN(_type, _field) \
277__HPP_SORT_RAW_FN(_type, _field)
219 278
220 279
221HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) 280HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
@@ -227,19 +286,31 @@ HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
227HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) 286HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
228HPP_RAW_FNS(period, "Period", period, 12, 12) 287HPP_RAW_FNS(period, "Period", period, 12, 12)
229 288
289static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused,
290 struct hist_entry *b __maybe_unused)
291{
292 return 0;
293}
294
230#define HPP__COLOR_PRINT_FNS(_name) \ 295#define HPP__COLOR_PRINT_FNS(_name) \
231 { \ 296 { \
232 .header = hpp__header_ ## _name, \ 297 .header = hpp__header_ ## _name, \
233 .width = hpp__width_ ## _name, \ 298 .width = hpp__width_ ## _name, \
234 .color = hpp__color_ ## _name, \ 299 .color = hpp__color_ ## _name, \
235 .entry = hpp__entry_ ## _name \ 300 .entry = hpp__entry_ ## _name, \
301 .cmp = hpp__nop_cmp, \
302 .collapse = hpp__nop_cmp, \
303 .sort = hpp__sort_ ## _name, \
236 } 304 }
237 305
238#define HPP__PRINT_FNS(_name) \ 306#define HPP__PRINT_FNS(_name) \
239 { \ 307 { \
240 .header = hpp__header_ ## _name, \ 308 .header = hpp__header_ ## _name, \
241 .width = hpp__width_ ## _name, \ 309 .width = hpp__width_ ## _name, \
242 .entry = hpp__entry_ ## _name \ 310 .entry = hpp__entry_ ## _name, \
311 .cmp = hpp__nop_cmp, \
312 .collapse = hpp__nop_cmp, \
313 .sort = hpp__sort_ ## _name, \
243 } 314 }
244 315
245struct perf_hpp_fmt perf_hpp__format[] = { 316struct perf_hpp_fmt perf_hpp__format[] = {
@@ -253,6 +324,7 @@ struct perf_hpp_fmt perf_hpp__format[] = {
253}; 324};
254 325
255LIST_HEAD(perf_hpp__list); 326LIST_HEAD(perf_hpp__list);
327LIST_HEAD(perf_hpp__sort_list);
256 328
257 329
258#undef HPP__COLOR_PRINT_FNS 330#undef HPP__COLOR_PRINT_FNS
@@ -270,6 +342,25 @@ LIST_HEAD(perf_hpp__list);
270 342
271void perf_hpp__init(void) 343void perf_hpp__init(void)
272{ 344{
345 struct list_head *list;
346 int i;
347
348 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
349 struct perf_hpp_fmt *fmt = &perf_hpp__format[i];
350
351 INIT_LIST_HEAD(&fmt->list);
352
353 /* sort_list may be linked by setup_sorting() */
354 if (fmt->sort_list.next == NULL)
355 INIT_LIST_HEAD(&fmt->sort_list);
356 }
357
358 /*
359 * If user specified field order, no need to setup default fields.
360 */
361 if (field_order)
362 return;
363
273 perf_hpp__column_enable(PERF_HPP__OVERHEAD); 364 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
274 365
275 if (symbol_conf.show_cpu_utilization) { 366 if (symbol_conf.show_cpu_utilization) {
@@ -287,6 +378,11 @@ void perf_hpp__init(void)
287 378
288 if (symbol_conf.show_total_period) 379 if (symbol_conf.show_total_period)
289 perf_hpp__column_enable(PERF_HPP__PERIOD); 380 perf_hpp__column_enable(PERF_HPP__PERIOD);
381
382 /* prepend overhead field for backward compatiblity. */
383 list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list;
384 if (list_empty(list))
385 list_add(list, &perf_hpp__sort_list);
290} 386}
291 387
292void perf_hpp__column_register(struct perf_hpp_fmt *format) 388void perf_hpp__column_register(struct perf_hpp_fmt *format)
@@ -294,29 +390,90 @@ void perf_hpp__column_register(struct perf_hpp_fmt *format)
294 list_add_tail(&format->list, &perf_hpp__list); 390 list_add_tail(&format->list, &perf_hpp__list);
295} 391}
296 392
393void perf_hpp__register_sort_field(struct perf_hpp_fmt *format)
394{
395 list_add_tail(&format->sort_list, &perf_hpp__sort_list);
396}
397
297void perf_hpp__column_enable(unsigned col) 398void perf_hpp__column_enable(unsigned col)
298{ 399{
299 BUG_ON(col >= PERF_HPP__MAX_INDEX); 400 BUG_ON(col >= PERF_HPP__MAX_INDEX);
300 perf_hpp__column_register(&perf_hpp__format[col]); 401 perf_hpp__column_register(&perf_hpp__format[col]);
301} 402}
302 403
303int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, 404void perf_hpp__setup_output_field(void)
304 struct hists *hists)
305{ 405{
306 const char *sep = symbol_conf.field_sep; 406 struct perf_hpp_fmt *fmt;
307 struct sort_entry *se;
308 int ret = 0;
309 407
310 list_for_each_entry(se, &hist_entry__sort_list, list) { 408 /* append sort keys to output field */
311 if (se->elide) 409 perf_hpp__for_each_sort_list(fmt) {
410 if (!list_empty(&fmt->list))
312 continue; 411 continue;
313 412
314 ret += scnprintf(s + ret, size - ret, "%s", sep ?: " "); 413 /*
315 ret += se->se_snprintf(he, s + ret, size - ret, 414 * sort entry fields are dynamically created,
316 hists__col_len(hists, se->se_width_idx)); 415 * so they can share a same sort key even though
416 * the list is empty.
417 */
418 if (perf_hpp__is_sort_entry(fmt)) {
419 struct perf_hpp_fmt *pos;
420
421 perf_hpp__for_each_format(pos) {
422 if (perf_hpp__same_sort_entry(pos, fmt))
423 goto next;
424 }
425 }
426
427 perf_hpp__column_register(fmt);
428next:
429 continue;
317 } 430 }
431}
318 432
319 return ret; 433void perf_hpp__append_sort_keys(void)
434{
435 struct perf_hpp_fmt *fmt;
436
437 /* append output fields to sort keys */
438 perf_hpp__for_each_format(fmt) {
439 if (!list_empty(&fmt->sort_list))
440 continue;
441
442 /*
443 * sort entry fields are dynamically created,
444 * so they can share a same sort key even though
445 * the list is empty.
446 */
447 if (perf_hpp__is_sort_entry(fmt)) {
448 struct perf_hpp_fmt *pos;
449
450 perf_hpp__for_each_sort_list(pos) {
451 if (perf_hpp__same_sort_entry(pos, fmt))
452 goto next;
453 }
454 }
455
456 perf_hpp__register_sort_field(fmt);
457next:
458 continue;
459 }
460}
461
462void perf_hpp__reset_output_field(void)
463{
464 struct perf_hpp_fmt *fmt, *tmp;
465
466 /* reset output fields */
467 perf_hpp__for_each_format_safe(fmt, tmp) {
468 list_del_init(&fmt->list);
469 list_del_init(&fmt->sort_list);
470 }
471
472 /* reset sort keys */
473 perf_hpp__for_each_sort_list_safe(fmt, tmp) {
474 list_del_init(&fmt->list);
475 list_del_init(&fmt->sort_list);
476 }
320} 477}
321 478
322/* 479/*
@@ -325,22 +482,23 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
325unsigned int hists__sort_list_width(struct hists *hists) 482unsigned int hists__sort_list_width(struct hists *hists)
326{ 483{
327 struct perf_hpp_fmt *fmt; 484 struct perf_hpp_fmt *fmt;
328 struct sort_entry *se; 485 int ret = 0;
329 int i = 0, ret = 0; 486 bool first = true;
330 struct perf_hpp dummy_hpp; 487 struct perf_hpp dummy_hpp;
331 488
332 perf_hpp__for_each_format(fmt) { 489 perf_hpp__for_each_format(fmt) {
333 if (i) 490 if (perf_hpp__should_skip(fmt))
491 continue;
492
493 if (first)
494 first = false;
495 else
334 ret += 2; 496 ret += 2;
335 497
336 ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); 498 ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
337 } 499 }
338 500
339 list_for_each_entry(se, &hist_entry__sort_list, list) 501 if (verbose && sort__has_sym) /* Addr + origin */
340 if (!se->elide)
341 ret += 2 + hists__col_len(hists, se->se_width_idx);
342
343 if (verbose) /* Addr + origin */
344 ret += 3 + BITS_PER_LONG / 4; 502 ret += 3 + BITS_PER_LONG / 4;
345 503
346 return ret; 504 return ret;
diff --git a/tools/perf/ui/progress.h b/tools/perf/ui/progress.h
index 29ec8efffefb..f34f89eb607c 100644
--- a/tools/perf/ui/progress.h
+++ b/tools/perf/ui/progress.h
@@ -1,7 +1,7 @@
1#ifndef _PERF_UI_PROGRESS_H_ 1#ifndef _PERF_UI_PROGRESS_H_
2#define _PERF_UI_PROGRESS_H_ 1 2#define _PERF_UI_PROGRESS_H_ 1
3 3
4#include <../types.h> 4#include <linux/types.h>
5 5
6void ui_progress__finish(void); 6void ui_progress__finish(void);
7 7
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index 5df5140a9f29..ba51fa8a1176 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -86,8 +86,6 @@ void setup_browser(bool fallback_to_pager)
86 use_browser = 0; 86 use_browser = 0;
87 if (fallback_to_pager) 87 if (fallback_to_pager)
88 setup_pager(); 88 setup_pager();
89
90 perf_hpp__init();
91 break; 89 break;
92 } 90 }
93} 91}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index d59893edf031..9f57991025a9 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -183,7 +183,8 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
183 * the symbol. No need to print it otherwise it appears as 183 * the symbol. No need to print it otherwise it appears as
184 * displayed twice. 184 * displayed twice.
185 */ 185 */
186 if (!i++ && sort__first_dimension == SORT_SYM) 186 if (!i++ && field_order == NULL &&
187 sort_order && !prefixcmp(sort_order, "sym"))
187 continue; 188 continue;
188 if (!printed) { 189 if (!printed) {
189 ret += callchain__fprintf_left_margin(fp, left_margin); 190 ret += callchain__fprintf_left_margin(fp, left_margin);
@@ -296,18 +297,24 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
296 int left_margin = 0; 297 int left_margin = 0;
297 u64 total_period = hists->stats.total_period; 298 u64 total_period = hists->stats.total_period;
298 299
299 if (sort__first_dimension == SORT_COMM) { 300 if (field_order == NULL && (sort_order == NULL ||
300 struct sort_entry *se = list_first_entry(&hist_entry__sort_list, 301 !prefixcmp(sort_order, "comm"))) {
301 typeof(*se), list); 302 struct perf_hpp_fmt *fmt;
302 left_margin = hists__col_len(hists, se->se_width_idx); 303
303 left_margin -= thread__comm_len(he->thread); 304 perf_hpp__for_each_format(fmt) {
304 } 305 if (!perf_hpp__is_sort_entry(fmt))
306 continue;
305 307
308 /* must be 'comm' sort entry */
309 left_margin = fmt->width(fmt, NULL, hists_to_evsel(hists));
310 left_margin -= thread__comm_len(he->thread);
311 break;
312 }
313 }
306 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); 314 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
307} 315}
308 316
309static int hist_entry__period_snprintf(struct perf_hpp *hpp, 317static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
310 struct hist_entry *he)
311{ 318{
312 const char *sep = symbol_conf.field_sep; 319 const char *sep = symbol_conf.field_sep;
313 struct perf_hpp_fmt *fmt; 320 struct perf_hpp_fmt *fmt;
@@ -319,6 +326,9 @@ static int hist_entry__period_snprintf(struct perf_hpp *hpp,
319 return 0; 326 return 0;
320 327
321 perf_hpp__for_each_format(fmt) { 328 perf_hpp__for_each_format(fmt) {
329 if (perf_hpp__should_skip(fmt))
330 continue;
331
322 /* 332 /*
323 * If there's no field_sep, we still need 333 * If there's no field_sep, we still need
324 * to display initial ' '. 334 * to display initial ' '.
@@ -353,8 +363,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
353 if (size == 0 || size > bfsz) 363 if (size == 0 || size > bfsz)
354 size = hpp.size = bfsz; 364 size = hpp.size = bfsz;
355 365
356 ret = hist_entry__period_snprintf(&hpp, he); 366 hist_entry__snprintf(he, &hpp);
357 hist_entry__sort_snprintf(he, bf + ret, size - ret, hists);
358 367
359 ret = fprintf(fp, "%s\n", bf); 368 ret = fprintf(fp, "%s\n", bf);
360 369
@@ -368,12 +377,10 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
368 int max_cols, float min_pcnt, FILE *fp) 377 int max_cols, float min_pcnt, FILE *fp)
369{ 378{
370 struct perf_hpp_fmt *fmt; 379 struct perf_hpp_fmt *fmt;
371 struct sort_entry *se;
372 struct rb_node *nd; 380 struct rb_node *nd;
373 size_t ret = 0; 381 size_t ret = 0;
374 unsigned int width; 382 unsigned int width;
375 const char *sep = symbol_conf.field_sep; 383 const char *sep = symbol_conf.field_sep;
376 const char *col_width = symbol_conf.col_width_list_str;
377 int nr_rows = 0; 384 int nr_rows = 0;
378 char bf[96]; 385 char bf[96];
379 struct perf_hpp dummy_hpp = { 386 struct perf_hpp dummy_hpp = {
@@ -386,12 +393,19 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
386 393
387 init_rem_hits(); 394 init_rem_hits();
388 395
396
397 perf_hpp__for_each_format(fmt)
398 perf_hpp__reset_width(fmt, hists);
399
389 if (!show_header) 400 if (!show_header)
390 goto print_entries; 401 goto print_entries;
391 402
392 fprintf(fp, "# "); 403 fprintf(fp, "# ");
393 404
394 perf_hpp__for_each_format(fmt) { 405 perf_hpp__for_each_format(fmt) {
406 if (perf_hpp__should_skip(fmt))
407 continue;
408
395 if (!first) 409 if (!first)
396 fprintf(fp, "%s", sep ?: " "); 410 fprintf(fp, "%s", sep ?: " ");
397 else 411 else
@@ -401,28 +415,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
401 fprintf(fp, "%s", bf); 415 fprintf(fp, "%s", bf);
402 } 416 }
403 417
404 list_for_each_entry(se, &hist_entry__sort_list, list) {
405 if (se->elide)
406 continue;
407 if (sep) {
408 fprintf(fp, "%c%s", *sep, se->se_header);
409 continue;
410 }
411 width = strlen(se->se_header);
412 if (symbol_conf.col_width_list_str) {
413 if (col_width) {
414 hists__set_col_len(hists, se->se_width_idx,
415 atoi(col_width));
416 col_width = strchr(col_width, ',');
417 if (col_width)
418 ++col_width;
419 }
420 }
421 if (!hists__new_col_len(hists, se->se_width_idx, width))
422 width = hists__col_len(hists, se->se_width_idx);
423 fprintf(fp, " %*s", width, se->se_header);
424 }
425
426 fprintf(fp, "\n"); 418 fprintf(fp, "\n");
427 if (max_rows && ++nr_rows >= max_rows) 419 if (max_rows && ++nr_rows >= max_rows)
428 goto out; 420 goto out;
@@ -437,6 +429,9 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
437 perf_hpp__for_each_format(fmt) { 429 perf_hpp__for_each_format(fmt) {
438 unsigned int i; 430 unsigned int i;
439 431
432 if (perf_hpp__should_skip(fmt))
433 continue;
434
440 if (!first) 435 if (!first)
441 fprintf(fp, "%s", sep ?: " "); 436 fprintf(fp, "%s", sep ?: " ");
442 else 437 else
@@ -447,20 +442,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
447 fprintf(fp, "."); 442 fprintf(fp, ".");
448 } 443 }
449 444
450 list_for_each_entry(se, &hist_entry__sort_list, list) {
451 unsigned int i;
452
453 if (se->elide)
454 continue;
455
456 fprintf(fp, " ");
457 width = hists__col_len(hists, se->se_width_idx);
458 if (width == 0)
459 width = strlen(se->se_header);
460 for (i = 0; i < width; i++)
461 fprintf(fp, ".");
462 }
463
464 fprintf(fp, "\n"); 445 fprintf(fp, "\n");
465 if (max_rows && ++nr_rows >= max_rows) 446 if (max_rows && ++nr_rows >= max_rows)
466 goto out; 447 goto out;
@@ -495,7 +476,7 @@ print_entries:
495 break; 476 break;
496 477
497 if (h->ms.map == NULL && verbose > 1) { 478 if (h->ms.map == NULL && verbose > 1) {
498 __map_groups__fprintf_maps(&h->thread->mg, 479 __map_groups__fprintf_maps(h->thread->mg,
499 MAP__FUNCTION, verbose, fp); 480 MAP__FUNCTION, verbose, fp);
500 fprintf(fp, "%.10s end\n", graph_dotted_line); 481 fprintf(fp, "%.10s end\n", graph_dotted_line);
501 } 482 }
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 56ad4f5287de..112d6e268150 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -3,7 +3,7 @@
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <stdint.h> 5#include <stdint.h>
6#include "types.h" 6#include <linux/types.h>
7#include "symbol.h" 7#include "symbol.h"
8#include "hist.h" 8#include "hist.h"
9#include "sort.h" 9#include "sort.h"
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 6baabe63182b..a904a4cfe7d3 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -25,7 +25,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
25 struct addr_location al; 25 struct addr_location al;
26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
27 struct thread *thread = machine__findnew_thread(machine, sample->pid, 27 struct thread *thread = machine__findnew_thread(machine, sample->pid,
28 sample->pid); 28 sample->tid);
29 29
30 if (thread == NULL) { 30 if (thread == NULL) {
31 pr_err("problem processing %d event, skipping it.\n", 31 pr_err("problem processing %d event, skipping it.\n",
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 845ef865eced..ae392561470b 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -4,7 +4,7 @@
4#define BUILD_ID_SIZE 20 4#define BUILD_ID_SIZE 20
5 5
6#include "tool.h" 6#include "tool.h"
7#include "types.h" 7#include <linux/types.h>
8 8
9extern struct perf_tool build_id__mark_dso_hit_ops; 9extern struct perf_tool build_id__mark_dso_hit_ops;
10struct dso; 10struct dso;
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 8d9db454f1a9..9a42382b3921 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -25,6 +25,84 @@
25 25
26__thread struct callchain_cursor callchain_cursor; 26__thread struct callchain_cursor callchain_cursor;
27 27
28int
29parse_callchain_report_opt(const char *arg)
30{
31 char *tok, *tok2;
32 char *endptr;
33
34 symbol_conf.use_callchain = true;
35
36 if (!arg)
37 return 0;
38
39 tok = strtok((char *)arg, ",");
40 if (!tok)
41 return -1;
42
43 /* get the output mode */
44 if (!strncmp(tok, "graph", strlen(arg))) {
45 callchain_param.mode = CHAIN_GRAPH_ABS;
46
47 } else if (!strncmp(tok, "flat", strlen(arg))) {
48 callchain_param.mode = CHAIN_FLAT;
49 } else if (!strncmp(tok, "fractal", strlen(arg))) {
50 callchain_param.mode = CHAIN_GRAPH_REL;
51 } else if (!strncmp(tok, "none", strlen(arg))) {
52 callchain_param.mode = CHAIN_NONE;
53 symbol_conf.use_callchain = false;
54 return 0;
55 } else {
56 return -1;
57 }
58
59 /* get the min percentage */
60 tok = strtok(NULL, ",");
61 if (!tok)
62 goto setup;
63
64 callchain_param.min_percent = strtod(tok, &endptr);
65 if (tok == endptr)
66 return -1;
67
68 /* get the print limit */
69 tok2 = strtok(NULL, ",");
70 if (!tok2)
71 goto setup;
72
73 if (tok2[0] != 'c') {
74 callchain_param.print_limit = strtoul(tok2, &endptr, 0);
75 tok2 = strtok(NULL, ",");
76 if (!tok2)
77 goto setup;
78 }
79
80 /* get the call chain order */
81 if (!strncmp(tok2, "caller", strlen("caller")))
82 callchain_param.order = ORDER_CALLER;
83 else if (!strncmp(tok2, "callee", strlen("callee")))
84 callchain_param.order = ORDER_CALLEE;
85 else
86 return -1;
87
88 /* Get the sort key */
89 tok2 = strtok(NULL, ",");
90 if (!tok2)
91 goto setup;
92 if (!strncmp(tok2, "function", strlen("function")))
93 callchain_param.key = CCKEY_FUNCTION;
94 else if (!strncmp(tok2, "address", strlen("address")))
95 callchain_param.key = CCKEY_ADDRESS;
96 else
97 return -1;
98setup:
99 if (callchain_register_param(&callchain_param) < 0) {
100 pr_err("Can't register callchain params\n");
101 return -1;
102 }
103 return 0;
104}
105
28static void 106static void
29rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 107rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
30 enum chain_mode mode) 108 enum chain_mode mode)
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 8ad97e9b119f..bde2b0cc24cf 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -7,6 +7,13 @@
7#include "event.h" 7#include "event.h"
8#include "symbol.h" 8#include "symbol.h"
9 9
10enum perf_call_graph_mode {
11 CALLCHAIN_NONE,
12 CALLCHAIN_FP,
13 CALLCHAIN_DWARF,
14 CALLCHAIN_MAX
15};
16
10enum chain_mode { 17enum chain_mode {
11 CHAIN_NONE, 18 CHAIN_NONE,
12 CHAIN_FLAT, 19 CHAIN_FLAT,
@@ -157,4 +164,5 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
157int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); 164int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample);
158 165
159extern const char record_callchain_help[]; 166extern const char record_callchain_help[];
167int parse_callchain_report_opt(const char *arg);
160#endif /* __PERF_CALLCHAIN_H */ 168#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 3e0fdd369ccb..24519e14ac56 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -11,6 +11,7 @@
11#include "util.h" 11#include "util.h"
12#include "cache.h" 12#include "cache.h"
13#include "exec_cmd.h" 13#include "exec_cmd.h"
14#include "util/hist.h" /* perf_hist_config */
14 15
15#define MAXNAME (256) 16#define MAXNAME (256)
16 17
@@ -355,6 +356,9 @@ int perf_default_config(const char *var, const char *value,
355 if (!prefixcmp(var, "core.")) 356 if (!prefixcmp(var, "core."))
356 return perf_default_core_config(var, value); 357 return perf_default_core_config(var, value);
357 358
359 if (!prefixcmp(var, "hist."))
360 return perf_hist_config(var, value);
361
358 /* Add other config variables here. */ 362 /* Add other config variables here. */
359 return 0; 363 return 0;
360} 364}
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 7fe4994eeb63..c4e55b71010c 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -317,3 +317,163 @@ int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep)
317{ 317{
318 return cpu_map__build_map(cpus, corep, cpu_map__get_core); 318 return cpu_map__build_map(cpus, corep, cpu_map__get_core);
319} 319}
320
321/* setup simple routines to easily access node numbers given a cpu number */
322static int get_max_num(char *path, int *max)
323{
324 size_t num;
325 char *buf;
326 int err = 0;
327
328 if (filename__read_str(path, &buf, &num))
329 return -1;
330
331 buf[num] = '\0';
332
333 /* start on the right, to find highest node num */
334 while (--num) {
335 if ((buf[num] == ',') || (buf[num] == '-')) {
336 num++;
337 break;
338 }
339 }
340 if (sscanf(&buf[num], "%d", max) < 1) {
341 err = -1;
342 goto out;
343 }
344
345 /* convert from 0-based to 1-based */
346 (*max)++;
347
348out:
349 free(buf);
350 return err;
351}
352
353/* Determine highest possible cpu in the system for sparse allocation */
354static void set_max_cpu_num(void)
355{
356 const char *mnt;
357 char path[PATH_MAX];
358 int ret = -1;
359
360 /* set up default */
361 max_cpu_num = 4096;
362
363 mnt = sysfs__mountpoint();
364 if (!mnt)
365 goto out;
366
367 /* get the highest possible cpu number for a sparse allocation */
368 ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/possible", mnt);
369 if (ret == PATH_MAX) {
370 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
371 goto out;
372 }
373
374 ret = get_max_num(path, &max_cpu_num);
375
376out:
377 if (ret)
378 pr_err("Failed to read max cpus, using default of %d\n", max_cpu_num);
379}
380
381/* Determine highest possible node in the system for sparse allocation */
382static void set_max_node_num(void)
383{
384 const char *mnt;
385 char path[PATH_MAX];
386 int ret = -1;
387
388 /* set up default */
389 max_node_num = 8;
390
391 mnt = sysfs__mountpoint();
392 if (!mnt)
393 goto out;
394
395 /* get the highest possible cpu number for a sparse allocation */
396 ret = snprintf(path, PATH_MAX, "%s/devices/system/node/possible", mnt);
397 if (ret == PATH_MAX) {
398 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
399 goto out;
400 }
401
402 ret = get_max_num(path, &max_node_num);
403
404out:
405 if (ret)
406 pr_err("Failed to read max nodes, using default of %d\n", max_node_num);
407}
408
409static int init_cpunode_map(void)
410{
411 int i;
412
413 set_max_cpu_num();
414 set_max_node_num();
415
416 cpunode_map = calloc(max_cpu_num, sizeof(int));
417 if (!cpunode_map) {
418 pr_err("%s: calloc failed\n", __func__);
419 return -1;
420 }
421
422 for (i = 0; i < max_cpu_num; i++)
423 cpunode_map[i] = -1;
424
425 return 0;
426}
427
428int cpu__setup_cpunode_map(void)
429{
430 struct dirent *dent1, *dent2;
431 DIR *dir1, *dir2;
432 unsigned int cpu, mem;
433 char buf[PATH_MAX];
434 char path[PATH_MAX];
435 const char *mnt;
436 int n;
437
438 /* initialize globals */
439 if (init_cpunode_map())
440 return -1;
441
442 mnt = sysfs__mountpoint();
443 if (!mnt)
444 return 0;
445
446 n = snprintf(path, PATH_MAX, "%s/devices/system/node", mnt);
447 if (n == PATH_MAX) {
448 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
449 return -1;
450 }
451
452 dir1 = opendir(path);
453 if (!dir1)
454 return 0;
455
456 /* walk tree and setup map */
457 while ((dent1 = readdir(dir1)) != NULL) {
458 if (dent1->d_type != DT_DIR || sscanf(dent1->d_name, "node%u", &mem) < 1)
459 continue;
460
461 n = snprintf(buf, PATH_MAX, "%s/%s", path, dent1->d_name);
462 if (n == PATH_MAX) {
463 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
464 continue;
465 }
466
467 dir2 = opendir(buf);
468 if (!dir2)
469 continue;
470 while ((dent2 = readdir(dir2)) != NULL) {
471 if (dent2->d_type != DT_LNK || sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
472 continue;
473 cpunode_map[cpu] = mem;
474 }
475 closedir(dir2);
476 }
477 closedir(dir1);
478 return 0;
479}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index b123bb9d6f55..61a654849002 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -4,6 +4,9 @@
4#include <stdio.h> 4#include <stdio.h>
5#include <stdbool.h> 5#include <stdbool.h>
6 6
7#include "perf.h"
8#include "util/debug.h"
9
7struct cpu_map { 10struct cpu_map {
8 int nr; 11 int nr;
9 int map[]; 12 int map[];
@@ -46,4 +49,36 @@ static inline bool cpu_map__empty(const struct cpu_map *map)
46 return map ? map->map[0] == -1 : true; 49 return map ? map->map[0] == -1 : true;
47} 50}
48 51
52int max_cpu_num;
53int max_node_num;
54int *cpunode_map;
55
56int cpu__setup_cpunode_map(void);
57
58static inline int cpu__max_node(void)
59{
60 if (unlikely(!max_node_num))
61 pr_debug("cpu_map not initialized\n");
62
63 return max_node_num;
64}
65
66static inline int cpu__max_cpu(void)
67{
68 if (unlikely(!max_cpu_num))
69 pr_debug("cpu_map not initialized\n");
70
71 return max_cpu_num;
72}
73
74static inline int cpu__get_node(int cpu)
75{
76 if (unlikely(cpunode_map == NULL)) {
77 pr_debug("cpu_map not initialized\n");
78 return -1;
79 }
80
81 return cpunode_map[cpu];
82}
83
49#endif /* __PERF_CPUMAP_H */ 84#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index ab06f1c03655..38efe95a7fdd 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -4,7 +4,7 @@
4#include <linux/types.h> 4#include <linux/types.h>
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include <linux/types.h>
8#include "map.h" 8#include "map.h"
9#include "build-id.h" 9#include "build-id.h"
10 10
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 9d12aa6dd485..65795b835b39 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -699,7 +699,7 @@ void thread__find_addr_map(struct thread *thread,
699 enum map_type type, u64 addr, 699 enum map_type type, u64 addr,
700 struct addr_location *al) 700 struct addr_location *al)
701{ 701{
702 struct map_groups *mg = &thread->mg; 702 struct map_groups *mg = thread->mg;
703 bool load_map = false; 703 bool load_map = false;
704 704
705 al->machine = machine; 705 al->machine = machine;
@@ -788,7 +788,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
788{ 788{
789 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 789 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
790 struct thread *thread = machine__findnew_thread(machine, sample->pid, 790 struct thread *thread = machine__findnew_thread(machine, sample->pid,
791 sample->pid); 791 sample->tid);
792 792
793 if (thread == NULL) 793 if (thread == NULL)
794 return -1; 794 return -1;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 38457d447a13..d970232cb270 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -112,6 +112,30 @@ struct sample_read {
112 }; 112 };
113}; 113};
114 114
115struct ip_callchain {
116 u64 nr;
117 u64 ips[0];
118};
119
120struct branch_flags {
121 u64 mispred:1;
122 u64 predicted:1;
123 u64 in_tx:1;
124 u64 abort:1;
125 u64 reserved:60;
126};
127
128struct branch_entry {
129 u64 from;
130 u64 to;
131 struct branch_flags flags;
132};
133
134struct branch_stack {
135 u64 nr;
136 struct branch_entry entries[0];
137};
138
115struct perf_sample { 139struct perf_sample {
116 u64 ip; 140 u64 ip;
117 u32 pid, tid; 141 u32 pid, tid;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 0c9926cfb292..a52e9a5bb2d0 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -5,12 +5,12 @@
5#include <stdbool.h> 5#include <stdbool.h>
6#include <stddef.h> 6#include <stddef.h>
7#include <linux/perf_event.h> 7#include <linux/perf_event.h>
8#include "types.h" 8#include <linux/types.h>
9#include "xyarray.h" 9#include "xyarray.h"
10#include "cgroup.h" 10#include "cgroup.h"
11#include "hist.h" 11#include "hist.h"
12#include "symbol.h" 12#include "symbol.h"
13 13
14struct perf_counts_values { 14struct perf_counts_values {
15 union { 15 union {
16 struct { 16 struct {
@@ -91,6 +91,11 @@ struct perf_evsel {
91 char *group_name; 91 char *group_name;
92}; 92};
93 93
94union u64_swap {
95 u64 val64;
96 u32 val32[2];
97};
98
94#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists) 99#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists)
95 100
96struct cpu_map; 101struct cpu_map;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index a2d047bdf4ef..d08cfe499404 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -4,10 +4,10 @@
4#include <linux/perf_event.h> 4#include <linux/perf_event.h>
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include <linux/bitmap.h>
8#include <linux/types.h>
8#include "event.h" 9#include "event.h"
9 10
10#include <linux/bitmap.h>
11 11
12enum { 12enum {
13 HEADER_RESERVED = 0, /* always cleared */ 13 HEADER_RESERVED = 0, /* always cleared */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index f38590d7561b..b262b44b7a65 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -225,14 +225,18 @@ static void he_stat__decay(struct he_stat *he_stat)
225static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 225static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
226{ 226{
227 u64 prev_period = he->stat.period; 227 u64 prev_period = he->stat.period;
228 u64 diff;
228 229
229 if (prev_period == 0) 230 if (prev_period == 0)
230 return true; 231 return true;
231 232
232 he_stat__decay(&he->stat); 233 he_stat__decay(&he->stat);
233 234
235 diff = prev_period - he->stat.period;
236
237 hists->stats.total_period -= diff;
234 if (!he->filtered) 238 if (!he->filtered)
235 hists->stats.total_period -= prev_period - he->stat.period; 239 hists->stats.total_non_filtered_period -= diff;
236 240
237 return he->stat.period == 0; 241 return he->stat.period == 0;
238} 242}
@@ -259,8 +263,11 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
259 if (sort__need_collapse) 263 if (sort__need_collapse)
260 rb_erase(&n->rb_node_in, &hists->entries_collapsed); 264 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
261 265
262 hist_entry__free(n);
263 --hists->nr_entries; 266 --hists->nr_entries;
267 if (!n->filtered)
268 --hists->nr_non_filtered_entries;
269
270 hist_entry__free(n);
264 } 271 }
265 } 272 }
266} 273}
@@ -317,15 +324,6 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
317 return he; 324 return he;
318} 325}
319 326
320void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
321{
322 if (!h->filtered) {
323 hists__calc_col_len(hists, h);
324 ++hists->nr_entries;
325 hists->stats.total_period += h->stat.period;
326 }
327}
328
329static u8 symbol__parent_filter(const struct symbol *parent) 327static u8 symbol__parent_filter(const struct symbol *parent)
330{ 328{
331 if (symbol_conf.exclude_other && parent == NULL) 329 if (symbol_conf.exclude_other && parent == NULL)
@@ -391,7 +389,6 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
391 if (!he) 389 if (!he)
392 return NULL; 390 return NULL;
393 391
394 hists->nr_entries++;
395 rb_link_node(&he->rb_node_in, parent, p); 392 rb_link_node(&he->rb_node_in, parent, p);
396 rb_insert_color(&he->rb_node_in, hists->entries_in); 393 rb_insert_color(&he->rb_node_in, hists->entries_in);
397out: 394out:
@@ -435,11 +432,14 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
435int64_t 432int64_t
436hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 433hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
437{ 434{
438 struct sort_entry *se; 435 struct perf_hpp_fmt *fmt;
439 int64_t cmp = 0; 436 int64_t cmp = 0;
440 437
441 list_for_each_entry(se, &hist_entry__sort_list, list) { 438 perf_hpp__for_each_sort_list(fmt) {
442 cmp = se->se_cmp(left, right); 439 if (perf_hpp__should_skip(fmt))
440 continue;
441
442 cmp = fmt->cmp(left, right);
443 if (cmp) 443 if (cmp)
444 break; 444 break;
445 } 445 }
@@ -450,15 +450,14 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
450int64_t 450int64_t
451hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) 451hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
452{ 452{
453 struct sort_entry *se; 453 struct perf_hpp_fmt *fmt;
454 int64_t cmp = 0; 454 int64_t cmp = 0;
455 455
456 list_for_each_entry(se, &hist_entry__sort_list, list) { 456 perf_hpp__for_each_sort_list(fmt) {
457 int64_t (*f)(struct hist_entry *, struct hist_entry *); 457 if (perf_hpp__should_skip(fmt))
458 458 continue;
459 f = se->se_collapse ?: se->se_cmp;
460 459
461 cmp = f(left, right); 460 cmp = fmt->collapse(left, right);
462 if (cmp) 461 if (cmp)
463 break; 462 break;
464 } 463 }
@@ -571,64 +570,50 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
571 } 570 }
572} 571}
573 572
574/* 573static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
575 * reverse the map, sort on period.
576 */
577
578static int period_cmp(u64 period_a, u64 period_b)
579{ 574{
580 if (period_a > period_b) 575 struct perf_hpp_fmt *fmt;
581 return 1; 576 int64_t cmp = 0;
582 if (period_a < period_b)
583 return -1;
584 return 0;
585}
586
587static int hist_entry__sort_on_period(struct hist_entry *a,
588 struct hist_entry *b)
589{
590 int ret;
591 int i, nr_members;
592 struct perf_evsel *evsel;
593 struct hist_entry *pair;
594 u64 *periods_a, *periods_b;
595 577
596 ret = period_cmp(a->stat.period, b->stat.period); 578 perf_hpp__for_each_sort_list(fmt) {
597 if (ret || !symbol_conf.event_group) 579 if (perf_hpp__should_skip(fmt))
598 return ret; 580 continue;
599 581
600 evsel = hists_to_evsel(a->hists); 582 cmp = fmt->sort(a, b);
601 nr_members = evsel->nr_members; 583 if (cmp)
602 if (nr_members <= 1) 584 break;
603 return ret; 585 }
604 586
605 periods_a = zalloc(sizeof(periods_a) * nr_members); 587 return cmp;
606 periods_b = zalloc(sizeof(periods_b) * nr_members); 588}
607 589
608 if (!periods_a || !periods_b) 590static void hists__reset_filter_stats(struct hists *hists)
609 goto out; 591{
592 hists->nr_non_filtered_entries = 0;
593 hists->stats.total_non_filtered_period = 0;
594}
610 595
611 list_for_each_entry(pair, &a->pairs.head, pairs.node) { 596void hists__reset_stats(struct hists *hists)
612 evsel = hists_to_evsel(pair->hists); 597{
613 periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period; 598 hists->nr_entries = 0;
614 } 599 hists->stats.total_period = 0;
615 600
616 list_for_each_entry(pair, &b->pairs.head, pairs.node) { 601 hists__reset_filter_stats(hists);
617 evsel = hists_to_evsel(pair->hists); 602}
618 periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period;
619 }
620 603
621 for (i = 1; i < nr_members; i++) { 604static void hists__inc_filter_stats(struct hists *hists, struct hist_entry *h)
622 ret = period_cmp(periods_a[i], periods_b[i]); 605{
623 if (ret) 606 hists->nr_non_filtered_entries++;
624 break; 607 hists->stats.total_non_filtered_period += h->stat.period;
625 } 608}
626 609
627out: 610void hists__inc_stats(struct hists *hists, struct hist_entry *h)
628 free(periods_a); 611{
629 free(periods_b); 612 if (!h->filtered)
613 hists__inc_filter_stats(hists, h);
630 614
631 return ret; 615 hists->nr_entries++;
616 hists->stats.total_period += h->stat.period;
632} 617}
633 618
634static void __hists__insert_output_entry(struct rb_root *entries, 619static void __hists__insert_output_entry(struct rb_root *entries,
@@ -647,7 +632,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
647 parent = *p; 632 parent = *p;
648 iter = rb_entry(parent, struct hist_entry, rb_node); 633 iter = rb_entry(parent, struct hist_entry, rb_node);
649 634
650 if (hist_entry__sort_on_period(he, iter) > 0) 635 if (hist_entry__sort(he, iter) > 0)
651 p = &(*p)->rb_left; 636 p = &(*p)->rb_left;
652 else 637 else
653 p = &(*p)->rb_right; 638 p = &(*p)->rb_right;
@@ -674,8 +659,7 @@ void hists__output_resort(struct hists *hists)
674 next = rb_first(root); 659 next = rb_first(root);
675 hists->entries = RB_ROOT; 660 hists->entries = RB_ROOT;
676 661
677 hists->nr_entries = 0; 662 hists__reset_stats(hists);
678 hists->stats.total_period = 0;
679 hists__reset_col_len(hists); 663 hists__reset_col_len(hists);
680 664
681 while (next) { 665 while (next) {
@@ -683,7 +667,10 @@ void hists__output_resort(struct hists *hists)
683 next = rb_next(&n->rb_node_in); 667 next = rb_next(&n->rb_node_in);
684 668
685 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits); 669 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
686 hists__inc_nr_entries(hists, n); 670 hists__inc_stats(hists, n);
671
672 if (!n->filtered)
673 hists__calc_col_len(hists, n);
687 } 674 }
688} 675}
689 676
@@ -694,13 +681,13 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
694 if (h->filtered) 681 if (h->filtered)
695 return; 682 return;
696 683
697 ++hists->nr_entries; 684 /* force fold unfiltered entry for simplicity */
698 if (h->ms.unfolded) 685 h->ms.unfolded = false;
699 hists->nr_entries += h->nr_rows;
700 h->row_offset = 0; 686 h->row_offset = 0;
701 hists->stats.total_period += h->stat.period;
702 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events;
703 687
688 hists->stats.nr_non_filtered_samples += h->stat.nr_events;
689
690 hists__inc_filter_stats(hists, h);
704 hists__calc_col_len(hists, h); 691 hists__calc_col_len(hists, h);
705} 692}
706 693
@@ -721,8 +708,9 @@ void hists__filter_by_dso(struct hists *hists)
721{ 708{
722 struct rb_node *nd; 709 struct rb_node *nd;
723 710
724 hists->nr_entries = hists->stats.total_period = 0; 711 hists->stats.nr_non_filtered_samples = 0;
725 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 712
713 hists__reset_filter_stats(hists);
726 hists__reset_col_len(hists); 714 hists__reset_col_len(hists);
727 715
728 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 716 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -754,8 +742,9 @@ void hists__filter_by_thread(struct hists *hists)
754{ 742{
755 struct rb_node *nd; 743 struct rb_node *nd;
756 744
757 hists->nr_entries = hists->stats.total_period = 0; 745 hists->stats.nr_non_filtered_samples = 0;
758 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 746
747 hists__reset_filter_stats(hists);
759 hists__reset_col_len(hists); 748 hists__reset_col_len(hists);
760 749
761 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 750 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -785,8 +774,9 @@ void hists__filter_by_symbol(struct hists *hists)
785{ 774{
786 struct rb_node *nd; 775 struct rb_node *nd;
787 776
788 hists->nr_entries = hists->stats.total_period = 0; 777 hists->stats.nr_non_filtered_samples = 0;
789 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 778
779 hists__reset_filter_stats(hists);
790 hists__reset_col_len(hists); 780 hists__reset_col_len(hists);
791 781
792 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 782 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -847,7 +837,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
847 he->hists = hists; 837 he->hists = hists;
848 rb_link_node(&he->rb_node_in, parent, p); 838 rb_link_node(&he->rb_node_in, parent, p);
849 rb_insert_color(&he->rb_node_in, root); 839 rb_insert_color(&he->rb_node_in, root);
850 hists__inc_nr_entries(hists, he); 840 hists__inc_stats(hists, he);
851 he->dummy = true; 841 he->dummy = true;
852 } 842 }
853out: 843out:
@@ -931,3 +921,30 @@ int hists__link(struct hists *leader, struct hists *other)
931 921
932 return 0; 922 return 0;
933} 923}
924
925u64 hists__total_period(struct hists *hists)
926{
927 return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period :
928 hists->stats.total_period;
929}
930
931int parse_filter_percentage(const struct option *opt __maybe_unused,
932 const char *arg, int unset __maybe_unused)
933{
934 if (!strcmp(arg, "relative"))
935 symbol_conf.filter_relative = true;
936 else if (!strcmp(arg, "absolute"))
937 symbol_conf.filter_relative = false;
938 else
939 return -1;
940
941 return 0;
942}
943
944int perf_hist_config(const char *var, const char *value)
945{
946 if (!strcmp(var, "hist.percentage"))
947 return parse_filter_percentage(NULL, value, 0);
948
949 return 0;
950}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 1f1f513dfe7f..a8418d19808d 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -37,9 +37,11 @@ enum hist_filter {
37 */ 37 */
38struct events_stats { 38struct events_stats {
39 u64 total_period; 39 u64 total_period;
40 u64 total_non_filtered_period;
40 u64 total_lost; 41 u64 total_lost;
41 u64 total_invalid_chains; 42 u64 total_invalid_chains;
42 u32 nr_events[PERF_RECORD_HEADER_MAX]; 43 u32 nr_events[PERF_RECORD_HEADER_MAX];
44 u32 nr_non_filtered_samples;
43 u32 nr_lost_warned; 45 u32 nr_lost_warned;
44 u32 nr_unknown_events; 46 u32 nr_unknown_events;
45 u32 nr_invalid_chains; 47 u32 nr_invalid_chains;
@@ -83,6 +85,7 @@ struct hists {
83 struct rb_root entries; 85 struct rb_root entries;
84 struct rb_root entries_collapsed; 86 struct rb_root entries_collapsed;
85 u64 nr_entries; 87 u64 nr_entries;
88 u64 nr_non_filtered_entries;
86 const struct thread *thread_filter; 89 const struct thread *thread_filter;
87 const struct dso *dso_filter; 90 const struct dso *dso_filter;
88 const char *uid_filter_str; 91 const char *uid_filter_str;
@@ -112,7 +115,9 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
112void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); 115void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
113void hists__output_recalc_col_len(struct hists *hists, int max_rows); 116void hists__output_recalc_col_len(struct hists *hists, int max_rows);
114 117
115void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); 118u64 hists__total_period(struct hists *hists);
119void hists__reset_stats(struct hists *hists);
120void hists__inc_stats(struct hists *hists, struct hist_entry *h);
116void hists__inc_nr_events(struct hists *hists, u32 type); 121void hists__inc_nr_events(struct hists *hists, u32 type);
117void events_stats__inc(struct events_stats *stats, u32 type); 122void events_stats__inc(struct events_stats *stats, u32 type);
118size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); 123size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
@@ -124,6 +129,12 @@ void hists__filter_by_dso(struct hists *hists);
124void hists__filter_by_thread(struct hists *hists); 129void hists__filter_by_thread(struct hists *hists);
125void hists__filter_by_symbol(struct hists *hists); 130void hists__filter_by_symbol(struct hists *hists);
126 131
132static inline bool hists__has_filter(struct hists *hists)
133{
134 return hists->thread_filter || hists->dso_filter ||
135 hists->symbol_filter_str;
136}
137
127u16 hists__col_len(struct hists *hists, enum hist_column col); 138u16 hists__col_len(struct hists *hists, enum hist_column col);
128void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len); 139void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len);
129bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len); 140bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len);
@@ -149,15 +160,29 @@ struct perf_hpp_fmt {
149 struct hist_entry *he); 160 struct hist_entry *he);
150 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 161 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
151 struct hist_entry *he); 162 struct hist_entry *he);
163 int64_t (*cmp)(struct hist_entry *a, struct hist_entry *b);
164 int64_t (*collapse)(struct hist_entry *a, struct hist_entry *b);
165 int64_t (*sort)(struct hist_entry *a, struct hist_entry *b);
152 166
153 struct list_head list; 167 struct list_head list;
168 struct list_head sort_list;
154}; 169};
155 170
156extern struct list_head perf_hpp__list; 171extern struct list_head perf_hpp__list;
172extern struct list_head perf_hpp__sort_list;
157 173
158#define perf_hpp__for_each_format(format) \ 174#define perf_hpp__for_each_format(format) \
159 list_for_each_entry(format, &perf_hpp__list, list) 175 list_for_each_entry(format, &perf_hpp__list, list)
160 176
177#define perf_hpp__for_each_format_safe(format, tmp) \
178 list_for_each_entry_safe(format, tmp, &perf_hpp__list, list)
179
180#define perf_hpp__for_each_sort_list(format) \
181 list_for_each_entry(format, &perf_hpp__sort_list, sort_list)
182
183#define perf_hpp__for_each_sort_list_safe(format, tmp) \
184 list_for_each_entry_safe(format, tmp, &perf_hpp__sort_list, sort_list)
185
161extern struct perf_hpp_fmt perf_hpp__format[]; 186extern struct perf_hpp_fmt perf_hpp__format[];
162 187
163enum { 188enum {
@@ -176,14 +201,23 @@ enum {
176void perf_hpp__init(void); 201void perf_hpp__init(void);
177void perf_hpp__column_register(struct perf_hpp_fmt *format); 202void perf_hpp__column_register(struct perf_hpp_fmt *format);
178void perf_hpp__column_enable(unsigned col); 203void perf_hpp__column_enable(unsigned col);
204void perf_hpp__register_sort_field(struct perf_hpp_fmt *format);
205void perf_hpp__setup_output_field(void);
206void perf_hpp__reset_output_field(void);
207void perf_hpp__append_sort_keys(void);
208
209bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
210bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
211bool perf_hpp__should_skip(struct perf_hpp_fmt *format);
212void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
179 213
180typedef u64 (*hpp_field_fn)(struct hist_entry *he); 214typedef u64 (*hpp_field_fn)(struct hist_entry *he);
181typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); 215typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
182typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...); 216typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
183 217
184int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 218int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
185 hpp_field_fn get_field, hpp_callback_fn callback, 219 hpp_field_fn get_field, const char *fmt,
186 const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent); 220 hpp_snprint_fn print_fn, bool fmt_percent);
187 221
188static inline void advance_hpp(struct perf_hpp *hpp, int inc) 222static inline void advance_hpp(struct perf_hpp *hpp, int inc)
189{ 223{
@@ -250,4 +284,10 @@ static inline int script_browse(const char *script_opt __maybe_unused)
250#endif 284#endif
251 285
252unsigned int hists__sort_list_width(struct hists *hists); 286unsigned int hists__sort_list_width(struct hists *hists);
287
288struct option;
289int parse_filter_percentage(const struct option *opt __maybe_unused,
290 const char *arg, int unset __maybe_unused);
291int perf_hist_config(const char *var, const char *value);
292
253#endif /* __PERF_HIST_H */ 293#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index bb162e40c76c..01ffd12dc791 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -4,6 +4,9 @@
4#include <string.h> 4#include <string.h>
5#include <linux/bitops.h> 5#include <linux/bitops.h>
6 6
7#define DECLARE_BITMAP(name,bits) \
8 unsigned long name[BITS_TO_LONGS(bits)]
9
7int __bitmap_weight(const unsigned long *bitmap, int bits); 10int __bitmap_weight(const unsigned long *bitmap, int bits);
8void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, 11void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
9 const unsigned long *bitmap2, int bits); 12 const unsigned long *bitmap2, int bits);
diff --git a/tools/perf/util/include/linux/export.h b/tools/perf/util/include/linux/export.h
deleted file mode 100644
index b43e2dc21e04..000000000000
--- a/tools/perf/util/include/linux/export.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef PERF_LINUX_MODULE_H
2#define PERF_LINUX_MODULE_H
3
4#define EXPORT_SYMBOL(name)
5
6#endif
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
index bfe0a2afd0d2..76ddbc726343 100644
--- a/tools/perf/util/include/linux/list.h
+++ b/tools/perf/util/include/linux/list.h
@@ -1,4 +1,5 @@
1#include <linux/kernel.h> 1#include <linux/kernel.h>
2#include <linux/types.h>
2 3
3#include "../../../../include/linux/list.h" 4#include "../../../../include/linux/list.h"
4 5
diff --git a/tools/perf/util/include/linux/types.h b/tools/perf/util/include/linux/types.h
deleted file mode 100644
index eb464786c084..000000000000
--- a/tools/perf/util/include/linux/types.h
+++ /dev/null
@@ -1,29 +0,0 @@
1#ifndef _PERF_LINUX_TYPES_H_
2#define _PERF_LINUX_TYPES_H_
3
4#include <asm/types.h>
5
6#ifndef __bitwise
7#define __bitwise
8#endif
9
10#ifndef __le32
11typedef __u32 __bitwise __le32;
12#endif
13
14#define DECLARE_BITMAP(name,bits) \
15 unsigned long name[BITS_TO_LONGS(bits)]
16
17struct list_head {
18 struct list_head *next, *prev;
19};
20
21struct hlist_head {
22 struct hlist_node *first;
23};
24
25struct hlist_node {
26 struct hlist_node *next, **pprev;
27};
28
29#endif
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 27c2a5efe450..7409ac8de51c 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -316,6 +316,17 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
316 rb_link_node(&th->rb_node, parent, p); 316 rb_link_node(&th->rb_node, parent, p);
317 rb_insert_color(&th->rb_node, &machine->threads); 317 rb_insert_color(&th->rb_node, &machine->threads);
318 machine->last_match = th; 318 machine->last_match = th;
319
320 /*
321 * We have to initialize map_groups separately
322 * after rb tree is updated.
323 *
324 * The reason is that we call machine__findnew_thread
325 * within thread__init_map_groups to find the thread
326 * leader and that would screwed the rb tree.
327 */
328 if (thread__init_map_groups(th, machine))
329 return NULL;
319 } 330 }
320 331
321 return th; 332 return th;
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 39cd2d0faff6..8ccbb32eda25 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -32,6 +32,93 @@ static inline int is_no_dso_memory(const char *filename)
32 !strcmp(filename, "[heap]"); 32 !strcmp(filename, "[heap]");
33} 33}
34 34
35static inline int is_android_lib(const char *filename)
36{
37 return !strncmp(filename, "/data/app-lib", 13) ||
38 !strncmp(filename, "/system/lib", 11);
39}
40
41static inline bool replace_android_lib(const char *filename, char *newfilename)
42{
43 const char *libname;
44 char *app_abi;
45 size_t app_abi_length, new_length;
46 size_t lib_length = 0;
47
48 libname = strrchr(filename, '/');
49 if (libname)
50 lib_length = strlen(libname);
51
52 app_abi = getenv("APP_ABI");
53 if (!app_abi)
54 return false;
55
56 app_abi_length = strlen(app_abi);
57
58 if (!strncmp(filename, "/data/app-lib", 13)) {
59 char *apk_path;
60
61 if (!app_abi_length)
62 return false;
63
64 new_length = 7 + app_abi_length + lib_length;
65
66 apk_path = getenv("APK_PATH");
67 if (apk_path) {
68 new_length += strlen(apk_path) + 1;
69 if (new_length > PATH_MAX)
70 return false;
71 snprintf(newfilename, new_length,
72 "%s/libs/%s/%s", apk_path, app_abi, libname);
73 } else {
74 if (new_length > PATH_MAX)
75 return false;
76 snprintf(newfilename, new_length,
77 "libs/%s/%s", app_abi, libname);
78 }
79 return true;
80 }
81
82 if (!strncmp(filename, "/system/lib/", 11)) {
83 char *ndk, *app;
84 const char *arch;
85 size_t ndk_length;
86 size_t app_length;
87
88 ndk = getenv("NDK_ROOT");
89 app = getenv("APP_PLATFORM");
90
91 if (!(ndk && app))
92 return false;
93
94 ndk_length = strlen(ndk);
95 app_length = strlen(app);
96
97 if (!(ndk_length && app_length && app_abi_length))
98 return false;
99
100 arch = !strncmp(app_abi, "arm", 3) ? "arm" :
101 !strncmp(app_abi, "mips", 4) ? "mips" :
102 !strncmp(app_abi, "x86", 3) ? "x86" : NULL;
103
104 if (!arch)
105 return false;
106
107 new_length = 27 + ndk_length +
108 app_length + lib_length
109 + strlen(arch);
110
111 if (new_length > PATH_MAX)
112 return false;
113 snprintf(newfilename, new_length,
114 "%s/platforms/%s/arch-%s/usr/lib/%s",
115 ndk, app, arch, libname);
116
117 return true;
118 }
119 return false;
120}
121
35void map__init(struct map *map, enum map_type type, 122void map__init(struct map *map, enum map_type type,
36 u64 start, u64 end, u64 pgoff, struct dso *dso) 123 u64 start, u64 end, u64 pgoff, struct dso *dso)
37{ 124{
@@ -59,8 +146,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
59 if (map != NULL) { 146 if (map != NULL) {
60 char newfilename[PATH_MAX]; 147 char newfilename[PATH_MAX];
61 struct dso *dso; 148 struct dso *dso;
62 int anon, no_dso, vdso; 149 int anon, no_dso, vdso, android;
63 150
151 android = is_android_lib(filename);
64 anon = is_anon_memory(filename); 152 anon = is_anon_memory(filename);
65 vdso = is_vdso_map(filename); 153 vdso = is_vdso_map(filename);
66 no_dso = is_no_dso_memory(filename); 154 no_dso = is_no_dso_memory(filename);
@@ -75,6 +163,11 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
75 filename = newfilename; 163 filename = newfilename;
76 } 164 }
77 165
166 if (android) {
167 if (replace_android_lib(filename, newfilename))
168 filename = newfilename;
169 }
170
78 if (vdso) { 171 if (vdso) {
79 pgoff = 0; 172 pgoff = 0;
80 dso = vdso__dso_findnew(dsos__list); 173 dso = vdso__dso_findnew(dsos__list);
@@ -323,6 +416,7 @@ void map_groups__init(struct map_groups *mg)
323 INIT_LIST_HEAD(&mg->removed_maps[i]); 416 INIT_LIST_HEAD(&mg->removed_maps[i]);
324 } 417 }
325 mg->machine = NULL; 418 mg->machine = NULL;
419 mg->refcnt = 1;
326} 420}
327 421
328static void maps__delete(struct rb_root *maps) 422static void maps__delete(struct rb_root *maps)
@@ -358,6 +452,28 @@ void map_groups__exit(struct map_groups *mg)
358 } 452 }
359} 453}
360 454
455struct map_groups *map_groups__new(void)
456{
457 struct map_groups *mg = malloc(sizeof(*mg));
458
459 if (mg != NULL)
460 map_groups__init(mg);
461
462 return mg;
463}
464
465void map_groups__delete(struct map_groups *mg)
466{
467 map_groups__exit(mg);
468 free(mg);
469}
470
471void map_groups__put(struct map_groups *mg)
472{
473 if (--mg->refcnt == 0)
474 map_groups__delete(mg);
475}
476
361void map_groups__flush(struct map_groups *mg) 477void map_groups__flush(struct map_groups *mg)
362{ 478{
363 int type; 479 int type;
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index f00f058afb3b..ae2d45110588 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -6,7 +6,7 @@
6#include <linux/rbtree.h> 6#include <linux/rbtree.h>
7#include <stdio.h> 7#include <stdio.h>
8#include <stdbool.h> 8#include <stdbool.h>
9#include "types.h" 9#include <linux/types.h>
10 10
11enum map_type { 11enum map_type {
12 MAP__FUNCTION = 0, 12 MAP__FUNCTION = 0,
@@ -59,8 +59,20 @@ struct map_groups {
59 struct rb_root maps[MAP__NR_TYPES]; 59 struct rb_root maps[MAP__NR_TYPES];
60 struct list_head removed_maps[MAP__NR_TYPES]; 60 struct list_head removed_maps[MAP__NR_TYPES];
61 struct machine *machine; 61 struct machine *machine;
62 int refcnt;
62}; 63};
63 64
65struct map_groups *map_groups__new(void);
66void map_groups__delete(struct map_groups *mg);
67
68static inline struct map_groups *map_groups__get(struct map_groups *mg)
69{
70 ++mg->refcnt;
71 return mg;
72}
73
74void map_groups__put(struct map_groups *mg);
75
64static inline struct kmap *map__kmap(struct map *map) 76static inline struct kmap *map__kmap(struct map *map)
65{ 77{
66 return (struct kmap *)(map + 1); 78 return (struct kmap *)(map + 1);
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
index 3322b8446e89..31ee02d4e988 100644
--- a/tools/perf/util/pager.c
+++ b/tools/perf/util/pager.c
@@ -57,13 +57,13 @@ void setup_pager(void)
57 } 57 }
58 if (!pager) 58 if (!pager)
59 pager = getenv("PAGER"); 59 pager = getenv("PAGER");
60 if (!pager) { 60 if (!(pager || access("/usr/bin/pager", X_OK)))
61 if (!access("/usr/bin/pager", X_OK)) 61 pager = "/usr/bin/pager";
62 pager = "/usr/bin/pager"; 62 if (!(pager || access("/usr/bin/less", X_OK)))
63 } 63 pager = "/usr/bin/less";
64 if (!pager) 64 if (!pager)
65 pager = "less"; 65 pager = "cat";
66 else if (!*pager || !strcmp(pager, "cat")) 66 if (!*pager || !strcmp(pager, "cat"))
67 return; 67 return;
68 68
69 spawned_pager = 1; /* means we are emitting to terminal */ 69 spawned_pager = 1; /* means we are emitting to terminal */
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index f1cb4c4b3c70..df094b4ed5ed 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -6,9 +6,8 @@
6 6
7#include <linux/list.h> 7#include <linux/list.h>
8#include <stdbool.h> 8#include <stdbool.h>
9#include "types.h" 9#include <linux/types.h>
10#include <linux/perf_event.h> 10#include <linux/perf_event.h>
11#include "types.h"
12 11
13struct list_head; 12struct list_head;
14struct perf_evsel; 13struct perf_evsel;
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 4eb67ec333f1..0bc87ba46bf3 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -9,7 +9,7 @@
9 9
10#include <linux/compiler.h> 10#include <linux/compiler.h>
11#include <linux/list.h> 11#include <linux/list.h>
12#include "types.h" 12#include <linux/types.h>
13#include "util.h" 13#include "util.h"
14#include "parse-events.h" 14#include "parse-events.h"
15#include "parse-events-bison.h" 15#include "parse-events-bison.h"
@@ -299,6 +299,18 @@ PE_PREFIX_MEM PE_VALUE sep_dc
299} 299}
300 300
301event_legacy_tracepoint: 301event_legacy_tracepoint:
302PE_NAME '-' PE_NAME ':' PE_NAME
303{
304 struct parse_events_evlist *data = _data;
305 struct list_head *list;
306 char sys_name[128];
307 snprintf(&sys_name, 128, "%s-%s", $1, $3);
308
309 ALLOC_LIST(list);
310 ABORT_ON(parse_events_add_tracepoint(list, &data->idx, &sys_name, $5));
311 $$ = list;
312}
313|
302PE_NAME ':' PE_NAME 314PE_NAME ':' PE_NAME
303{ 315{
304 struct parse_events_evlist *data = _data; 316 struct parse_events_evlist *data = _data;
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index d6e8b6a8d7f3..79c78f74e0cf 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_REGS_H 1#ifndef __PERF_REGS_H
2#define __PERF_REGS_H 2#define __PERF_REGS_H
3 3
4#include "types.h" 4#include <linux/types.h>
5#include "event.h" 5#include "event.h"
6 6
7#ifdef HAVE_PERF_REGS_SUPPORT 7#ifdef HAVE_PERF_REGS_SUPPORT
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 00a7dcb2f55c..7a811eb61f75 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -284,17 +284,17 @@ static int pmu_aliases(const char *name, struct list_head *head)
284static int pmu_alias_terms(struct perf_pmu_alias *alias, 284static int pmu_alias_terms(struct perf_pmu_alias *alias,
285 struct list_head *terms) 285 struct list_head *terms)
286{ 286{
287 struct parse_events_term *term, *clone; 287 struct parse_events_term *term, *cloned;
288 LIST_HEAD(list); 288 LIST_HEAD(list);
289 int ret; 289 int ret;
290 290
291 list_for_each_entry(term, &alias->terms, list) { 291 list_for_each_entry(term, &alias->terms, list) {
292 ret = parse_events_term__clone(&clone, term); 292 ret = parse_events_term__clone(&cloned, term);
293 if (ret) { 293 if (ret) {
294 parse_events__free_terms(&list); 294 parse_events__free_terms(&list);
295 return ret; 295 return ret;
296 } 296 }
297 list_add_tail(&clone->list, &list); 297 list_add_tail(&cloned->list, &list);
298 } 298 }
299 list_splice(&list, terms); 299 list_splice(&list, terms);
300 return 0; 300 return 0;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 8b64125a9281..c14a543ce1f3 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -1,7 +1,7 @@
1#ifndef __PMU_H 1#ifndef __PMU_H
2#define __PMU_H 2#define __PMU_H
3 3
4#include <linux/bitops.h> 4#include <linux/bitmap.h>
5#include <linux/perf_event.h> 5#include <linux/perf_event.h>
6#include <stdbool.h> 6#include <stdbool.h>
7 7
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 55960f22233c..64a186edc7be 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1625,13 +1625,14 @@ out_delete_map:
1625void perf_session__fprintf_info(struct perf_session *session, FILE *fp, 1625void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
1626 bool full) 1626 bool full)
1627{ 1627{
1628 int fd = perf_data_file__fd(session->file);
1629 struct stat st; 1628 struct stat st;
1630 int ret; 1629 int fd, ret;
1631 1630
1632 if (session == NULL || fp == NULL) 1631 if (session == NULL || fp == NULL)
1633 return; 1632 return;
1634 1633
1634 fd = perf_data_file__fd(session->file);
1635
1635 ret = fstat(fd, &st); 1636 ret = fstat(fd, &st);
1636 if (ret == -1) 1637 if (ret == -1)
1637 return; 1638 return;
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 635cd8f8b22e..901b9bece2ee 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -2,12 +2,18 @@
2#include "hist.h" 2#include "hist.h"
3#include "comm.h" 3#include "comm.h"
4#include "symbol.h" 4#include "symbol.h"
5#include "evsel.h"
5 6
6regex_t parent_regex; 7regex_t parent_regex;
7const char default_parent_pattern[] = "^sys_|^do_page_fault"; 8const char default_parent_pattern[] = "^sys_|^do_page_fault";
8const char *parent_pattern = default_parent_pattern; 9const char *parent_pattern = default_parent_pattern;
9const char default_sort_order[] = "comm,dso,symbol"; 10const char default_sort_order[] = "comm,dso,symbol";
10const char *sort_order = default_sort_order; 11const char default_branch_sort_order[] = "comm,dso_from,symbol_from,dso_to,symbol_to";
12const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
13const char default_top_sort_order[] = "dso,symbol";
14const char default_diff_sort_order[] = "dso,symbol";
15const char *sort_order;
16const char *field_order;
11regex_t ignore_callees_regex; 17regex_t ignore_callees_regex;
12int have_ignore_callees = 0; 18int have_ignore_callees = 0;
13int sort__need_collapse = 0; 19int sort__need_collapse = 0;
@@ -16,9 +22,6 @@ int sort__has_sym = 0;
16int sort__has_dso = 0; 22int sort__has_dso = 0;
17enum sort_mode sort__mode = SORT_MODE__NORMAL; 23enum sort_mode sort__mode = SORT_MODE__NORMAL;
18 24
19enum sort_type sort__first_dimension;
20
21LIST_HEAD(hist_entry__sort_list);
22 25
23static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 26static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
24{ 27{
@@ -93,6 +96,12 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
93 return comm__str(right->comm) - comm__str(left->comm); 96 return comm__str(right->comm) - comm__str(left->comm);
94} 97}
95 98
99static int64_t
100sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
101{
102 return strcmp(comm__str(right->comm), comm__str(left->comm));
103}
104
96static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, 105static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
97 size_t size, unsigned int width) 106 size_t size, unsigned int width)
98{ 107{
@@ -103,6 +112,7 @@ struct sort_entry sort_comm = {
103 .se_header = "Command", 112 .se_header = "Command",
104 .se_cmp = sort__comm_cmp, 113 .se_cmp = sort__comm_cmp,
105 .se_collapse = sort__comm_collapse, 114 .se_collapse = sort__comm_collapse,
115 .se_sort = sort__comm_sort,
106 .se_snprintf = hist_entry__comm_snprintf, 116 .se_snprintf = hist_entry__comm_snprintf,
107 .se_width_idx = HISTC_COMM, 117 .se_width_idx = HISTC_COMM,
108}; 118};
@@ -116,7 +126,7 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
116 const char *dso_name_l, *dso_name_r; 126 const char *dso_name_l, *dso_name_r;
117 127
118 if (!dso_l || !dso_r) 128 if (!dso_l || !dso_r)
119 return cmp_null(dso_l, dso_r); 129 return cmp_null(dso_r, dso_l);
120 130
121 if (verbose) { 131 if (verbose) {
122 dso_name_l = dso_l->long_name; 132 dso_name_l = dso_l->long_name;
@@ -132,7 +142,7 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
132static int64_t 142static int64_t
133sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 143sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
134{ 144{
135 return _sort__dso_cmp(left->ms.map, right->ms.map); 145 return _sort__dso_cmp(right->ms.map, left->ms.map);
136} 146}
137 147
138static int _hist_entry__dso_snprintf(struct map *map, char *bf, 148static int _hist_entry__dso_snprintf(struct map *map, char *bf,
@@ -204,6 +214,15 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
204 return _sort__sym_cmp(left->ms.sym, right->ms.sym); 214 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
205} 215}
206 216
217static int64_t
218sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
219{
220 if (!left->ms.sym || !right->ms.sym)
221 return cmp_null(left->ms.sym, right->ms.sym);
222
223 return strcmp(right->ms.sym->name, left->ms.sym->name);
224}
225
207static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, 226static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
208 u64 ip, char level, char *bf, size_t size, 227 u64 ip, char level, char *bf, size_t size,
209 unsigned int width) 228 unsigned int width)
@@ -250,6 +269,7 @@ static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
250struct sort_entry sort_sym = { 269struct sort_entry sort_sym = {
251 .se_header = "Symbol", 270 .se_header = "Symbol",
252 .se_cmp = sort__sym_cmp, 271 .se_cmp = sort__sym_cmp,
272 .se_sort = sort__sym_sort,
253 .se_snprintf = hist_entry__sym_snprintf, 273 .se_snprintf = hist_entry__sym_snprintf,
254 .se_width_idx = HISTC_SYMBOL, 274 .se_width_idx = HISTC_SYMBOL,
255}; 275};
@@ -277,7 +297,7 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
277 map__rip_2objdump(map, right->ip)); 297 map__rip_2objdump(map, right->ip));
278 } 298 }
279 } 299 }
280 return strcmp(left->srcline, right->srcline); 300 return strcmp(right->srcline, left->srcline);
281} 301}
282 302
283static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, 303static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
@@ -305,7 +325,7 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
305 if (!sym_l || !sym_r) 325 if (!sym_l || !sym_r)
306 return cmp_null(sym_l, sym_r); 326 return cmp_null(sym_l, sym_r);
307 327
308 return strcmp(sym_l->name, sym_r->name); 328 return strcmp(sym_r->name, sym_l->name);
309} 329}
310 330
311static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf, 331static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
@@ -1027,19 +1047,192 @@ static struct sort_dimension memory_sort_dimensions[] = {
1027 1047
1028#undef DIM 1048#undef DIM
1029 1049
1030static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx) 1050struct hpp_dimension {
1051 const char *name;
1052 struct perf_hpp_fmt *fmt;
1053 int taken;
1054};
1055
1056#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1057
1058static struct hpp_dimension hpp_sort_dimensions[] = {
1059 DIM(PERF_HPP__OVERHEAD, "overhead"),
1060 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1061 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1062 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1063 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1064 DIM(PERF_HPP__SAMPLES, "sample"),
1065 DIM(PERF_HPP__PERIOD, "period"),
1066};
1067
1068#undef DIM
1069
1070struct hpp_sort_entry {
1071 struct perf_hpp_fmt hpp;
1072 struct sort_entry *se;
1073};
1074
1075bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1031{ 1076{
1032 if (sd->taken) 1077 struct hpp_sort_entry *hse_a;
1078 struct hpp_sort_entry *hse_b;
1079
1080 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1081 return false;
1082
1083 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1084 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1085
1086 return hse_a->se == hse_b->se;
1087}
1088
1089void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1090{
1091 struct hpp_sort_entry *hse;
1092
1093 if (!perf_hpp__is_sort_entry(fmt))
1033 return; 1094 return;
1034 1095
1096 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1097 hists__new_col_len(hists, hse->se->se_width_idx,
1098 strlen(hse->se->se_header));
1099}
1100
1101static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1102 struct perf_evsel *evsel)
1103{
1104 struct hpp_sort_entry *hse;
1105 size_t len;
1106
1107 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1108 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1109
1110 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
1111}
1112
1113static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1114 struct perf_hpp *hpp __maybe_unused,
1115 struct perf_evsel *evsel)
1116{
1117 struct hpp_sort_entry *hse;
1118
1119 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1120
1121 return hists__col_len(&evsel->hists, hse->se->se_width_idx);
1122}
1123
1124static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1125 struct hist_entry *he)
1126{
1127 struct hpp_sort_entry *hse;
1128 size_t len;
1129
1130 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1131 len = hists__col_len(he->hists, hse->se->se_width_idx);
1132
1133 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1134}
1135
1136static struct hpp_sort_entry *
1137__sort_dimension__alloc_hpp(struct sort_dimension *sd)
1138{
1139 struct hpp_sort_entry *hse;
1140
1141 hse = malloc(sizeof(*hse));
1142 if (hse == NULL) {
1143 pr_err("Memory allocation failed\n");
1144 return NULL;
1145 }
1146
1147 hse->se = sd->entry;
1148 hse->hpp.header = __sort__hpp_header;
1149 hse->hpp.width = __sort__hpp_width;
1150 hse->hpp.entry = __sort__hpp_entry;
1151 hse->hpp.color = NULL;
1152
1153 hse->hpp.cmp = sd->entry->se_cmp;
1154 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
1155 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
1156
1157 INIT_LIST_HEAD(&hse->hpp.list);
1158 INIT_LIST_HEAD(&hse->hpp.sort_list);
1159
1160 return hse;
1161}
1162
1163bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1164{
1165 return format->header == __sort__hpp_header;
1166}
1167
1168static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1169{
1170 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1171
1172 if (hse == NULL)
1173 return -1;
1174
1175 perf_hpp__register_sort_field(&hse->hpp);
1176 return 0;
1177}
1178
1179static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1180{
1181 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1182
1183 if (hse == NULL)
1184 return -1;
1185
1186 perf_hpp__column_register(&hse->hpp);
1187 return 0;
1188}
1189
1190static int __sort_dimension__add(struct sort_dimension *sd)
1191{
1192 if (sd->taken)
1193 return 0;
1194
1195 if (__sort_dimension__add_hpp_sort(sd) < 0)
1196 return -1;
1197
1035 if (sd->entry->se_collapse) 1198 if (sd->entry->se_collapse)
1036 sort__need_collapse = 1; 1199 sort__need_collapse = 1;
1037 1200
1038 if (list_empty(&hist_entry__sort_list)) 1201 sd->taken = 1;
1039 sort__first_dimension = idx; 1202
1203 return 0;
1204}
1205
1206static int __hpp_dimension__add(struct hpp_dimension *hd)
1207{
1208 if (!hd->taken) {
1209 hd->taken = 1;
1210
1211 perf_hpp__register_sort_field(hd->fmt);
1212 }
1213 return 0;
1214}
1215
1216static int __sort_dimension__add_output(struct sort_dimension *sd)
1217{
1218 if (sd->taken)
1219 return 0;
1220
1221 if (__sort_dimension__add_hpp_output(sd) < 0)
1222 return -1;
1040 1223
1041 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1042 sd->taken = 1; 1224 sd->taken = 1;
1225 return 0;
1226}
1227
1228static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1229{
1230 if (!hd->taken) {
1231 hd->taken = 1;
1232
1233 perf_hpp__column_register(hd->fmt);
1234 }
1235 return 0;
1043} 1236}
1044 1237
1045int sort_dimension__add(const char *tok) 1238int sort_dimension__add(const char *tok)
@@ -1068,8 +1261,16 @@ int sort_dimension__add(const char *tok)
1068 sort__has_dso = 1; 1261 sort__has_dso = 1;
1069 } 1262 }
1070 1263
1071 __sort_dimension__add(sd, i); 1264 return __sort_dimension__add(sd);
1072 return 0; 1265 }
1266
1267 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1268 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1269
1270 if (strncasecmp(tok, hd->name, strlen(tok)))
1271 continue;
1272
1273 return __hpp_dimension__add(hd);
1073 } 1274 }
1074 1275
1075 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 1276 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -1084,7 +1285,7 @@ int sort_dimension__add(const char *tok)
1084 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) 1285 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1085 sort__has_sym = 1; 1286 sort__has_sym = 1;
1086 1287
1087 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK); 1288 __sort_dimension__add(sd);
1088 return 0; 1289 return 0;
1089 } 1290 }
1090 1291
@@ -1100,18 +1301,47 @@ int sort_dimension__add(const char *tok)
1100 if (sd->entry == &sort_mem_daddr_sym) 1301 if (sd->entry == &sort_mem_daddr_sym)
1101 sort__has_sym = 1; 1302 sort__has_sym = 1;
1102 1303
1103 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE); 1304 __sort_dimension__add(sd);
1104 return 0; 1305 return 0;
1105 } 1306 }
1106 1307
1107 return -ESRCH; 1308 return -ESRCH;
1108} 1309}
1109 1310
1110int setup_sorting(void) 1311static const char *get_default_sort_order(void)
1111{ 1312{
1112 char *tmp, *tok, *str = strdup(sort_order); 1313 const char *default_sort_orders[] = {
1314 default_sort_order,
1315 default_branch_sort_order,
1316 default_mem_sort_order,
1317 default_top_sort_order,
1318 default_diff_sort_order,
1319 };
1320
1321 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1322
1323 return default_sort_orders[sort__mode];
1324}
1325
1326static int __setup_sorting(void)
1327{
1328 char *tmp, *tok, *str;
1329 const char *sort_keys = sort_order;
1113 int ret = 0; 1330 int ret = 0;
1114 1331
1332 if (sort_keys == NULL) {
1333 if (field_order) {
1334 /*
1335 * If user specified field order but no sort order,
1336 * we'll honor it and not add default sort orders.
1337 */
1338 return 0;
1339 }
1340
1341 sort_keys = get_default_sort_order();
1342 }
1343
1344 str = strdup(sort_keys);
1115 if (str == NULL) { 1345 if (str == NULL) {
1116 error("Not enough memory to setup sort keys"); 1346 error("Not enough memory to setup sort keys");
1117 return -ENOMEM; 1347 return -ENOMEM;
@@ -1133,6 +1363,17 @@ int setup_sorting(void)
1133 return ret; 1363 return ret;
1134} 1364}
1135 1365
1366bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
1367{
1368 if (perf_hpp__is_sort_entry(format)) {
1369 struct hpp_sort_entry *hse;
1370
1371 hse = container_of(format, struct hpp_sort_entry, hpp);
1372 return hse->se->elide;
1373 }
1374 return false;
1375}
1376
1136static void sort_entry__setup_elide(struct sort_entry *se, 1377static void sort_entry__setup_elide(struct sort_entry *se,
1137 struct strlist *list, 1378 struct strlist *list,
1138 const char *list_name, FILE *fp) 1379 const char *list_name, FILE *fp)
@@ -1147,7 +1388,8 @@ static void sort_entry__setup_elide(struct sort_entry *se,
1147 1388
1148void sort__setup_elide(FILE *output) 1389void sort__setup_elide(FILE *output)
1149{ 1390{
1150 struct sort_entry *se; 1391 struct perf_hpp_fmt *fmt;
1392 struct hpp_sort_entry *hse;
1151 1393
1152 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, 1394 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1153 "dso", output); 1395 "dso", output);
@@ -1188,11 +1430,157 @@ void sort__setup_elide(FILE *output)
1188 * It makes no sense to elide all of sort entries. 1430 * It makes no sense to elide all of sort entries.
1189 * Just revert them to show up again. 1431 * Just revert them to show up again.
1190 */ 1432 */
1191 list_for_each_entry(se, &hist_entry__sort_list, list) { 1433 perf_hpp__for_each_format(fmt) {
1192 if (!se->elide) 1434 if (!perf_hpp__is_sort_entry(fmt))
1435 continue;
1436
1437 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1438 if (!hse->se->elide)
1193 return; 1439 return;
1194 } 1440 }
1195 1441
1196 list_for_each_entry(se, &hist_entry__sort_list, list) 1442 perf_hpp__for_each_format(fmt) {
1197 se->elide = false; 1443 if (!perf_hpp__is_sort_entry(fmt))
1444 continue;
1445
1446 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1447 hse->se->elide = false;
1448 }
1449}
1450
1451static int output_field_add(char *tok)
1452{
1453 unsigned int i;
1454
1455 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1456 struct sort_dimension *sd = &common_sort_dimensions[i];
1457
1458 if (strncasecmp(tok, sd->name, strlen(tok)))
1459 continue;
1460
1461 return __sort_dimension__add_output(sd);
1462 }
1463
1464 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1465 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1466
1467 if (strncasecmp(tok, hd->name, strlen(tok)))
1468 continue;
1469
1470 return __hpp_dimension__add_output(hd);
1471 }
1472
1473 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1474 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1475
1476 if (strncasecmp(tok, sd->name, strlen(tok)))
1477 continue;
1478
1479 return __sort_dimension__add_output(sd);
1480 }
1481
1482 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1483 struct sort_dimension *sd = &memory_sort_dimensions[i];
1484
1485 if (strncasecmp(tok, sd->name, strlen(tok)))
1486 continue;
1487
1488 return __sort_dimension__add_output(sd);
1489 }
1490
1491 return -ESRCH;
1492}
1493
1494static void reset_dimensions(void)
1495{
1496 unsigned int i;
1497
1498 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1499 common_sort_dimensions[i].taken = 0;
1500
1501 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1502 hpp_sort_dimensions[i].taken = 0;
1503
1504 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1505 bstack_sort_dimensions[i].taken = 0;
1506
1507 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1508 memory_sort_dimensions[i].taken = 0;
1509}
1510
1511static int __setup_output_field(void)
1512{
1513 char *tmp, *tok, *str;
1514 int ret = 0;
1515
1516 if (field_order == NULL)
1517 return 0;
1518
1519 reset_dimensions();
1520
1521 str = strdup(field_order);
1522 if (str == NULL) {
1523 error("Not enough memory to setup output fields");
1524 return -ENOMEM;
1525 }
1526
1527 for (tok = strtok_r(str, ", ", &tmp);
1528 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1529 ret = output_field_add(tok);
1530 if (ret == -EINVAL) {
1531 error("Invalid --fields key: `%s'", tok);
1532 break;
1533 } else if (ret == -ESRCH) {
1534 error("Unknown --fields key: `%s'", tok);
1535 break;
1536 }
1537 }
1538
1539 free(str);
1540 return ret;
1541}
1542
1543int setup_sorting(void)
1544{
1545 int err;
1546
1547 err = __setup_sorting();
1548 if (err < 0)
1549 return err;
1550
1551 if (parent_pattern != default_parent_pattern) {
1552 err = sort_dimension__add("parent");
1553 if (err < 0)
1554 return err;
1555 }
1556
1557 reset_dimensions();
1558
1559 /*
1560 * perf diff doesn't use default hpp output fields.
1561 */
1562 if (sort__mode != SORT_MODE__DIFF)
1563 perf_hpp__init();
1564
1565 err = __setup_output_field();
1566 if (err < 0)
1567 return err;
1568
1569 /* copy sort keys to output fields */
1570 perf_hpp__setup_output_field();
1571 /* and then copy output fields to sort keys */
1572 perf_hpp__append_sort_keys();
1573
1574 return 0;
1575}
1576
1577void reset_output_field(void)
1578{
1579 sort__need_collapse = 0;
1580 sort__has_parent = 0;
1581 sort__has_sym = 0;
1582 sort__has_dso = 0;
1583
1584 reset_dimensions();
1585 perf_hpp__reset_output_field();
1198} 1586}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 43e5ff42a609..5f38d925e92f 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -25,6 +25,7 @@
25 25
26extern regex_t parent_regex; 26extern regex_t parent_regex;
27extern const char *sort_order; 27extern const char *sort_order;
28extern const char *field_order;
28extern const char default_parent_pattern[]; 29extern const char default_parent_pattern[];
29extern const char *parent_pattern; 30extern const char *parent_pattern;
30extern const char default_sort_order[]; 31extern const char default_sort_order[];
@@ -133,6 +134,8 @@ enum sort_mode {
133 SORT_MODE__NORMAL, 134 SORT_MODE__NORMAL,
134 SORT_MODE__BRANCH, 135 SORT_MODE__BRANCH,
135 SORT_MODE__MEMORY, 136 SORT_MODE__MEMORY,
137 SORT_MODE__TOP,
138 SORT_MODE__DIFF,
136}; 139};
137 140
138enum sort_type { 141enum sort_type {
@@ -179,6 +182,7 @@ struct sort_entry {
179 182
180 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *); 183 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
181 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *); 184 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *);
185 int64_t (*se_sort)(struct hist_entry *, struct hist_entry *);
182 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size, 186 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size,
183 unsigned int width); 187 unsigned int width);
184 u8 se_width_idx; 188 u8 se_width_idx;
@@ -189,6 +193,8 @@ extern struct sort_entry sort_thread;
189extern struct list_head hist_entry__sort_list; 193extern struct list_head hist_entry__sort_list;
190 194
191int setup_sorting(void); 195int setup_sorting(void);
196int setup_output_field(void);
197void reset_output_field(void);
192extern int sort_dimension__add(const char *); 198extern int sort_dimension__add(const char *);
193void sort__setup_elide(FILE *fp); 199void sort__setup_elide(FILE *fp);
194 200
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index ae8ccd7227cf..5667fc3e39cf 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_STATS_H 1#ifndef __PERF_STATS_H
2#define __PERF_STATS_H 2#define __PERF_STATS_H
3 3
4#include "types.h" 4#include <linux/types.h>
5 5
6struct stats 6struct stats
7{ 7{
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 43262b83c541..6a0a13d07a28 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -17,7 +17,7 @@
17#include <stdlib.h> 17#include <stdlib.h>
18#include <unistd.h> 18#include <unistd.h>
19#include <string.h> 19#include <string.h>
20#include <linux/bitops.h> 20#include <linux/bitmap.h>
21 21
22#include "perf.h" 22#include "perf.h"
23#include "svghelper.h" 23#include "svghelper.h"
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index f7b4d6e699ea..e3aff5332e30 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_SVGHELPER_H 1#ifndef __PERF_SVGHELPER_H
2#define __PERF_SVGHELPER_H 2#define __PERF_SVGHELPER_H
3 3
4#include "types.h" 4#include <linux/types.h>
5 5
6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); 6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end);
7extern void svg_box(int Yslot, u64 start, u64 end, const char *type); 7extern void svg_box(int Yslot, u64 start, u64 end, const char *type);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 501e4e722e8e..33ede53fa6b9 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -12,6 +12,7 @@
12#include <byteswap.h> 12#include <byteswap.h>
13#include <libgen.h> 13#include <libgen.h>
14#include "build-id.h" 14#include "build-id.h"
15#include "event.h"
15 16
16#ifdef HAVE_LIBELF_SUPPORT 17#ifdef HAVE_LIBELF_SUPPORT
17#include <libelf.h> 18#include <libelf.h>
@@ -115,7 +116,8 @@ struct symbol_conf {
115 annotate_asm_raw, 116 annotate_asm_raw,
116 annotate_src, 117 annotate_src,
117 event_group, 118 event_group,
118 demangle; 119 demangle,
120 filter_relative;
119 const char *vmlinux_name, 121 const char *vmlinux_name,
120 *kallsyms_name, 122 *kallsyms_name,
121 *source_prefix, 123 *source_prefix,
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 3ce0498bdae6..2fde0d5e40b5 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -8,6 +8,22 @@
8#include "debug.h" 8#include "debug.h"
9#include "comm.h" 9#include "comm.h"
10 10
11int thread__init_map_groups(struct thread *thread, struct machine *machine)
12{
13 struct thread *leader;
14 pid_t pid = thread->pid_;
15
16 if (pid == thread->tid) {
17 thread->mg = map_groups__new();
18 } else {
19 leader = machine__findnew_thread(machine, pid, pid);
20 if (leader)
21 thread->mg = map_groups__get(leader->mg);
22 }
23
24 return thread->mg ? 0 : -1;
25}
26
11struct thread *thread__new(pid_t pid, pid_t tid) 27struct thread *thread__new(pid_t pid, pid_t tid)
12{ 28{
13 char *comm_str; 29 char *comm_str;
@@ -15,7 +31,6 @@ struct thread *thread__new(pid_t pid, pid_t tid)
15 struct thread *thread = zalloc(sizeof(*thread)); 31 struct thread *thread = zalloc(sizeof(*thread));
16 32
17 if (thread != NULL) { 33 if (thread != NULL) {
18 map_groups__init(&thread->mg);
19 thread->pid_ = pid; 34 thread->pid_ = pid;
20 thread->tid = tid; 35 thread->tid = tid;
21 thread->ppid = -1; 36 thread->ppid = -1;
@@ -45,7 +60,8 @@ void thread__delete(struct thread *thread)
45{ 60{
46 struct comm *comm, *tmp; 61 struct comm *comm, *tmp;
47 62
48 map_groups__exit(&thread->mg); 63 map_groups__put(thread->mg);
64 thread->mg = NULL;
49 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { 65 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
50 list_del(&comm->list); 66 list_del(&comm->list);
51 comm__free(comm); 67 comm__free(comm);
@@ -111,18 +127,35 @@ int thread__comm_len(struct thread *thread)
111size_t thread__fprintf(struct thread *thread, FILE *fp) 127size_t thread__fprintf(struct thread *thread, FILE *fp)
112{ 128{
113 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) + 129 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
114 map_groups__fprintf(&thread->mg, verbose, fp); 130 map_groups__fprintf(thread->mg, verbose, fp);
115} 131}
116 132
117void thread__insert_map(struct thread *thread, struct map *map) 133void thread__insert_map(struct thread *thread, struct map *map)
118{ 134{
119 map_groups__fixup_overlappings(&thread->mg, map, verbose, stderr); 135 map_groups__fixup_overlappings(thread->mg, map, verbose, stderr);
120 map_groups__insert(&thread->mg, map); 136 map_groups__insert(thread->mg, map);
137}
138
139static int thread__clone_map_groups(struct thread *thread,
140 struct thread *parent)
141{
142 int i;
143
144 /* This is new thread, we share map groups for process. */
145 if (thread->pid_ == parent->pid_)
146 return 0;
147
148 /* But this one is new process, copy maps. */
149 for (i = 0; i < MAP__NR_TYPES; ++i)
150 if (map_groups__clone(thread->mg, parent->mg, i) < 0)
151 return -ENOMEM;
152
153 return 0;
121} 154}
122 155
123int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) 156int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
124{ 157{
125 int i, err; 158 int err;
126 159
127 if (parent->comm_set) { 160 if (parent->comm_set) {
128 const char *comm = thread__comm_str(parent); 161 const char *comm = thread__comm_str(parent);
@@ -134,13 +167,8 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
134 thread->comm_set = true; 167 thread->comm_set = true;
135 } 168 }
136 169
137 for (i = 0; i < MAP__NR_TYPES; ++i)
138 if (map_groups__clone(&thread->mg, &parent->mg, i) < 0)
139 return -ENOMEM;
140
141 thread->ppid = parent->tid; 170 thread->ppid = parent->tid;
142 171 return thread__clone_map_groups(thread, parent);
143 return 0;
144} 172}
145 173
146void thread__find_cpumode_addr_location(struct thread *thread, 174void thread__find_cpumode_addr_location(struct thread *thread,
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 9b29f085aede..3c0c2724f82c 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -13,7 +13,7 @@ struct thread {
13 struct rb_node rb_node; 13 struct rb_node rb_node;
14 struct list_head node; 14 struct list_head node;
15 }; 15 };
16 struct map_groups mg; 16 struct map_groups *mg;
17 pid_t pid_; /* Not all tools update this */ 17 pid_t pid_; /* Not all tools update this */
18 pid_t tid; 18 pid_t tid;
19 pid_t ppid; 19 pid_t ppid;
@@ -30,6 +30,7 @@ struct machine;
30struct comm; 30struct comm;
31 31
32struct thread *thread__new(pid_t pid, pid_t tid); 32struct thread *thread__new(pid_t pid, pid_t tid);
33int thread__init_map_groups(struct thread *thread, struct machine *machine);
33void thread__delete(struct thread *thread); 34void thread__delete(struct thread *thread);
34static inline void thread__exited(struct thread *thread) 35static inline void thread__exited(struct thread *thread)
35{ 36{
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index dab14d0ad3d0..f92c37abb0a8 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -2,7 +2,7 @@
2#define __PERF_TOP_H 1 2#define __PERF_TOP_H 1
3 3
4#include "tool.h" 4#include "tool.h"
5#include "types.h" 5#include <linux/types.h>
6#include <stddef.h> 6#include <stddef.h>
7#include <stdbool.h> 7#include <stdbool.h>
8#include <termios.h> 8#include <termios.h>
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
deleted file mode 100644
index c51fa6b70a28..000000000000
--- a/tools/perf/util/types.h
+++ /dev/null
@@ -1,24 +0,0 @@
1#ifndef __PERF_TYPES_H
2#define __PERF_TYPES_H
3
4#include <stdint.h>
5
6/*
7 * We define u64 as uint64_t for every architecture
8 * so that we can print it with "%"PRIx64 without getting warnings.
9 */
10typedef uint64_t u64;
11typedef int64_t s64;
12typedef unsigned int u32;
13typedef signed int s32;
14typedef unsigned short u16;
15typedef signed short s16;
16typedef unsigned char u8;
17typedef signed char s8;
18
19union u64_swap {
20 u64 val64;
21 u32 val32[2];
22};
23
24#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 67db73ec3dab..5ec80a575b50 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -7,7 +7,7 @@
7#include "unwind-libdw.h" 7#include "unwind-libdw.h"
8#include "machine.h" 8#include "machine.h"
9#include "thread.h" 9#include "thread.h"
10#include "types.h" 10#include <linux/types.h>
11#include "event.h" 11#include "event.h"
12#include "perf_regs.h" 12#include "perf_regs.h"
13 13
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index b031316f221a..f03061260b4e 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -1,7 +1,7 @@
1#ifndef __UNWIND_H 1#ifndef __UNWIND_H
2#define __UNWIND_H 2#define __UNWIND_H
3 3
4#include "types.h" 4#include <linux/types.h>
5#include "event.h" 5#include "event.h"
6#include "symbol.h" 6#include "symbol.h"
7 7
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 9f66549562bd..7fff6be07f07 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -166,6 +166,8 @@ static ssize_t ion(bool is_read, int fd, void *buf, size_t n)
166 ssize_t ret = is_read ? read(fd, buf, left) : 166 ssize_t ret = is_read ? read(fd, buf, left) :
167 write(fd, buf, left); 167 write(fd, buf, left);
168 168
169 if (ret < 0 && errno == EINTR)
170 continue;
169 if (ret <= 0) 171 if (ret <= 0)
170 return ret; 172 return ret;
171 173
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 6995d66f225c..b03da44e94e4 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -69,7 +69,7 @@
69#include <sys/ioctl.h> 69#include <sys/ioctl.h>
70#include <inttypes.h> 70#include <inttypes.h>
71#include <linux/magic.h> 71#include <linux/magic.h>
72#include "types.h" 72#include <linux/types.h>
73#include <sys/ttydefaults.h> 73#include <sys/ttydefaults.h>
74#include <api/fs/debugfs.h> 74#include <api/fs/debugfs.h>
75#include <termios.h> 75#include <termios.h>
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
index 2fa967e1a88a..b21a80c6cf8d 100644
--- a/tools/perf/util/values.h
+++ b/tools/perf/util/values.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_VALUES_H 1#ifndef __PERF_VALUES_H
2#define __PERF_VALUES_H 2#define __PERF_VALUES_H
3 3
4#include "types.h" 4#include <linux/types.h>
5 5
6struct perf_read_values { 6struct perf_read_values {
7 int threads; 7 int threads;
diff --git a/tools/virtio/Makefile b/tools/virtio/Makefile
index 3187c62d9814..9325f4693821 100644
--- a/tools/virtio/Makefile
+++ b/tools/virtio/Makefile
@@ -3,7 +3,7 @@ test: virtio_test vringh_test
3virtio_test: virtio_ring.o virtio_test.o 3virtio_test: virtio_ring.o virtio_test.o
4vringh_test: vringh_test.o vringh.o virtio_ring.o 4vringh_test: vringh_test.o vringh.o virtio_ring.o
5 5
6CFLAGS += -g -O2 -Wall -I. -I ../../usr/include/ -Wno-pointer-sign -fno-strict-overflow -fno-strict-aliasing -fno-common -MMD -U_FORTIFY_SOURCE 6CFLAGS += -g -O2 -Wall -I. -I../include/ -I ../../usr/include/ -Wno-pointer-sign -fno-strict-overflow -fno-strict-aliasing -fno-common -MMD -U_FORTIFY_SOURCE
7vpath %.c ../../drivers/virtio ../../drivers/vhost 7vpath %.c ../../drivers/virtio ../../drivers/vhost
8mod: 8mod:
9 ${MAKE} -C `pwd`/../.. M=`pwd`/vhost_test 9 ${MAKE} -C `pwd`/../.. M=`pwd`/vhost_test
diff --git a/tools/virtio/linux/kernel.h b/tools/virtio/linux/kernel.h
index fba705963968..1e8ce6979c1e 100644
--- a/tools/virtio/linux/kernel.h
+++ b/tools/virtio/linux/kernel.h
@@ -38,13 +38,6 @@ struct page {
38 38
39#define __printf(a,b) __attribute__((format(printf,a,b))) 39#define __printf(a,b) __attribute__((format(printf,a,b)))
40 40
41typedef enum {
42 GFP_KERNEL,
43 GFP_ATOMIC,
44 __GFP_HIGHMEM,
45 __GFP_HIGH
46} gfp_t;
47
48#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 41#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
49 42
50extern void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end; 43extern void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end;
diff --git a/tools/virtio/linux/types.h b/tools/virtio/linux/types.h
deleted file mode 100644
index f8ebb9a2b3d6..000000000000
--- a/tools/virtio/linux/types.h
+++ /dev/null
@@ -1,28 +0,0 @@
1#ifndef TYPES_H
2#define TYPES_H
3#include <stdint.h>
4
5#define __force
6#define __user
7#define __must_check
8#define __cold
9
10typedef uint64_t u64;
11typedef int64_t s64;
12typedef uint32_t u32;
13typedef int32_t s32;
14typedef uint16_t u16;
15typedef int16_t s16;
16typedef uint8_t u8;
17typedef int8_t s8;
18
19typedef uint64_t __u64;
20typedef int64_t __s64;
21typedef uint32_t __u32;
22typedef int32_t __s32;
23typedef uint16_t __u16;
24typedef int16_t __s16;
25typedef uint8_t __u8;
26typedef int8_t __s8;
27
28#endif /* TYPES_H */