aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/kernel/perf_event.c4
-rw-r--r--arch/powerpc/include/asm/uprobes.h5
-rw-r--r--arch/powerpc/kernel/uprobes.c2
-rw-r--r--arch/x86/kernel/cpu/Makefile2
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_rapl.c679
-rw-r--r--include/linux/perf_event.h1
-rw-r--r--include/linux/uprobes.h52
-rw-r--r--include/uapi/linux/perf_event.h1
-rw-r--r--kernel/events/core.c31
-rw-r--r--kernel/events/ring_buffer.c42
-rw-r--r--kernel/events/uprobes.c60
-rw-r--r--tools/Makefile12
-rw-r--r--tools/include/asm/bug.h (renamed from tools/perf/util/include/asm/bug.h)9
-rw-r--r--tools/include/linux/compiler.h (renamed from tools/perf/util/include/linux/compiler.h)12
-rw-r--r--tools/lib/api/Makefile (renamed from tools/lib/lk/Makefile)18
-rw-r--r--tools/lib/api/fs/debugfs.c (renamed from tools/lib/lk/debugfs.c)0
-rw-r--r--tools/lib/api/fs/debugfs.h (renamed from tools/lib/lk/debugfs.h)6
-rw-r--r--tools/lib/symbol/kallsyms.c58
-rw-r--r--tools/lib/symbol/kallsyms.h24
-rw-r--r--tools/lib/traceevent/Makefile191
-rw-r--r--tools/lib/traceevent/event-parse.c244
-rw-r--r--tools/lib/traceevent/event-parse.h86
-rw-r--r--tools/lib/traceevent/event-plugin.c215
-rw-r--r--tools/lib/traceevent/event-utils.h4
-rw-r--r--tools/lib/traceevent/parse-filter.c673
-rw-r--r--tools/lib/traceevent/parse-utils.c44
-rw-r--r--tools/lib/traceevent/plugin_cfg80211.c30
-rw-r--r--tools/lib/traceevent/plugin_function.c163
-rw-r--r--tools/lib/traceevent/plugin_hrtimer.c88
-rw-r--r--tools/lib/traceevent/plugin_jbd2.c77
-rw-r--r--tools/lib/traceevent/plugin_kmem.c94
-rw-r--r--tools/lib/traceevent/plugin_kvm.c465
-rw-r--r--tools/lib/traceevent/plugin_mac80211.c102
-rw-r--r--tools/lib/traceevent/plugin_sched_switch.c160
-rw-r--r--tools/lib/traceevent/plugin_scsi.c429
-rw-r--r--tools/lib/traceevent/plugin_xen.c136
-rw-r--r--tools/lib/traceevent/trace-seq.c67
-rw-r--r--tools/perf/Documentation/perf-archive.txt6
-rw-r--r--tools/perf/Documentation/perf-kvm.txt34
-rw-r--r--tools/perf/Documentation/perf-record.txt20
-rw-r--r--tools/perf/Documentation/perf-report.txt9
-rw-r--r--tools/perf/Documentation/perf-script.txt14
-rw-r--r--tools/perf/Documentation/perf-stat.txt2
-rw-r--r--tools/perf/Documentation/perf-timechart.txt42
-rw-r--r--tools/perf/Documentation/perf-top.txt5
-rw-r--r--tools/perf/MANIFEST6
-rw-r--r--tools/perf/Makefile13
-rw-r--r--tools/perf/Makefile.perf66
-rw-r--r--tools/perf/arch/common.c3
-rw-r--r--tools/perf/builtin-annotate.c17
-rw-r--r--tools/perf/builtin-diff.c103
-rw-r--r--tools/perf/builtin-evlist.c2
-rw-r--r--tools/perf/builtin-inject.c67
-rw-r--r--tools/perf/builtin-kvm.c25
-rw-r--r--tools/perf/builtin-mem.c5
-rw-r--r--tools/perf/builtin-probe.c67
-rw-r--r--tools/perf/builtin-record.c201
-rw-r--r--tools/perf/builtin-report.c433
-rw-r--r--tools/perf/builtin-sched.c2
-rw-r--r--tools/perf/builtin-script.c266
-rw-r--r--tools/perf/builtin-stat.c186
-rw-r--r--tools/perf/builtin-timechart.c754
-rw-r--r--tools/perf/builtin-top.c88
-rw-r--r--tools/perf/builtin-trace.c98
-rw-r--r--tools/perf/config/Makefile136
-rw-r--r--tools/perf/config/Makefile.arch22
-rw-r--r--tools/perf/config/feature-checks/.gitignore2
-rw-r--r--tools/perf/config/feature-checks/Makefile129
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-stackprotector.c6
-rw-r--r--tools/perf/config/feature-checks/test-volatile-register-var.c6
-rw-r--r--tools/perf/config/utilities.mak7
-rw-r--r--tools/perf/perf-completion.sh (renamed from tools/perf/bash_completion)104
-rw-r--r--tools/perf/perf.c2
-rw-r--r--tools/perf/perf.h6
-rw-r--r--tools/perf/tests/attr/test-record-no-inherit2
-rw-r--r--tools/perf/tests/code-reading.c9
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c2
-rw-r--r--tools/perf/tests/hists_link.c4
-rw-r--r--tools/perf/tests/keep-tracking.c9
-rw-r--r--tools/perf/tests/make58
-rw-r--r--tools/perf/tests/mmap-basic.c25
-rw-r--r--tools/perf/tests/open-syscall-tp-fields.c26
-rw-r--r--tools/perf/tests/parse-events.c12
-rw-r--r--tools/perf/tests/perf-record.c29
-rwxr-xr-xtools/perf/tests/perf-targz-src-pkg21
-rw-r--r--tools/perf/tests/perf-time-to-tsc.c8
-rw-r--r--tools/perf/tests/sw-clock.c18
-rw-r--r--tools/perf/tests/task-exit.c33
-rw-r--r--tools/perf/ui/browser.c8
-rw-r--r--tools/perf/ui/browser.h2
-rw-r--r--tools/perf/ui/browsers/header.c127
-rw-r--r--tools/perf/ui/browsers/hists.c68
-rw-r--r--tools/perf/ui/browsers/scripts.c3
-rw-r--r--tools/perf/ui/gtk/hists.c2
-rw-r--r--tools/perf/ui/gtk/util.c3
-rw-r--r--tools/perf/ui/stdio/hist.c2
-rw-r--r--tools/perf/ui/tui/util.c19
-rw-r--r--tools/perf/util/alias.c6
-rw-r--r--tools/perf/util/annotate.c75
-rw-r--r--tools/perf/util/annotate.h9
-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.c46
-rw-r--r--tools/perf/util/callchain.h8
-rw-r--r--tools/perf/util/cgroup.c6
-rw-r--r--tools/perf/util/color.c15
-rw-r--r--tools/perf/util/color.h1
-rw-r--r--tools/perf/util/comm.c21
-rw-r--r--tools/perf/util/comm.h2
-rw-r--r--tools/perf/util/data.c6
-rw-r--r--tools/perf/util/data.h14
-rw-r--r--tools/perf/util/debug.c31
-rw-r--r--tools/perf/util/debug.h2
-rw-r--r--tools/perf/util/dso.c134
-rw-r--r--tools/perf/util/dso.h31
-rw-r--r--tools/perf/util/event.c61
-rw-r--r--tools/perf/util/event.h7
-rw-r--r--tools/perf/util/evlist.c123
-rw-r--r--tools/perf/util/evlist.h81
-rw-r--r--tools/perf/util/evsel.c75
-rw-r--r--tools/perf/util/evsel.h7
-rw-r--r--tools/perf/util/header.c69
-rw-r--r--tools/perf/util/header.h10
-rw-r--r--tools/perf/util/help.c7
-rw-r--r--tools/perf/util/hist.c49
-rw-r--r--tools/perf/util/hist.h3
-rw-r--r--tools/perf/util/machine.c36
-rw-r--r--tools/perf/util/map.c17
-rw-r--r--tools/perf/util/map.h2
-rw-r--r--tools/perf/util/parse-events.c43
-rw-r--r--tools/perf/util/parse-options.c21
-rw-r--r--tools/perf/util/parse-options.h8
-rw-r--r--tools/perf/util/pmu.c142
-rw-r--r--tools/perf/util/pmu.h3
-rw-r--r--tools/perf/util/probe-event.c258
-rw-r--r--tools/perf/util/probe-event.h7
-rw-r--r--tools/perf/util/probe-finder.c33
-rw-r--r--tools/perf/util/python-ext-sources1
-rw-r--r--tools/perf/util/python.c3
-rw-r--r--tools/perf/util/record.c52
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c22
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c28
-rw-r--r--tools/perf/util/session.c110
-rw-r--r--tools/perf/util/session.h10
-rw-r--r--tools/perf/util/setup.py4
-rw-r--r--tools/perf/util/sort.c22
-rw-r--r--tools/perf/util/srcline.c72
-rw-r--r--tools/perf/util/strbuf.c2
-rw-r--r--tools/perf/util/strfilter.c2
-rw-r--r--tools/perf/util/string.c2
-rw-r--r--tools/perf/util/strlist.c3
-rw-r--r--tools/perf/util/svghelper.c235
-rw-r--r--tools/perf/util/svghelper.h17
-rw-r--r--tools/perf/util/symbol-elf.c8
-rw-r--r--tools/perf/util/symbol-minimal.c4
-rw-r--r--tools/perf/util/symbol.c165
-rw-r--r--tools/perf/util/symbol.h16
-rw-r--r--tools/perf/util/target.c11
-rw-r--r--tools/perf/util/target.h17
-rw-r--r--tools/perf/util/thread.c7
-rw-r--r--tools/perf/util/thread.h12
-rw-r--r--tools/perf/util/thread_map.c20
-rw-r--r--tools/perf/util/top.c2
-rw-r--r--tools/perf/util/top.h2
-rw-r--r--tools/perf/util/trace-event-info.c12
-rw-r--r--tools/perf/util/trace-event-parse.c13
-rw-r--r--tools/perf/util/trace-event-read.c20
-rw-r--r--tools/perf/util/trace-event-scripting.c3
-rw-r--r--tools/perf/util/trace-event.c82
-rw-r--r--tools/perf/util/trace-event.h16
-rw-r--r--tools/perf/util/unwind.c28
-rw-r--r--tools/perf/util/util.c136
-rw-r--r--tools/perf/util/util.h26
-rw-r--r--tools/perf/util/values.c14
-rw-r--r--tools/perf/util/vdso.c2
-rw-r--r--tools/scripts/Makefile.include4
-rw-r--r--tools/vm/Makefile14
-rw-r--r--tools/vm/page-types.c2
179 files changed, 7725 insertions, 2704 deletions
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index bc3f2efa0d86..789d846a9184 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -99,10 +99,6 @@ int armpmu_event_set_period(struct perf_event *event)
99 s64 period = hwc->sample_period; 99 s64 period = hwc->sample_period;
100 int ret = 0; 100 int ret = 0;
101 101
102 /* The period may have been changed by PERF_EVENT_IOC_PERIOD */
103 if (unlikely(period != hwc->last_period))
104 left = period - (hwc->last_period - left);
105
106 if (unlikely(left <= -period)) { 102 if (unlikely(left <= -period)) {
107 left = period; 103 left = period;
108 local64_set(&hwc->period_left, left); 104 local64_set(&hwc->period_left, left);
diff --git a/arch/powerpc/include/asm/uprobes.h b/arch/powerpc/include/asm/uprobes.h
index 75c6ecdb8f37..7422a999a39a 100644
--- a/arch/powerpc/include/asm/uprobes.h
+++ b/arch/powerpc/include/asm/uprobes.h
@@ -36,9 +36,8 @@ typedef ppc_opcode_t uprobe_opcode_t;
36 36
37struct arch_uprobe { 37struct arch_uprobe {
38 union { 38 union {
39 u8 insn[MAX_UINSN_BYTES]; 39 u32 insn;
40 u8 ixol[MAX_UINSN_BYTES]; 40 u32 ixol;
41 u32 ainsn;
42 }; 41 };
43}; 42};
44 43
diff --git a/arch/powerpc/kernel/uprobes.c b/arch/powerpc/kernel/uprobes.c
index 59f419b935f2..003b20964ea0 100644
--- a/arch/powerpc/kernel/uprobes.c
+++ b/arch/powerpc/kernel/uprobes.c
@@ -186,7 +186,7 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
186 * emulate_step() returns 1 if the insn was successfully emulated. 186 * emulate_step() returns 1 if the insn was successfully emulated.
187 * For all other cases, we need to single-step in hardware. 187 * For all other cases, we need to single-step in hardware.
188 */ 188 */
189 ret = emulate_step(regs, auprobe->ainsn); 189 ret = emulate_step(regs, auprobe->insn);
190 if (ret > 0) 190 if (ret > 0)
191 return true; 191 return true;
192 192
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index 47b56a7e99cb..6359506a19ee 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -36,7 +36,7 @@ obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd_iommu.o
36endif 36endif
37obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o 37obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o
38obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o 38obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o
39obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o 39obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o perf_event_intel_rapl.o
40endif 40endif
41 41
42 42
diff --git a/arch/x86/kernel/cpu/perf_event_intel_rapl.c b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
new file mode 100644
index 000000000000..5ad35ad94d0f
--- /dev/null
+++ b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
@@ -0,0 +1,679 @@
1/*
2 * perf_event_intel_rapl.c: support Intel RAPL energy consumption counters
3 * Copyright (C) 2013 Google, Inc., Stephane Eranian
4 *
5 * Intel RAPL interface is specified in the IA-32 Manual Vol3b
6 * section 14.7.1 (September 2013)
7 *
8 * RAPL provides more controls than just reporting energy consumption
9 * however here we only expose the 3 energy consumption free running
10 * counters (pp0, pkg, dram).
11 *
12 * Each of those counters increments in a power unit defined by the
13 * RAPL_POWER_UNIT MSR. On SandyBridge, this unit is 1/(2^16) Joules
14 * but it can vary.
15 *
16 * Counter to rapl events mappings:
17 *
18 * pp0 counter: consumption of all physical cores (power plane 0)
19 * event: rapl_energy_cores
20 * perf code: 0x1
21 *
22 * pkg counter: consumption of the whole processor package
23 * event: rapl_energy_pkg
24 * perf code: 0x2
25 *
26 * dram counter: consumption of the dram domain (servers only)
27 * event: rapl_energy_dram
28 * perf code: 0x3
29 *
30 * dram counter: consumption of the builtin-gpu domain (client only)
31 * event: rapl_energy_gpu
32 * perf code: 0x4
33 *
34 * We manage those counters as free running (read-only). They may be
35 * use simultaneously by other tools, such as turbostat.
36 *
37 * The events only support system-wide mode counting. There is no
38 * sampling support because it does not make sense and is not
39 * supported by the RAPL hardware.
40 *
41 * Because we want to avoid floating-point operations in the kernel,
42 * the events are all reported in fixed point arithmetic (32.32).
43 * Tools must adjust the counts to convert them to Watts using
44 * the duration of the measurement. Tools may use a function such as
45 * ldexp(raw_count, -32);
46 */
47#include <linux/module.h>
48#include <linux/slab.h>
49#include <linux/perf_event.h>
50#include <asm/cpu_device_id.h>
51#include "perf_event.h"
52
53/*
54 * RAPL energy status counters
55 */
56#define RAPL_IDX_PP0_NRG_STAT 0 /* all cores */
57#define INTEL_RAPL_PP0 0x1 /* pseudo-encoding */
58#define RAPL_IDX_PKG_NRG_STAT 1 /* entire package */
59#define INTEL_RAPL_PKG 0x2 /* pseudo-encoding */
60#define RAPL_IDX_RAM_NRG_STAT 2 /* DRAM */
61#define INTEL_RAPL_RAM 0x3 /* pseudo-encoding */
62#define RAPL_IDX_PP1_NRG_STAT 3 /* DRAM */
63#define INTEL_RAPL_PP1 0x4 /* pseudo-encoding */
64
65/* Clients have PP0, PKG */
66#define RAPL_IDX_CLN (1<<RAPL_IDX_PP0_NRG_STAT|\
67 1<<RAPL_IDX_PKG_NRG_STAT|\
68 1<<RAPL_IDX_PP1_NRG_STAT)
69
70/* Servers have PP0, PKG, RAM */
71#define RAPL_IDX_SRV (1<<RAPL_IDX_PP0_NRG_STAT|\
72 1<<RAPL_IDX_PKG_NRG_STAT|\
73 1<<RAPL_IDX_RAM_NRG_STAT)
74
75/*
76 * event code: LSB 8 bits, passed in attr->config
77 * any other bit is reserved
78 */
79#define RAPL_EVENT_MASK 0xFFULL
80
81#define DEFINE_RAPL_FORMAT_ATTR(_var, _name, _format) \
82static ssize_t __rapl_##_var##_show(struct kobject *kobj, \
83 struct kobj_attribute *attr, \
84 char *page) \
85{ \
86 BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \
87 return sprintf(page, _format "\n"); \
88} \
89static struct kobj_attribute format_attr_##_var = \
90 __ATTR(_name, 0444, __rapl_##_var##_show, NULL)
91
92#define RAPL_EVENT_DESC(_name, _config) \
93{ \
94 .attr = __ATTR(_name, 0444, rapl_event_show, NULL), \
95 .config = _config, \
96}
97
98#define RAPL_CNTR_WIDTH 32 /* 32-bit rapl counters */
99
100struct rapl_pmu {
101 spinlock_t lock;
102 int hw_unit; /* 1/2^hw_unit Joule */
103 int n_active; /* number of active events */
104 struct list_head active_list;
105 struct pmu *pmu; /* pointer to rapl_pmu_class */
106 ktime_t timer_interval; /* in ktime_t unit */
107 struct hrtimer hrtimer;
108};
109
110static struct pmu rapl_pmu_class;
111static cpumask_t rapl_cpu_mask;
112static int rapl_cntr_mask;
113
114static DEFINE_PER_CPU(struct rapl_pmu *, rapl_pmu);
115static DEFINE_PER_CPU(struct rapl_pmu *, rapl_pmu_to_free);
116
117static inline u64 rapl_read_counter(struct perf_event *event)
118{
119 u64 raw;
120 rdmsrl(event->hw.event_base, raw);
121 return raw;
122}
123
124static inline u64 rapl_scale(u64 v)
125{
126 /*
127 * scale delta to smallest unit (1/2^32)
128 * users must then scale back: count * 1/(1e9*2^32) to get Joules
129 * or use ldexp(count, -32).
130 * Watts = Joules/Time delta
131 */
132 return v << (32 - __get_cpu_var(rapl_pmu)->hw_unit);
133}
134
135static u64 rapl_event_update(struct perf_event *event)
136{
137 struct hw_perf_event *hwc = &event->hw;
138 u64 prev_raw_count, new_raw_count;
139 s64 delta, sdelta;
140 int shift = RAPL_CNTR_WIDTH;
141
142again:
143 prev_raw_count = local64_read(&hwc->prev_count);
144 rdmsrl(event->hw.event_base, new_raw_count);
145
146 if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
147 new_raw_count) != prev_raw_count) {
148 cpu_relax();
149 goto again;
150 }
151
152 /*
153 * Now we have the new raw value and have updated the prev
154 * timestamp already. We can now calculate the elapsed delta
155 * (event-)time and add that to the generic event.
156 *
157 * Careful, not all hw sign-extends above the physical width
158 * of the count.
159 */
160 delta = (new_raw_count << shift) - (prev_raw_count << shift);
161 delta >>= shift;
162
163 sdelta = rapl_scale(delta);
164
165 local64_add(sdelta, &event->count);
166
167 return new_raw_count;
168}
169
170static void rapl_start_hrtimer(struct rapl_pmu *pmu)
171{
172 __hrtimer_start_range_ns(&pmu->hrtimer,
173 pmu->timer_interval, 0,
174 HRTIMER_MODE_REL_PINNED, 0);
175}
176
177static void rapl_stop_hrtimer(struct rapl_pmu *pmu)
178{
179 hrtimer_cancel(&pmu->hrtimer);
180}
181
182static enum hrtimer_restart rapl_hrtimer_handle(struct hrtimer *hrtimer)
183{
184 struct rapl_pmu *pmu = __get_cpu_var(rapl_pmu);
185 struct perf_event *event;
186 unsigned long flags;
187
188 if (!pmu->n_active)
189 return HRTIMER_NORESTART;
190
191 spin_lock_irqsave(&pmu->lock, flags);
192
193 list_for_each_entry(event, &pmu->active_list, active_entry) {
194 rapl_event_update(event);
195 }
196
197 spin_unlock_irqrestore(&pmu->lock, flags);
198
199 hrtimer_forward_now(hrtimer, pmu->timer_interval);
200
201 return HRTIMER_RESTART;
202}
203
204static void rapl_hrtimer_init(struct rapl_pmu *pmu)
205{
206 struct hrtimer *hr = &pmu->hrtimer;
207
208 hrtimer_init(hr, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
209 hr->function = rapl_hrtimer_handle;
210}
211
212static void __rapl_pmu_event_start(struct rapl_pmu *pmu,
213 struct perf_event *event)
214{
215 if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
216 return;
217
218 event->hw.state = 0;
219
220 list_add_tail(&event->active_entry, &pmu->active_list);
221
222 local64_set(&event->hw.prev_count, rapl_read_counter(event));
223
224 pmu->n_active++;
225 if (pmu->n_active == 1)
226 rapl_start_hrtimer(pmu);
227}
228
229static void rapl_pmu_event_start(struct perf_event *event, int mode)
230{
231 struct rapl_pmu *pmu = __get_cpu_var(rapl_pmu);
232 unsigned long flags;
233
234 spin_lock_irqsave(&pmu->lock, flags);
235 __rapl_pmu_event_start(pmu, event);
236 spin_unlock_irqrestore(&pmu->lock, flags);
237}
238
239static void rapl_pmu_event_stop(struct perf_event *event, int mode)
240{
241 struct rapl_pmu *pmu = __get_cpu_var(rapl_pmu);
242 struct hw_perf_event *hwc = &event->hw;
243 unsigned long flags;
244
245 spin_lock_irqsave(&pmu->lock, flags);
246
247 /* mark event as deactivated and stopped */
248 if (!(hwc->state & PERF_HES_STOPPED)) {
249 WARN_ON_ONCE(pmu->n_active <= 0);
250 pmu->n_active--;
251 if (pmu->n_active == 0)
252 rapl_stop_hrtimer(pmu);
253
254 list_del(&event->active_entry);
255
256 WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
257 hwc->state |= PERF_HES_STOPPED;
258 }
259
260 /* check if update of sw counter is necessary */
261 if ((mode & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
262 /*
263 * Drain the remaining delta count out of a event
264 * that we are disabling:
265 */
266 rapl_event_update(event);
267 hwc->state |= PERF_HES_UPTODATE;
268 }
269
270 spin_unlock_irqrestore(&pmu->lock, flags);
271}
272
273static int rapl_pmu_event_add(struct perf_event *event, int mode)
274{
275 struct rapl_pmu *pmu = __get_cpu_var(rapl_pmu);
276 struct hw_perf_event *hwc = &event->hw;
277 unsigned long flags;
278
279 spin_lock_irqsave(&pmu->lock, flags);
280
281 hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
282
283 if (mode & PERF_EF_START)
284 __rapl_pmu_event_start(pmu, event);
285
286 spin_unlock_irqrestore(&pmu->lock, flags);
287
288 return 0;
289}
290
291static void rapl_pmu_event_del(struct perf_event *event, int flags)
292{
293 rapl_pmu_event_stop(event, PERF_EF_UPDATE);
294}
295
296static int rapl_pmu_event_init(struct perf_event *event)
297{
298 u64 cfg = event->attr.config & RAPL_EVENT_MASK;
299 int bit, msr, ret = 0;
300
301 /* only look at RAPL events */
302 if (event->attr.type != rapl_pmu_class.type)
303 return -ENOENT;
304
305 /* check only supported bits are set */
306 if (event->attr.config & ~RAPL_EVENT_MASK)
307 return -EINVAL;
308
309 /*
310 * check event is known (determines counter)
311 */
312 switch (cfg) {
313 case INTEL_RAPL_PP0:
314 bit = RAPL_IDX_PP0_NRG_STAT;
315 msr = MSR_PP0_ENERGY_STATUS;
316 break;
317 case INTEL_RAPL_PKG:
318 bit = RAPL_IDX_PKG_NRG_STAT;
319 msr = MSR_PKG_ENERGY_STATUS;
320 break;
321 case INTEL_RAPL_RAM:
322 bit = RAPL_IDX_RAM_NRG_STAT;
323 msr = MSR_DRAM_ENERGY_STATUS;
324 break;
325 case INTEL_RAPL_PP1:
326 bit = RAPL_IDX_PP1_NRG_STAT;
327 msr = MSR_PP1_ENERGY_STATUS;
328 break;
329 default:
330 return -EINVAL;
331 }
332 /* check event supported */
333 if (!(rapl_cntr_mask & (1 << bit)))
334 return -EINVAL;
335
336 /* unsupported modes and filters */
337 if (event->attr.exclude_user ||
338 event->attr.exclude_kernel ||
339 event->attr.exclude_hv ||
340 event->attr.exclude_idle ||
341 event->attr.exclude_host ||
342 event->attr.exclude_guest ||
343 event->attr.sample_period) /* no sampling */
344 return -EINVAL;
345
346 /* must be done before validate_group */
347 event->hw.event_base = msr;
348 event->hw.config = cfg;
349 event->hw.idx = bit;
350
351 return ret;
352}
353
354static void rapl_pmu_event_read(struct perf_event *event)
355{
356 rapl_event_update(event);
357}
358
359static ssize_t rapl_get_attr_cpumask(struct device *dev,
360 struct device_attribute *attr, char *buf)
361{
362 int n = cpulist_scnprintf(buf, PAGE_SIZE - 2, &rapl_cpu_mask);
363
364 buf[n++] = '\n';
365 buf[n] = '\0';
366 return n;
367}
368
369static DEVICE_ATTR(cpumask, S_IRUGO, rapl_get_attr_cpumask, NULL);
370
371static struct attribute *rapl_pmu_attrs[] = {
372 &dev_attr_cpumask.attr,
373 NULL,
374};
375
376static struct attribute_group rapl_pmu_attr_group = {
377 .attrs = rapl_pmu_attrs,
378};
379
380EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01");
381EVENT_ATTR_STR(energy-pkg , rapl_pkg, "event=0x02");
382EVENT_ATTR_STR(energy-ram , rapl_ram, "event=0x03");
383EVENT_ATTR_STR(energy-gpu , rapl_gpu, "event=0x04");
384
385EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules");
386EVENT_ATTR_STR(energy-pkg.unit , rapl_pkg_unit, "Joules");
387EVENT_ATTR_STR(energy-ram.unit , rapl_ram_unit, "Joules");
388EVENT_ATTR_STR(energy-gpu.unit , rapl_gpu_unit, "Joules");
389
390/*
391 * we compute in 0.23 nJ increments regardless of MSR
392 */
393EVENT_ATTR_STR(energy-cores.scale, rapl_cores_scale, "2.3283064365386962890625e-10");
394EVENT_ATTR_STR(energy-pkg.scale, rapl_pkg_scale, "2.3283064365386962890625e-10");
395EVENT_ATTR_STR(energy-ram.scale, rapl_ram_scale, "2.3283064365386962890625e-10");
396EVENT_ATTR_STR(energy-gpu.scale, rapl_gpu_scale, "2.3283064365386962890625e-10");
397
398static struct attribute *rapl_events_srv_attr[] = {
399 EVENT_PTR(rapl_cores),
400 EVENT_PTR(rapl_pkg),
401 EVENT_PTR(rapl_ram),
402
403 EVENT_PTR(rapl_cores_unit),
404 EVENT_PTR(rapl_pkg_unit),
405 EVENT_PTR(rapl_ram_unit),
406
407 EVENT_PTR(rapl_cores_scale),
408 EVENT_PTR(rapl_pkg_scale),
409 EVENT_PTR(rapl_ram_scale),
410 NULL,
411};
412
413static struct attribute *rapl_events_cln_attr[] = {
414 EVENT_PTR(rapl_cores),
415 EVENT_PTR(rapl_pkg),
416 EVENT_PTR(rapl_gpu),
417
418 EVENT_PTR(rapl_cores_unit),
419 EVENT_PTR(rapl_pkg_unit),
420 EVENT_PTR(rapl_gpu_unit),
421
422 EVENT_PTR(rapl_cores_scale),
423 EVENT_PTR(rapl_pkg_scale),
424 EVENT_PTR(rapl_gpu_scale),
425 NULL,
426};
427
428static struct attribute_group rapl_pmu_events_group = {
429 .name = "events",
430 .attrs = NULL, /* patched at runtime */
431};
432
433DEFINE_RAPL_FORMAT_ATTR(event, event, "config:0-7");
434static struct attribute *rapl_formats_attr[] = {
435 &format_attr_event.attr,
436 NULL,
437};
438
439static struct attribute_group rapl_pmu_format_group = {
440 .name = "format",
441 .attrs = rapl_formats_attr,
442};
443
444const struct attribute_group *rapl_attr_groups[] = {
445 &rapl_pmu_attr_group,
446 &rapl_pmu_format_group,
447 &rapl_pmu_events_group,
448 NULL,
449};
450
451static struct pmu rapl_pmu_class = {
452 .attr_groups = rapl_attr_groups,
453 .task_ctx_nr = perf_invalid_context, /* system-wide only */
454 .event_init = rapl_pmu_event_init,
455 .add = rapl_pmu_event_add, /* must have */
456 .del = rapl_pmu_event_del, /* must have */
457 .start = rapl_pmu_event_start,
458 .stop = rapl_pmu_event_stop,
459 .read = rapl_pmu_event_read,
460};
461
462static void rapl_cpu_exit(int cpu)
463{
464 struct rapl_pmu *pmu = per_cpu(rapl_pmu, cpu);
465 int i, phys_id = topology_physical_package_id(cpu);
466 int target = -1;
467
468 /* find a new cpu on same package */
469 for_each_online_cpu(i) {
470 if (i == cpu)
471 continue;
472 if (phys_id == topology_physical_package_id(i)) {
473 target = i;
474 break;
475 }
476 }
477 /*
478 * clear cpu from cpumask
479 * if was set in cpumask and still some cpu on package,
480 * then move to new cpu
481 */
482 if (cpumask_test_and_clear_cpu(cpu, &rapl_cpu_mask) && target >= 0)
483 cpumask_set_cpu(target, &rapl_cpu_mask);
484
485 WARN_ON(cpumask_empty(&rapl_cpu_mask));
486 /*
487 * migrate events and context to new cpu
488 */
489 if (target >= 0)
490 perf_pmu_migrate_context(pmu->pmu, cpu, target);
491
492 /* cancel overflow polling timer for CPU */
493 rapl_stop_hrtimer(pmu);
494}
495
496static void rapl_cpu_init(int cpu)
497{
498 int i, phys_id = topology_physical_package_id(cpu);
499
500 /* check if phys_is is already covered */
501 for_each_cpu(i, &rapl_cpu_mask) {
502 if (phys_id == topology_physical_package_id(i))
503 return;
504 }
505 /* was not found, so add it */
506 cpumask_set_cpu(cpu, &rapl_cpu_mask);
507}
508
509static int rapl_cpu_prepare(int cpu)
510{
511 struct rapl_pmu *pmu = per_cpu(rapl_pmu, cpu);
512 int phys_id = topology_physical_package_id(cpu);
513 u64 ms;
514
515 if (pmu)
516 return 0;
517
518 if (phys_id < 0)
519 return -1;
520
521 pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
522 if (!pmu)
523 return -1;
524
525 spin_lock_init(&pmu->lock);
526
527 INIT_LIST_HEAD(&pmu->active_list);
528
529 /*
530 * grab power unit as: 1/2^unit Joules
531 *
532 * we cache in local PMU instance
533 */
534 rdmsrl(MSR_RAPL_POWER_UNIT, pmu->hw_unit);
535 pmu->hw_unit = (pmu->hw_unit >> 8) & 0x1FULL;
536 pmu->pmu = &rapl_pmu_class;
537
538 /*
539 * use reference of 200W for scaling the timeout
540 * to avoid missing counter overflows.
541 * 200W = 200 Joules/sec
542 * divide interval by 2 to avoid lockstep (2 * 100)
543 * if hw unit is 32, then we use 2 ms 1/200/2
544 */
545 if (pmu->hw_unit < 32)
546 ms = (1000 / (2 * 100)) * (1ULL << (32 - pmu->hw_unit - 1));
547 else
548 ms = 2;
549
550 pmu->timer_interval = ms_to_ktime(ms);
551
552 rapl_hrtimer_init(pmu);
553
554 /* set RAPL pmu for this cpu for now */
555 per_cpu(rapl_pmu, cpu) = pmu;
556 per_cpu(rapl_pmu_to_free, cpu) = NULL;
557
558 return 0;
559}
560
561static void rapl_cpu_kfree(int cpu)
562{
563 struct rapl_pmu *pmu = per_cpu(rapl_pmu_to_free, cpu);
564
565 kfree(pmu);
566
567 per_cpu(rapl_pmu_to_free, cpu) = NULL;
568}
569
570static int rapl_cpu_dying(int cpu)
571{
572 struct rapl_pmu *pmu = per_cpu(rapl_pmu, cpu);
573
574 if (!pmu)
575 return 0;
576
577 per_cpu(rapl_pmu, cpu) = NULL;
578
579 per_cpu(rapl_pmu_to_free, cpu) = pmu;
580
581 return 0;
582}
583
584static int rapl_cpu_notifier(struct notifier_block *self,
585 unsigned long action, void *hcpu)
586{
587 unsigned int cpu = (long)hcpu;
588
589 switch (action & ~CPU_TASKS_FROZEN) {
590 case CPU_UP_PREPARE:
591 rapl_cpu_prepare(cpu);
592 break;
593 case CPU_STARTING:
594 rapl_cpu_init(cpu);
595 break;
596 case CPU_UP_CANCELED:
597 case CPU_DYING:
598 rapl_cpu_dying(cpu);
599 break;
600 case CPU_ONLINE:
601 case CPU_DEAD:
602 rapl_cpu_kfree(cpu);
603 break;
604 case CPU_DOWN_PREPARE:
605 rapl_cpu_exit(cpu);
606 break;
607 default:
608 break;
609 }
610
611 return NOTIFY_OK;
612}
613
614static const struct x86_cpu_id rapl_cpu_match[] = {
615 [0] = { .vendor = X86_VENDOR_INTEL, .family = 6 },
616 [1] = {},
617};
618
619static int __init rapl_pmu_init(void)
620{
621 struct rapl_pmu *pmu;
622 int cpu, ret;
623
624 /*
625 * check for Intel processor family 6
626 */
627 if (!x86_match_cpu(rapl_cpu_match))
628 return 0;
629
630 /* check supported CPU */
631 switch (boot_cpu_data.x86_model) {
632 case 42: /* Sandy Bridge */
633 case 58: /* Ivy Bridge */
634 case 60: /* Haswell */
635 case 69: /* Haswell-Celeron */
636 rapl_cntr_mask = RAPL_IDX_CLN;
637 rapl_pmu_events_group.attrs = rapl_events_cln_attr;
638 break;
639 case 45: /* Sandy Bridge-EP */
640 case 62: /* IvyTown */
641 rapl_cntr_mask = RAPL_IDX_SRV;
642 rapl_pmu_events_group.attrs = rapl_events_srv_attr;
643 break;
644
645 default:
646 /* unsupported */
647 return 0;
648 }
649 get_online_cpus();
650
651 for_each_online_cpu(cpu) {
652 rapl_cpu_prepare(cpu);
653 rapl_cpu_init(cpu);
654 }
655
656 perf_cpu_notifier(rapl_cpu_notifier);
657
658 ret = perf_pmu_register(&rapl_pmu_class, "power", -1);
659 if (WARN_ON(ret)) {
660 pr_info("RAPL PMU detected, registration failed (%d), RAPL PMU disabled\n", ret);
661 put_online_cpus();
662 return -1;
663 }
664
665 pmu = __get_cpu_var(rapl_pmu);
666
667 pr_info("RAPL PMU detected, hw unit 2^-%d Joules,"
668 " API unit is 2^-32 Joules,"
669 " %d fixed counters"
670 " %llu ms ovfl timer\n",
671 pmu->hw_unit,
672 hweight32(rapl_cntr_mask),
673 ktime_to_ms(pmu->timer_interval));
674
675 put_online_cpus();
676
677 return 0;
678}
679device_initcall(rapl_pmu_init);
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 2e069d1288df..e56b07f5c9b6 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -320,6 +320,7 @@ struct perf_event {
320 struct list_head migrate_entry; 320 struct list_head migrate_entry;
321 321
322 struct hlist_node hlist_entry; 322 struct hlist_node hlist_entry;
323 struct list_head active_entry;
323 int nr_siblings; 324 int nr_siblings;
324 int group_flags; 325 int group_flags;
325 struct perf_event *group_leader; 326 struct perf_event *group_leader;
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index 319eae70fe84..e32251e00e62 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -26,16 +26,13 @@
26 26
27#include <linux/errno.h> 27#include <linux/errno.h>
28#include <linux/rbtree.h> 28#include <linux/rbtree.h>
29#include <linux/types.h>
29 30
30struct vm_area_struct; 31struct vm_area_struct;
31struct mm_struct; 32struct mm_struct;
32struct inode; 33struct inode;
33struct notifier_block; 34struct notifier_block;
34 35
35#ifdef CONFIG_ARCH_SUPPORTS_UPROBES
36# include <asm/uprobes.h>
37#endif
38
39#define UPROBE_HANDLER_REMOVE 1 36#define UPROBE_HANDLER_REMOVE 1
40#define UPROBE_HANDLER_MASK 1 37#define UPROBE_HANDLER_MASK 1
41 38
@@ -60,6 +57,8 @@ struct uprobe_consumer {
60}; 57};
61 58
62#ifdef CONFIG_UPROBES 59#ifdef CONFIG_UPROBES
60#include <asm/uprobes.h>
61
63enum uprobe_task_state { 62enum uprobe_task_state {
64 UTASK_RUNNING, 63 UTASK_RUNNING,
65 UTASK_SSTEP, 64 UTASK_SSTEP,
@@ -72,35 +71,28 @@ enum uprobe_task_state {
72 */ 71 */
73struct uprobe_task { 72struct uprobe_task {
74 enum uprobe_task_state state; 73 enum uprobe_task_state state;
75 struct arch_uprobe_task autask;
76 74
77 struct return_instance *return_instances; 75 union {
78 unsigned int depth; 76 struct {
79 struct uprobe *active_uprobe; 77 struct arch_uprobe_task autask;
78 unsigned long vaddr;
79 };
80 80
81 struct {
82 struct callback_head dup_xol_work;
83 unsigned long dup_xol_addr;
84 };
85 };
86
87 struct uprobe *active_uprobe;
81 unsigned long xol_vaddr; 88 unsigned long xol_vaddr;
82 unsigned long vaddr;
83};
84 89
85/* 90 struct return_instance *return_instances;
86 * On a breakpoint hit, thread contests for a slot. It frees the 91 unsigned int depth;
87 * slot after singlestep. Currently a fixed number of slots are
88 * allocated.
89 */
90struct xol_area {
91 wait_queue_head_t wq; /* if all slots are busy */
92 atomic_t slot_count; /* number of in-use slots */
93 unsigned long *bitmap; /* 0 = free slot */
94 struct page *page;
95
96 /*
97 * We keep the vma's vm_start rather than a pointer to the vma
98 * itself. The probed process or a naughty kernel module could make
99 * the vma go away, and we must handle that reasonably gracefully.
100 */
101 unsigned long vaddr; /* Page(s) of instruction slots */
102}; 92};
103 93
94struct xol_area;
95
104struct uprobes_state { 96struct uprobes_state {
105 struct xol_area *xol_area; 97 struct xol_area *xol_area;
106}; 98};
@@ -109,6 +101,7 @@ extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsign
109extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); 101extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
110extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); 102extern bool __weak is_swbp_insn(uprobe_opcode_t *insn);
111extern bool __weak is_trap_insn(uprobe_opcode_t *insn); 103extern bool __weak is_trap_insn(uprobe_opcode_t *insn);
104extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs);
112extern int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t); 105extern int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t);
113extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); 106extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
114extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool); 107extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool);
@@ -120,7 +113,6 @@ extern void uprobe_end_dup_mmap(void);
120extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm); 113extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm);
121extern void uprobe_free_utask(struct task_struct *t); 114extern void uprobe_free_utask(struct task_struct *t);
122extern void uprobe_copy_process(struct task_struct *t, unsigned long flags); 115extern void uprobe_copy_process(struct task_struct *t, unsigned long flags);
123extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs);
124extern int uprobe_post_sstep_notifier(struct pt_regs *regs); 116extern int uprobe_post_sstep_notifier(struct pt_regs *regs);
125extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); 117extern int uprobe_pre_sstep_notifier(struct pt_regs *regs);
126extern void uprobe_notify_resume(struct pt_regs *regs); 118extern void uprobe_notify_resume(struct pt_regs *regs);
@@ -176,10 +168,6 @@ static inline bool uprobe_deny_signal(void)
176{ 168{
177 return false; 169 return false;
178} 170}
179static inline unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
180{
181 return 0;
182}
183static inline void uprobe_free_utask(struct task_struct *t) 171static inline void uprobe_free_utask(struct task_struct *t)
184{ 172{
185} 173}
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 959d454f76a1..e244ed412745 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -725,6 +725,7 @@ enum perf_callchain_context {
725#define PERF_FLAG_FD_NO_GROUP (1U << 0) 725#define PERF_FLAG_FD_NO_GROUP (1U << 0)
726#define PERF_FLAG_FD_OUTPUT (1U << 1) 726#define PERF_FLAG_FD_OUTPUT (1U << 1)
727#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */ 727#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */
728#define PERF_FLAG_FD_CLOEXEC (1U << 3) /* O_CLOEXEC */
728 729
729union perf_mem_data_src { 730union perf_mem_data_src {
730 __u64 val; 731 __u64 val;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index f5744010a8d2..56003c6edfd3 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -119,7 +119,8 @@ static int cpu_function_call(int cpu, int (*func) (void *info), void *info)
119 119
120#define PERF_FLAG_ALL (PERF_FLAG_FD_NO_GROUP |\ 120#define PERF_FLAG_ALL (PERF_FLAG_FD_NO_GROUP |\
121 PERF_FLAG_FD_OUTPUT |\ 121 PERF_FLAG_FD_OUTPUT |\
122 PERF_FLAG_PID_CGROUP) 122 PERF_FLAG_PID_CGROUP |\
123 PERF_FLAG_FD_CLOEXEC)
123 124
124/* 125/*
125 * branch priv levels that need permission checks 126 * branch priv levels that need permission checks
@@ -3542,7 +3543,7 @@ static void perf_event_for_each(struct perf_event *event,
3542static int perf_event_period(struct perf_event *event, u64 __user *arg) 3543static int perf_event_period(struct perf_event *event, u64 __user *arg)
3543{ 3544{
3544 struct perf_event_context *ctx = event->ctx; 3545 struct perf_event_context *ctx = event->ctx;
3545 int ret = 0; 3546 int ret = 0, active;
3546 u64 value; 3547 u64 value;
3547 3548
3548 if (!is_sampling_event(event)) 3549 if (!is_sampling_event(event))
@@ -3566,6 +3567,20 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
3566 event->attr.sample_period = value; 3567 event->attr.sample_period = value;
3567 event->hw.sample_period = value; 3568 event->hw.sample_period = value;
3568 } 3569 }
3570
3571 active = (event->state == PERF_EVENT_STATE_ACTIVE);
3572 if (active) {
3573 perf_pmu_disable(ctx->pmu);
3574 event->pmu->stop(event, PERF_EF_UPDATE);
3575 }
3576
3577 local64_set(&event->hw.period_left, 0);
3578
3579 if (active) {
3580 event->pmu->start(event, PERF_EF_RELOAD);
3581 perf_pmu_enable(ctx->pmu);
3582 }
3583
3569unlock: 3584unlock:
3570 raw_spin_unlock_irq(&ctx->lock); 3585 raw_spin_unlock_irq(&ctx->lock);
3571 3586
@@ -6670,6 +6685,9 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
6670 INIT_LIST_HEAD(&event->event_entry); 6685 INIT_LIST_HEAD(&event->event_entry);
6671 INIT_LIST_HEAD(&event->sibling_list); 6686 INIT_LIST_HEAD(&event->sibling_list);
6672 INIT_LIST_HEAD(&event->rb_entry); 6687 INIT_LIST_HEAD(&event->rb_entry);
6688 INIT_LIST_HEAD(&event->active_entry);
6689 INIT_HLIST_NODE(&event->hlist_entry);
6690
6673 6691
6674 init_waitqueue_head(&event->waitq); 6692 init_waitqueue_head(&event->waitq);
6675 init_irq_work(&event->pending, perf_pending_event); 6693 init_irq_work(&event->pending, perf_pending_event);
@@ -6980,6 +6998,7 @@ SYSCALL_DEFINE5(perf_event_open,
6980 int event_fd; 6998 int event_fd;
6981 int move_group = 0; 6999 int move_group = 0;
6982 int err; 7000 int err;
7001 int f_flags = O_RDWR;
6983 7002
6984 /* for future expandability... */ 7003 /* for future expandability... */
6985 if (flags & ~PERF_FLAG_ALL) 7004 if (flags & ~PERF_FLAG_ALL)
@@ -7008,7 +7027,10 @@ SYSCALL_DEFINE5(perf_event_open,
7008 if ((flags & PERF_FLAG_PID_CGROUP) && (pid == -1 || cpu == -1)) 7027 if ((flags & PERF_FLAG_PID_CGROUP) && (pid == -1 || cpu == -1))
7009 return -EINVAL; 7028 return -EINVAL;
7010 7029
7011 event_fd = get_unused_fd(); 7030 if (flags & PERF_FLAG_FD_CLOEXEC)
7031 f_flags |= O_CLOEXEC;
7032
7033 event_fd = get_unused_fd_flags(f_flags);
7012 if (event_fd < 0) 7034 if (event_fd < 0)
7013 return event_fd; 7035 return event_fd;
7014 7036
@@ -7130,7 +7152,8 @@ SYSCALL_DEFINE5(perf_event_open,
7130 goto err_context; 7152 goto err_context;
7131 } 7153 }
7132 7154
7133 event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR); 7155 event_file = anon_inode_getfile("[perf_event]", &perf_fops, event,
7156 f_flags);
7134 if (IS_ERR(event_file)) { 7157 if (IS_ERR(event_file)) {
7135 err = PTR_ERR(event_file); 7158 err = PTR_ERR(event_file);
7136 goto err_context; 7159 goto err_context;
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index e8b168af135b..146a5792b1d2 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -61,19 +61,20 @@ again:
61 * 61 *
62 * kernel user 62 * kernel user
63 * 63 *
64 * READ ->data_tail READ ->data_head 64 * if (LOAD ->data_tail) { LOAD ->data_head
65 * smp_mb() (A) smp_rmb() (C) 65 * (A) smp_rmb() (C)
66 * WRITE $data READ $data 66 * STORE $data LOAD $data
67 * smp_wmb() (B) smp_mb() (D) 67 * smp_wmb() (B) smp_mb() (D)
68 * STORE ->data_head WRITE ->data_tail 68 * STORE ->data_head STORE ->data_tail
69 * }
69 * 70 *
70 * Where A pairs with D, and B pairs with C. 71 * Where A pairs with D, and B pairs with C.
71 * 72 *
72 * I don't think A needs to be a full barrier because we won't in fact 73 * In our case (A) is a control dependency that separates the load of
73 * write data until we see the store from userspace. So we simply don't 74 * the ->data_tail and the stores of $data. In case ->data_tail
74 * issue the data WRITE until we observe it. Be conservative for now. 75 * indicates there is no room in the buffer to store $data we do not.
75 * 76 *
76 * OTOH, D needs to be a full barrier since it separates the data READ 77 * D needs to be a full barrier since it separates the data READ
77 * from the tail WRITE. 78 * from the tail WRITE.
78 * 79 *
79 * For B a WMB is sufficient since it separates two WRITEs, and for C 80 * For B a WMB is sufficient since it separates two WRITEs, and for C
@@ -81,7 +82,7 @@ again:
81 * 82 *
82 * See perf_output_begin(). 83 * See perf_output_begin().
83 */ 84 */
84 smp_wmb(); 85 smp_wmb(); /* B, matches C */
85 rb->user_page->data_head = head; 86 rb->user_page->data_head = head;
86 87
87 /* 88 /*
@@ -144,17 +145,26 @@ int perf_output_begin(struct perf_output_handle *handle,
144 if (!rb->overwrite && 145 if (!rb->overwrite &&
145 unlikely(CIRC_SPACE(head, tail, perf_data_size(rb)) < size)) 146 unlikely(CIRC_SPACE(head, tail, perf_data_size(rb)) < size))
146 goto fail; 147 goto fail;
148
149 /*
150 * The above forms a control dependency barrier separating the
151 * @tail load above from the data stores below. Since the @tail
152 * load is required to compute the branch to fail below.
153 *
154 * A, matches D; the full memory barrier userspace SHOULD issue
155 * after reading the data and before storing the new tail
156 * position.
157 *
158 * See perf_output_put_handle().
159 */
160
147 head += size; 161 head += size;
148 } while (local_cmpxchg(&rb->head, offset, head) != offset); 162 } while (local_cmpxchg(&rb->head, offset, head) != offset);
149 163
150 /* 164 /*
151 * Separate the userpage->tail read from the data stores below. 165 * We rely on the implied barrier() by local_cmpxchg() to ensure
152 * Matches the MB userspace SHOULD issue after reading the data 166 * none of the data stores below can be lifted up by the compiler.
153 * and before storing the new tail position.
154 *
155 * See perf_output_put_handle().
156 */ 167 */
157 smp_mb();
158 168
159 if (unlikely(head - local_read(&rb->wakeup) > rb->watermark)) 169 if (unlikely(head - local_read(&rb->wakeup) > rb->watermark))
160 local_add(rb->watermark, &rb->wakeup); 170 local_add(rb->watermark, &rb->wakeup);
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 24b7d6ca871b..b886a5e7d4ff 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -73,6 +73,17 @@ struct uprobe {
73 struct inode *inode; /* Also hold a ref to inode */ 73 struct inode *inode; /* Also hold a ref to inode */
74 loff_t offset; 74 loff_t offset;
75 unsigned long flags; 75 unsigned long flags;
76
77 /*
78 * The generic code assumes that it has two members of unknown type
79 * owned by the arch-specific code:
80 *
81 * insn - copy_insn() saves the original instruction here for
82 * arch_uprobe_analyze_insn().
83 *
84 * ixol - potentially modified instruction to execute out of
85 * line, copied to xol_area by xol_get_insn_slot().
86 */
76 struct arch_uprobe arch; 87 struct arch_uprobe arch;
77}; 88};
78 89
@@ -86,6 +97,29 @@ struct return_instance {
86}; 97};
87 98
88/* 99/*
100 * Execute out of line area: anonymous executable mapping installed
101 * by the probed task to execute the copy of the original instruction
102 * mangled by set_swbp().
103 *
104 * On a breakpoint hit, thread contests for a slot. It frees the
105 * slot after singlestep. Currently a fixed number of slots are
106 * allocated.
107 */
108struct xol_area {
109 wait_queue_head_t wq; /* if all slots are busy */
110 atomic_t slot_count; /* number of in-use slots */
111 unsigned long *bitmap; /* 0 = free slot */
112 struct page *page;
113
114 /*
115 * We keep the vma's vm_start rather than a pointer to the vma
116 * itself. The probed process or a naughty kernel module could make
117 * the vma go away, and we must handle that reasonably gracefully.
118 */
119 unsigned long vaddr; /* Page(s) of instruction slots */
120};
121
122/*
89 * valid_vma: Verify if the specified vma is an executable vma 123 * valid_vma: Verify if the specified vma is an executable vma
90 * Relax restrictions while unregistering: vm_flags might have 124 * Relax restrictions while unregistering: vm_flags might have
91 * changed after breakpoint was inserted. 125 * changed after breakpoint was inserted.
@@ -330,7 +364,7 @@ int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned
330int __weak 364int __weak
331set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) 365set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
332{ 366{
333 return uprobe_write_opcode(mm, vaddr, *(uprobe_opcode_t *)auprobe->insn); 367 return uprobe_write_opcode(mm, vaddr, *(uprobe_opcode_t *)&auprobe->insn);
334} 368}
335 369
336static int match_uprobe(struct uprobe *l, struct uprobe *r) 370static int match_uprobe(struct uprobe *l, struct uprobe *r)
@@ -529,8 +563,8 @@ static int copy_insn(struct uprobe *uprobe, struct file *filp)
529{ 563{
530 struct address_space *mapping = uprobe->inode->i_mapping; 564 struct address_space *mapping = uprobe->inode->i_mapping;
531 loff_t offs = uprobe->offset; 565 loff_t offs = uprobe->offset;
532 void *insn = uprobe->arch.insn; 566 void *insn = &uprobe->arch.insn;
533 int size = MAX_UINSN_BYTES; 567 int size = sizeof(uprobe->arch.insn);
534 int len, err = -EIO; 568 int len, err = -EIO;
535 569
536 /* Copy only available bytes, -EIO if nothing was read */ 570 /* Copy only available bytes, -EIO if nothing was read */
@@ -569,7 +603,7 @@ static int prepare_uprobe(struct uprobe *uprobe, struct file *file,
569 goto out; 603 goto out;
570 604
571 ret = -ENOTSUPP; 605 ret = -ENOTSUPP;
572 if (is_trap_insn((uprobe_opcode_t *)uprobe->arch.insn)) 606 if (is_trap_insn((uprobe_opcode_t *)&uprobe->arch.insn))
573 goto out; 607 goto out;
574 608
575 ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr); 609 ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr);
@@ -1264,7 +1298,7 @@ static unsigned long xol_get_insn_slot(struct uprobe *uprobe)
1264 1298
1265 /* Initialize the slot */ 1299 /* Initialize the slot */
1266 copy_to_page(area->page, xol_vaddr, 1300 copy_to_page(area->page, xol_vaddr,
1267 uprobe->arch.ixol, sizeof(uprobe->arch.ixol)); 1301 &uprobe->arch.ixol, sizeof(uprobe->arch.ixol));
1268 /* 1302 /*
1269 * We probably need flush_icache_user_range() but it needs vma. 1303 * We probably need flush_icache_user_range() but it needs vma.
1270 * This should work on supported architectures too. 1304 * This should work on supported architectures too.
@@ -1403,12 +1437,10 @@ static void uprobe_warn(struct task_struct *t, const char *msg)
1403 1437
1404static void dup_xol_work(struct callback_head *work) 1438static void dup_xol_work(struct callback_head *work)
1405{ 1439{
1406 kfree(work);
1407
1408 if (current->flags & PF_EXITING) 1440 if (current->flags & PF_EXITING)
1409 return; 1441 return;
1410 1442
1411 if (!__create_xol_area(current->utask->vaddr)) 1443 if (!__create_xol_area(current->utask->dup_xol_addr))
1412 uprobe_warn(current, "dup xol area"); 1444 uprobe_warn(current, "dup xol area");
1413} 1445}
1414 1446
@@ -1419,7 +1451,6 @@ void uprobe_copy_process(struct task_struct *t, unsigned long flags)
1419{ 1451{
1420 struct uprobe_task *utask = current->utask; 1452 struct uprobe_task *utask = current->utask;
1421 struct mm_struct *mm = current->mm; 1453 struct mm_struct *mm = current->mm;
1422 struct callback_head *work;
1423 struct xol_area *area; 1454 struct xol_area *area;
1424 1455
1425 t->utask = NULL; 1456 t->utask = NULL;
@@ -1441,14 +1472,9 @@ void uprobe_copy_process(struct task_struct *t, unsigned long flags)
1441 if (mm == t->mm) 1472 if (mm == t->mm)
1442 return; 1473 return;
1443 1474
1444 /* TODO: move it into the union in uprobe_task */ 1475 t->utask->dup_xol_addr = area->vaddr;
1445 work = kmalloc(sizeof(*work), GFP_KERNEL); 1476 init_task_work(&t->utask->dup_xol_work, dup_xol_work);
1446 if (!work) 1477 task_work_add(t, &t->utask->dup_xol_work, true);
1447 return uprobe_warn(t, "dup xol area");
1448
1449 t->utask->vaddr = area->vaddr;
1450 init_task_work(work, dup_xol_work);
1451 task_work_add(t, work, true);
1452} 1478}
1453 1479
1454/* 1480/*
diff --git a/tools/Makefile b/tools/Makefile
index a9b02008443c..927cd46d36dc 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -39,10 +39,10 @@ cpupower: FORCE
39cgroup firewire guest usb virtio vm net: FORCE 39cgroup firewire guest usb virtio vm net: FORCE
40 $(call descend,$@) 40 $(call descend,$@)
41 41
42liblk: FORCE 42libapikfs: FORCE
43 $(call descend,lib/lk) 43 $(call descend,lib/api)
44 44
45perf: liblk FORCE 45perf: libapikfs FORCE
46 $(call descend,$@) 46 $(call descend,$@)
47 47
48selftests: FORCE 48selftests: FORCE
@@ -80,10 +80,10 @@ cpupower_clean:
80cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean: 80cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean:
81 $(call descend,$(@:_clean=),clean) 81 $(call descend,$(@:_clean=),clean)
82 82
83liblk_clean: 83libapikfs_clean:
84 $(call descend,lib/lk,clean) 84 $(call descend,lib/api,clean)
85 85
86perf_clean: liblk_clean 86perf_clean: libapikfs_clean
87 $(call descend,$(@:_clean=),clean) 87 $(call descend,$(@:_clean=),clean)
88 88
89selftests_clean: 89selftests_clean:
diff --git a/tools/perf/util/include/asm/bug.h b/tools/include/asm/bug.h
index 7fcc6810adc2..9e5f4846967f 100644
--- a/tools/perf/util/include/asm/bug.h
+++ b/tools/include/asm/bug.h
@@ -1,5 +1,7 @@
1#ifndef _PERF_ASM_GENERIC_BUG_H 1#ifndef _TOOLS_ASM_BUG_H
2#define _PERF_ASM_GENERIC_BUG_H 2#define _TOOLS_ASM_BUG_H
3
4#include <linux/compiler.h>
3 5
4#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0) 6#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0)
5 7
@@ -19,4 +21,5 @@
19 __warned = 1; \ 21 __warned = 1; \
20 unlikely(__ret_warn_once); \ 22 unlikely(__ret_warn_once); \
21}) 23})
22#endif 24
25#endif /* _TOOLS_ASM_BUG_H */
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/include/linux/compiler.h
index b003ad7200b2..fbc6665c6d53 100644
--- a/tools/perf/util/include/linux/compiler.h
+++ b/tools/include/linux/compiler.h
@@ -1,5 +1,5 @@
1#ifndef _PERF_LINUX_COMPILER_H_ 1#ifndef _TOOLS_LINUX_COMPILER_H_
2#define _PERF_LINUX_COMPILER_H_ 2#define _TOOLS_LINUX_COMPILER_H_
3 3
4#ifndef __always_inline 4#ifndef __always_inline
5# define __always_inline inline __attribute__((always_inline)) 5# define __always_inline inline __attribute__((always_inline))
@@ -27,4 +27,12 @@
27# define __weak __attribute__((weak)) 27# define __weak __attribute__((weak))
28#endif 28#endif
29 29
30#ifndef likely
31# define likely(x) __builtin_expect(!!(x), 1)
30#endif 32#endif
33
34#ifndef unlikely
35# define unlikely(x) __builtin_expect(!!(x), 0)
36#endif
37
38#endif /* _TOOLS_LINUX_COMPILER_H */
diff --git a/tools/lib/lk/Makefile b/tools/lib/api/Makefile
index 3dba0a4aebbf..ed2f51e11b80 100644
--- a/tools/lib/lk/Makefile
+++ b/tools/lib/api/Makefile
@@ -1,4 +1,5 @@
1include ../../scripts/Makefile.include 1include ../../scripts/Makefile.include
2include ../../perf/config/utilities.mak # QUIET_CLEAN
2 3
3CC = $(CROSS_COMPILE)gcc 4CC = $(CROSS_COMPILE)gcc
4AR = $(CROSS_COMPILE)ar 5AR = $(CROSS_COMPILE)ar
@@ -7,11 +8,11 @@ AR = $(CROSS_COMPILE)ar
7LIB_H= 8LIB_H=
8LIB_OBJS= 9LIB_OBJS=
9 10
10LIB_H += debugfs.h 11LIB_H += fs/debugfs.h
11 12
12LIB_OBJS += $(OUTPUT)debugfs.o 13LIB_OBJS += $(OUTPUT)fs/debugfs.o
13 14
14LIBFILE = liblk.a 15LIBFILE = libapikfs.a
15 16
16CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC 17CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC
17EXTLIBS = -lelf -lpthread -lrt -lm 18EXTLIBS = -lelf -lpthread -lrt -lm
@@ -25,14 +26,17 @@ $(LIBFILE): $(LIB_OBJS)
25 26
26$(LIB_OBJS): $(LIB_H) 27$(LIB_OBJS): $(LIB_H)
27 28
28$(OUTPUT)%.o: %.c 29libapi_dirs:
30 $(QUIET_MKDIR)mkdir -p $(OUTPUT)fs/
31
32$(OUTPUT)%.o: %.c libapi_dirs
29 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 33 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
30$(OUTPUT)%.s: %.c 34$(OUTPUT)%.s: %.c libapi_dirs
31 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< 35 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
32$(OUTPUT)%.o: %.S 36$(OUTPUT)%.o: %.S libapi_dirs
33 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< 37 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
34 38
35clean: 39clean:
36 $(RM) $(LIB_OBJS) $(LIBFILE) 40 $(call QUIET_CLEAN, libapi) $(RM) $(LIB_OBJS) $(LIBFILE)
37 41
38.PHONY: clean 42.PHONY: clean
diff --git a/tools/lib/lk/debugfs.c b/tools/lib/api/fs/debugfs.c
index 7c4347962353..7c4347962353 100644
--- a/tools/lib/lk/debugfs.c
+++ b/tools/lib/api/fs/debugfs.c
diff --git a/tools/lib/lk/debugfs.h b/tools/lib/api/fs/debugfs.h
index 935c59bdb442..f19d3df9609d 100644
--- a/tools/lib/lk/debugfs.h
+++ b/tools/lib/api/fs/debugfs.h
@@ -1,5 +1,5 @@
1#ifndef __LK_DEBUGFS_H__ 1#ifndef __API_DEBUGFS_H__
2#define __LK_DEBUGFS_H__ 2#define __API_DEBUGFS_H__
3 3
4#define _STR(x) #x 4#define _STR(x) #x
5#define STR(x) _STR(x) 5#define STR(x) _STR(x)
@@ -26,4 +26,4 @@ char *debugfs_mount(const char *mountpoint);
26 26
27extern char debugfs_mountpoint[]; 27extern char debugfs_mountpoint[];
28 28
29#endif /* __LK_DEBUGFS_H__ */ 29#endif /* __API_DEBUGFS_H__ */
diff --git a/tools/lib/symbol/kallsyms.c b/tools/lib/symbol/kallsyms.c
new file mode 100644
index 000000000000..18bc271a4bbc
--- /dev/null
+++ b/tools/lib/symbol/kallsyms.c
@@ -0,0 +1,58 @@
1#include "symbol/kallsyms.h"
2#include <stdio.h>
3#include <stdlib.h>
4
5int kallsyms__parse(const char *filename, void *arg,
6 int (*process_symbol)(void *arg, const char *name,
7 char type, u64 start))
8{
9 char *line = NULL;
10 size_t n;
11 int err = -1;
12 FILE *file = fopen(filename, "r");
13
14 if (file == NULL)
15 goto out_failure;
16
17 err = 0;
18
19 while (!feof(file)) {
20 u64 start;
21 int line_len, len;
22 char symbol_type;
23 char *symbol_name;
24
25 line_len = getline(&line, &n, file);
26 if (line_len < 0 || !line)
27 break;
28
29 line[--line_len] = '\0'; /* \n */
30
31 len = hex2u64(line, &start);
32
33 len++;
34 if (len + 2 >= line_len)
35 continue;
36
37 symbol_type = line[len];
38 len += 2;
39 symbol_name = line + len;
40 len = line_len - len;
41
42 if (len >= KSYM_NAME_LEN) {
43 err = -1;
44 break;
45 }
46
47 err = process_symbol(arg, symbol_name, symbol_type, start);
48 if (err)
49 break;
50 }
51
52 free(line);
53 fclose(file);
54 return err;
55
56out_failure:
57 return -1;
58}
diff --git a/tools/lib/symbol/kallsyms.h b/tools/lib/symbol/kallsyms.h
new file mode 100644
index 000000000000..6084f5e18b3c
--- /dev/null
+++ b/tools/lib/symbol/kallsyms.h
@@ -0,0 +1,24 @@
1#ifndef __TOOLS_KALLSYMS_H_
2#define __TOOLS_KALLSYMS_H_ 1
3
4#include <elf.h>
5#include <linux/ctype.h>
6#include <linux/types.h>
7
8#ifndef KSYM_NAME_LEN
9#define KSYM_NAME_LEN 256
10#endif
11
12static inline u8 kallsyms2elf_type(char type)
13{
14 if (type == 'W')
15 return STB_WEAK;
16
17 return isupper(type) ? STB_GLOBAL : STB_LOCAL;
18}
19
20int kallsyms__parse(const char *filename, void *arg,
21 int (*process_symbol)(void *arg, const char *name,
22 char type, u64 start));
23
24#endif /* __TOOLS_KALLSYMS_H_ */
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
index fc1502098595..56d52a33a3df 100644
--- a/tools/lib/traceevent/Makefile
+++ b/tools/lib/traceevent/Makefile
@@ -43,6 +43,32 @@ man_dir_SQ = '$(subst ','\'',$(man_dir))'
43export man_dir man_dir_SQ INSTALL 43export man_dir man_dir_SQ INSTALL
44export DESTDIR DESTDIR_SQ 44export DESTDIR DESTDIR_SQ
45 45
46set_plugin_dir := 1
47
48# Set plugin_dir to preffered global plugin location
49# If we install under $HOME directory we go under
50# $(HOME)/.traceevent/plugins
51#
52# We dont set PLUGIN_DIR in case we install under $HOME
53# directory, because by default the code looks under:
54# $(HOME)/.traceevent/plugins by default.
55#
56ifeq ($(plugin_dir),)
57ifeq ($(prefix),$(HOME))
58override plugin_dir = $(HOME)/.traceevent/plugins
59set_plugin_dir := 0
60else
61override plugin_dir = $(prefix)/lib/traceevent/plugins
62endif
63endif
64
65ifeq ($(set_plugin_dir),1)
66PLUGIN_DIR = -DPLUGIN_DIR="$(DESTDIR)/$(plugin_dir)"
67PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))'
68endif
69
70include $(if $(BUILD_SRC),$(BUILD_SRC)/)../../scripts/Makefile.include
71
46# copy a bit from Linux kbuild 72# copy a bit from Linux kbuild
47 73
48ifeq ("$(origin V)", "command line") 74ifeq ("$(origin V)", "command line")
@@ -57,18 +83,13 @@ ifeq ("$(origin O)", "command line")
57endif 83endif
58 84
59ifeq ($(BUILD_SRC),) 85ifeq ($(BUILD_SRC),)
60ifneq ($(BUILD_OUTPUT),) 86ifneq ($(OUTPUT),)
61 87
62define build_output 88define build_output
63 $(if $(VERBOSE:1=),@)+$(MAKE) -C $(BUILD_OUTPUT) \ 89 $(if $(VERBOSE:1=),@)+$(MAKE) -C $(OUTPUT) \
64 BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1 90 BUILD_SRC=$(CURDIR)/ -f $(CURDIR)/Makefile $1
65endef 91endef
66 92
67saved-output := $(BUILD_OUTPUT)
68BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd)
69$(if $(BUILD_OUTPUT),, \
70 $(error output directory "$(saved-output)" does not exist))
71
72all: sub-make 93all: sub-make
73 94
74$(MAKECMDGOALS): sub-make 95$(MAKECMDGOALS): sub-make
@@ -80,7 +101,7 @@ sub-make: force
80# Leave processing to above invocation of make 101# Leave processing to above invocation of make
81skip-makefile := 1 102skip-makefile := 1
82 103
83endif # BUILD_OUTPUT 104endif # OUTPUT
84endif # BUILD_SRC 105endif # BUILD_SRC
85 106
86# We process the rest of the Makefile if this is the final invocation of make 107# We process the rest of the Makefile if this is the final invocation of make
@@ -96,6 +117,7 @@ export prefix bindir src obj
96# Shell quotes 117# Shell quotes
97bindir_SQ = $(subst ','\'',$(bindir)) 118bindir_SQ = $(subst ','\'',$(bindir))
98bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) 119bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
120plugin_dir_SQ = $(subst ','\'',$(plugin_dir))
99 121
100LIB_FILE = libtraceevent.a libtraceevent.so 122LIB_FILE = libtraceevent.a libtraceevent.so
101 123
@@ -114,7 +136,7 @@ export Q VERBOSE
114 136
115EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION) 137EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION)
116 138
117INCLUDES = -I. $(CONFIG_INCLUDES) 139INCLUDES = -I. -I $(srctree)/../../include $(CONFIG_INCLUDES)
118 140
119# Set compile option CFLAGS if not set elsewhere 141# Set compile option CFLAGS if not set elsewhere
120CFLAGS ?= -g -Wall 142CFLAGS ?= -g -Wall
@@ -125,41 +147,14 @@ override CFLAGS += $(udis86-flags) -D_GNU_SOURCE
125 147
126ifeq ($(VERBOSE),1) 148ifeq ($(VERBOSE),1)
127 Q = 149 Q =
128 print_compile =
129 print_app_build =
130 print_fpic_compile =
131 print_shared_lib_compile =
132 print_plugin_obj_compile =
133 print_plugin_build =
134 print_install =
135else 150else
136 Q = @ 151 Q = @
137 print_compile = echo ' CC '$(OBJ);
138 print_app_build = echo ' BUILD '$(OBJ);
139 print_fpic_compile = echo ' CC FPIC '$(OBJ);
140 print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ);
141 print_plugin_obj_compile = echo ' BUILD PLUGIN OBJ '$(OBJ);
142 print_plugin_build = echo ' BUILD PLUGIN '$(OBJ);
143 print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ);
144 print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2';
145endif 152endif
146 153
147do_fpic_compile = \
148 ($(print_fpic_compile) \
149 $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@)
150
151do_app_build = \
152 ($(print_app_build) \
153 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS))
154
155do_compile_shared_library = \ 154do_compile_shared_library = \
156 ($(print_shared_lib_compile) \ 155 ($(print_shared_lib_compile) \
157 $(CC) --shared $^ -o $@) 156 $(CC) --shared $^ -o $@)
158 157
159do_compile_plugin_obj = \
160 ($(print_plugin_obj_compile) \
161 $(CC) -c $(CFLAGS) -fPIC -o $@ $<)
162
163do_plugin_build = \ 158do_plugin_build = \
164 ($(print_plugin_build) \ 159 ($(print_plugin_build) \
165 $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<) 160 $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<)
@@ -169,23 +164,37 @@ do_build_static_lib = \
169 $(RM) $@; $(AR) rcs $@ $^) 164 $(RM) $@; $(AR) rcs $@ $^)
170 165
171 166
172define do_compile 167do_compile = $(QUIET_CC)$(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
173 $(print_compile) \
174 $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
175endef
176 168
177$(obj)/%.o: $(src)/%.c 169$(obj)/%.o: $(src)/%.c
178 $(Q)$(call do_compile) 170 $(call do_compile)
179 171
180%.o: $(src)/%.c 172%.o: $(src)/%.c
181 $(Q)$(call do_compile) 173 $(call do_compile)
182 174
183PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o 175PEVENT_LIB_OBJS = event-parse.o
176PEVENT_LIB_OBJS += event-plugin.o
177PEVENT_LIB_OBJS += trace-seq.o
178PEVENT_LIB_OBJS += parse-filter.o
179PEVENT_LIB_OBJS += parse-utils.o
184PEVENT_LIB_OBJS += kbuffer-parse.o 180PEVENT_LIB_OBJS += kbuffer-parse.o
185 181
186ALL_OBJS = $(PEVENT_LIB_OBJS) 182PLUGIN_OBJS = plugin_jbd2.o
183PLUGIN_OBJS += plugin_hrtimer.o
184PLUGIN_OBJS += plugin_kmem.o
185PLUGIN_OBJS += plugin_kvm.o
186PLUGIN_OBJS += plugin_mac80211.o
187PLUGIN_OBJS += plugin_sched_switch.o
188PLUGIN_OBJS += plugin_function.o
189PLUGIN_OBJS += plugin_xen.o
190PLUGIN_OBJS += plugin_scsi.o
191PLUGIN_OBJS += plugin_cfg80211.o
192
193PLUGINS := $(PLUGIN_OBJS:.o=.so)
194
195ALL_OBJS = $(PEVENT_LIB_OBJS) $(PLUGIN_OBJS)
187 196
188CMD_TARGETS = $(LIB_FILE) 197CMD_TARGETS = $(LIB_FILE) $(PLUGINS)
189 198
190TARGETS = $(CMD_TARGETS) 199TARGETS = $(CMD_TARGETS)
191 200
@@ -195,32 +204,40 @@ all: all_cmd
195all_cmd: $(CMD_TARGETS) 204all_cmd: $(CMD_TARGETS)
196 205
197libtraceevent.so: $(PEVENT_LIB_OBJS) 206libtraceevent.so: $(PEVENT_LIB_OBJS)
198 $(Q)$(do_compile_shared_library) 207 $(QUIET_LINK)$(CC) --shared $^ -o $@
199 208
200libtraceevent.a: $(PEVENT_LIB_OBJS) 209libtraceevent.a: $(PEVENT_LIB_OBJS)
201 $(Q)$(do_build_static_lib) 210 $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^
211
212plugins: $(PLUGINS)
202 213
203$(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS 214$(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS
204 $(Q)$(do_fpic_compile) 215 $(QUIET_CC_FPIC)$(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@
216
217$(PLUGIN_OBJS): %.o : $(src)/%.c
218 $(QUIET_CC_FPIC)$(CC) -c $(CFLAGS) -fPIC -o $@ $<
219
220$(PLUGINS): %.so: %.o
221 $(QUIET_LINK)$(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<
205 222
206define make_version.h 223define make_version.h
207 (echo '/* This file is automatically generated. Do not modify. */'; \ 224 (echo '/* This file is automatically generated. Do not modify. */'; \
208 echo \#define VERSION_CODE $(shell \ 225 echo \#define VERSION_CODE $(shell \
209 expr $(VERSION) \* 256 + $(PATCHLEVEL)); \ 226 expr $(VERSION) \* 256 + $(PATCHLEVEL)); \
210 echo '#define EXTRAVERSION ' $(EXTRAVERSION); \ 227 echo '#define EXTRAVERSION ' $(EXTRAVERSION); \
211 echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \ 228 echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \
212 echo '#define FILE_VERSION '$(FILE_VERSION); \ 229 echo '#define FILE_VERSION '$(FILE_VERSION); \
213 ) > $1 230 ) > $1
214endef 231endef
215 232
216define update_version.h 233define update_version.h
217 ($(call make_version.h, $@.tmp); \ 234 ($(call make_version.h, $@.tmp); \
218 if [ -r $@ ] && cmp -s $@ $@.tmp; then \ 235 if [ -r $@ ] && cmp -s $@ $@.tmp; then \
219 rm -f $@.tmp; \ 236 rm -f $@.tmp; \
220 else \ 237 else \
221 echo ' UPDATE $@'; \ 238 echo ' UPDATE $@'; \
222 mv -f $@.tmp $@; \ 239 mv -f $@.tmp $@; \
223 fi); 240 fi);
224endef 241endef
225 242
226ep_version.h: force 243ep_version.h: force
@@ -229,13 +246,13 @@ ep_version.h: force
229VERSION_FILES = ep_version.h 246VERSION_FILES = ep_version.h
230 247
231define update_dir 248define update_dir
232 (echo $1 > $@.tmp; \ 249 (echo $1 > $@.tmp; \
233 if [ -r $@ ] && cmp -s $@ $@.tmp; then \ 250 if [ -r $@ ] && cmp -s $@ $@.tmp; then \
234 rm -f $@.tmp; \ 251 rm -f $@.tmp; \
235 else \ 252 else \
236 echo ' UPDATE $@'; \ 253 echo ' UPDATE $@'; \
237 mv -f $@.tmp $@; \ 254 mv -f $@.tmp $@; \
238 fi); 255 fi);
239endef 256endef
240 257
241## make deps 258## make deps
@@ -245,10 +262,10 @@ all_deps := $(all_objs:%.o=.%.d)
245 262
246# let .d file also depends on the source and header files 263# let .d file also depends on the source and header files
247define check_deps 264define check_deps
248 @set -e; $(RM) $@; \ 265 @set -e; $(RM) $@; \
249 $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ 266 $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
250 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ 267 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
251 $(RM) $@.$$$$ 268 $(RM) $@.$$$$
252endef 269endef
253 270
254$(all_deps): .%.d: $(src)/%.c 271$(all_deps): .%.d: $(src)/%.c
@@ -283,27 +300,41 @@ TAGS: force
283 --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' 300 --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'
284 301
285define do_install 302define do_install
286 $(print_install) \
287 if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ 303 if [ ! -d '$(DESTDIR_SQ)$2' ]; then \
288 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ 304 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
289 fi; \ 305 fi; \
290 $(INSTALL) $1 '$(DESTDIR_SQ)$2' 306 $(INSTALL) $1 '$(DESTDIR_SQ)$2'
291endef 307endef
292 308
293install_lib: all_cmd 309define do_install_plugins
294 $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) 310 for plugin in $1; do \
311 $(call do_install,$$plugin,$(plugin_dir_SQ)); \
312 done
313endef
314
315install_lib: all_cmd install_plugins
316 $(call QUIET_INSTALL, $(LIB_FILE)) \
317 $(call do_install,$(LIB_FILE),$(bindir_SQ))
318
319install_plugins: $(PLUGINS)
320 $(call QUIET_INSTALL, trace_plugins) \
321 $(call do_install_plugins, $(PLUGINS))
295 322
296install: install_lib 323install: install_lib
297 324
298clean: 325clean:
299 $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d 326 $(call QUIET_CLEAN, libtraceevent) \
300 $(RM) TRACEEVENT-CFLAGS tags TAGS 327 $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \
328 $(RM) TRACEEVENT-CFLAGS tags TAGS
301 329
302endif # skip-makefile 330endif # skip-makefile
303 331
304PHONY += force 332PHONY += force plugins
305force: 333force:
306 334
335plugins:
336 @echo > /dev/null
337
307# Declare the contents of the .PHONY variable as phony. We keep that 338# Declare the contents of the .PHONY variable as phony. We keep that
308# information in a variable so we can use it in if_changed and friends. 339# information in a variable so we can use it in if_changed and friends.
309.PHONY: $(PHONY) 340.PHONY: $(PHONY)
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index 217c82ee3665..1587ea392ad6 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -2710,7 +2710,6 @@ process_func_handler(struct event_format *event, struct pevent_function_handler
2710 struct print_arg *farg; 2710 struct print_arg *farg;
2711 enum event_type type; 2711 enum event_type type;
2712 char *token; 2712 char *token;
2713 const char *test;
2714 int i; 2713 int i;
2715 2714
2716 arg->type = PRINT_FUNC; 2715 arg->type = PRINT_FUNC;
@@ -2727,15 +2726,19 @@ process_func_handler(struct event_format *event, struct pevent_function_handler
2727 } 2726 }
2728 2727
2729 type = process_arg(event, farg, &token); 2728 type = process_arg(event, farg, &token);
2730 if (i < (func->nr_args - 1)) 2729 if (i < (func->nr_args - 1)) {
2731 test = ","; 2730 if (type != EVENT_DELIM || strcmp(token, ",") != 0) {
2732 else 2731 warning("Error: function '%s()' expects %d arguments but event %s only uses %d",
2733 test = ")"; 2732 func->name, func->nr_args,
2734 2733 event->name, i + 1);
2735 if (test_type_token(type, token, EVENT_DELIM, test)) { 2734 goto err;
2736 free_arg(farg); 2735 }
2737 free_token(token); 2736 } else {
2738 return EVENT_ERROR; 2737 if (type != EVENT_DELIM || strcmp(token, ")") != 0) {
2738 warning("Error: function '%s()' only expects %d arguments but event %s has more",
2739 func->name, func->nr_args, event->name);
2740 goto err;
2741 }
2739 } 2742 }
2740 2743
2741 *next_arg = farg; 2744 *next_arg = farg;
@@ -2747,6 +2750,11 @@ process_func_handler(struct event_format *event, struct pevent_function_handler
2747 *tok = token; 2750 *tok = token;
2748 2751
2749 return type; 2752 return type;
2753
2754err:
2755 free_arg(farg);
2756 free_token(token);
2757 return EVENT_ERROR;
2750} 2758}
2751 2759
2752static enum event_type 2760static enum event_type
@@ -4099,6 +4107,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
4099 unsigned long long val; 4107 unsigned long long val;
4100 struct func_map *func; 4108 struct func_map *func;
4101 const char *saveptr; 4109 const char *saveptr;
4110 struct trace_seq p;
4102 char *bprint_fmt = NULL; 4111 char *bprint_fmt = NULL;
4103 char format[32]; 4112 char format[32];
4104 int show_func; 4113 int show_func;
@@ -4306,8 +4315,12 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
4306 format[len] = 0; 4315 format[len] = 0;
4307 if (!len_as_arg) 4316 if (!len_as_arg)
4308 len_arg = -1; 4317 len_arg = -1;
4309 print_str_arg(s, data, size, event, 4318 /* Use helper trace_seq */
4319 trace_seq_init(&p);
4320 print_str_arg(&p, data, size, event,
4310 format, len_arg, arg); 4321 format, len_arg, arg);
4322 trace_seq_terminate(&p);
4323 trace_seq_puts(s, p.buffer);
4311 arg = arg->next; 4324 arg = arg->next;
4312 break; 4325 break;
4313 default: 4326 default:
@@ -5116,8 +5129,38 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp,
5116 return ret; 5129 return ret;
5117} 5130}
5118 5131
5132static enum pevent_errno
5133__pevent_parse_event(struct pevent *pevent,
5134 struct event_format **eventp,
5135 const char *buf, unsigned long size,
5136 const char *sys)
5137{
5138 int ret = __pevent_parse_format(eventp, pevent, buf, size, sys);
5139 struct event_format *event = *eventp;
5140
5141 if (event == NULL)
5142 return ret;
5143
5144 if (pevent && add_event(pevent, event)) {
5145 ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
5146 goto event_add_failed;
5147 }
5148
5149#define PRINT_ARGS 0
5150 if (PRINT_ARGS && event->print_fmt.args)
5151 print_args(event->print_fmt.args);
5152
5153 return 0;
5154
5155event_add_failed:
5156 pevent_free_format(event);
5157 return ret;
5158}
5159
5119/** 5160/**
5120 * pevent_parse_format - parse the event format 5161 * pevent_parse_format - parse the event format
5162 * @pevent: the handle to the pevent
5163 * @eventp: returned format
5121 * @buf: the buffer storing the event format string 5164 * @buf: the buffer storing the event format string
5122 * @size: the size of @buf 5165 * @size: the size of @buf
5123 * @sys: the system the event belongs to 5166 * @sys: the system the event belongs to
@@ -5129,10 +5172,12 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp,
5129 * 5172 *
5130 * /sys/kernel/debug/tracing/events/.../.../format 5173 * /sys/kernel/debug/tracing/events/.../.../format
5131 */ 5174 */
5132enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, 5175enum pevent_errno pevent_parse_format(struct pevent *pevent,
5176 struct event_format **eventp,
5177 const char *buf,
5133 unsigned long size, const char *sys) 5178 unsigned long size, const char *sys)
5134{ 5179{
5135 return __pevent_parse_format(eventp, NULL, buf, size, sys); 5180 return __pevent_parse_event(pevent, eventp, buf, size, sys);
5136} 5181}
5137 5182
5138/** 5183/**
@@ -5153,25 +5198,7 @@ enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
5153 unsigned long size, const char *sys) 5198 unsigned long size, const char *sys)
5154{ 5199{
5155 struct event_format *event = NULL; 5200 struct event_format *event = NULL;
5156 int ret = __pevent_parse_format(&event, pevent, buf, size, sys); 5201 return __pevent_parse_event(pevent, &event, buf, size, sys);
5157
5158 if (event == NULL)
5159 return ret;
5160
5161 if (add_event(pevent, event)) {
5162 ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
5163 goto event_add_failed;
5164 }
5165
5166#define PRINT_ARGS 0
5167 if (PRINT_ARGS && event->print_fmt.args)
5168 print_args(event->print_fmt.args);
5169
5170 return 0;
5171
5172event_add_failed:
5173 pevent_free_format(event);
5174 return ret;
5175} 5202}
5176 5203
5177#undef _PE 5204#undef _PE
@@ -5203,22 +5230,7 @@ int pevent_strerror(struct pevent *pevent __maybe_unused,
5203 5230
5204 idx = errnum - __PEVENT_ERRNO__START - 1; 5231 idx = errnum - __PEVENT_ERRNO__START - 1;
5205 msg = pevent_error_str[idx]; 5232 msg = pevent_error_str[idx];
5206 5233 snprintf(buf, buflen, "%s", msg);
5207 switch (errnum) {
5208 case PEVENT_ERRNO__MEM_ALLOC_FAILED:
5209 case PEVENT_ERRNO__PARSE_EVENT_FAILED:
5210 case PEVENT_ERRNO__READ_ID_FAILED:
5211 case PEVENT_ERRNO__READ_FORMAT_FAILED:
5212 case PEVENT_ERRNO__READ_PRINT_FAILED:
5213 case PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED:
5214 case PEVENT_ERRNO__INVALID_ARG_TYPE:
5215 snprintf(buf, buflen, "%s", msg);
5216 break;
5217
5218 default:
5219 /* cannot reach here */
5220 break;
5221 }
5222 5234
5223 return 0; 5235 return 0;
5224} 5236}
@@ -5549,6 +5561,52 @@ int pevent_register_print_function(struct pevent *pevent,
5549} 5561}
5550 5562
5551/** 5563/**
5564 * pevent_unregister_print_function - unregister a helper function
5565 * @pevent: the handle to the pevent
5566 * @func: the function to process the helper function
5567 * @name: the name of the helper function
5568 *
5569 * This function removes existing print handler for function @name.
5570 *
5571 * Returns 0 if the handler was removed successully, -1 otherwise.
5572 */
5573int pevent_unregister_print_function(struct pevent *pevent,
5574 pevent_func_handler func, char *name)
5575{
5576 struct pevent_function_handler *func_handle;
5577
5578 func_handle = find_func_handler(pevent, name);
5579 if (func_handle && func_handle->func == func) {
5580 remove_func_handler(pevent, name);
5581 return 0;
5582 }
5583 return -1;
5584}
5585
5586static struct event_format *pevent_search_event(struct pevent *pevent, int id,
5587 const char *sys_name,
5588 const char *event_name)
5589{
5590 struct event_format *event;
5591
5592 if (id >= 0) {
5593 /* search by id */
5594 event = pevent_find_event(pevent, id);
5595 if (!event)
5596 return NULL;
5597 if (event_name && (strcmp(event_name, event->name) != 0))
5598 return NULL;
5599 if (sys_name && (strcmp(sys_name, event->system) != 0))
5600 return NULL;
5601 } else {
5602 event = pevent_find_event_by_name(pevent, sys_name, event_name);
5603 if (!event)
5604 return NULL;
5605 }
5606 return event;
5607}
5608
5609/**
5552 * pevent_register_event_handler - register a way to parse an event 5610 * pevent_register_event_handler - register a way to parse an event
5553 * @pevent: the handle to the pevent 5611 * @pevent: the handle to the pevent
5554 * @id: the id of the event to register 5612 * @id: the id of the event to register
@@ -5572,20 +5630,9 @@ int pevent_register_event_handler(struct pevent *pevent, int id,
5572 struct event_format *event; 5630 struct event_format *event;
5573 struct event_handler *handle; 5631 struct event_handler *handle;
5574 5632
5575 if (id >= 0) { 5633 event = pevent_search_event(pevent, id, sys_name, event_name);
5576 /* search by id */ 5634 if (event == NULL)
5577 event = pevent_find_event(pevent, id); 5635 goto not_found;
5578 if (!event)
5579 goto not_found;
5580 if (event_name && (strcmp(event_name, event->name) != 0))
5581 goto not_found;
5582 if (sys_name && (strcmp(sys_name, event->system) != 0))
5583 goto not_found;
5584 } else {
5585 event = pevent_find_event_by_name(pevent, sys_name, event_name);
5586 if (!event)
5587 goto not_found;
5588 }
5589 5636
5590 pr_stat("overriding event (%d) %s:%s with new print handler", 5637 pr_stat("overriding event (%d) %s:%s with new print handler",
5591 event->id, event->system, event->name); 5638 event->id, event->system, event->name);
@@ -5625,6 +5672,79 @@ int pevent_register_event_handler(struct pevent *pevent, int id,
5625 return -1; 5672 return -1;
5626} 5673}
5627 5674
5675static int handle_matches(struct event_handler *handler, int id,
5676 const char *sys_name, const char *event_name,
5677 pevent_event_handler_func func, void *context)
5678{
5679 if (id >= 0 && id != handler->id)
5680 return 0;
5681
5682 if (event_name && (strcmp(event_name, handler->event_name) != 0))
5683 return 0;
5684
5685 if (sys_name && (strcmp(sys_name, handler->sys_name) != 0))
5686 return 0;
5687
5688 if (func != handler->func || context != handler->context)
5689 return 0;
5690
5691 return 1;
5692}
5693
5694/**
5695 * pevent_unregister_event_handler - unregister an existing event handler
5696 * @pevent: the handle to the pevent
5697 * @id: the id of the event to unregister
5698 * @sys_name: the system name the handler belongs to
5699 * @event_name: the name of the event handler
5700 * @func: the function to call to parse the event information
5701 * @context: the data to be passed to @func
5702 *
5703 * This function removes existing event handler (parser).
5704 *
5705 * If @id is >= 0, then it is used to find the event.
5706 * else @sys_name and @event_name are used.
5707 *
5708 * Returns 0 if handler was removed successfully, -1 if event was not found.
5709 */
5710int pevent_unregister_event_handler(struct pevent *pevent, int id,
5711 const char *sys_name, const char *event_name,
5712 pevent_event_handler_func func, void *context)
5713{
5714 struct event_format *event;
5715 struct event_handler *handle;
5716 struct event_handler **next;
5717
5718 event = pevent_search_event(pevent, id, sys_name, event_name);
5719 if (event == NULL)
5720 goto not_found;
5721
5722 if (event->handler == func && event->context == context) {
5723 pr_stat("removing override handler for event (%d) %s:%s. Going back to default handler.",
5724 event->id, event->system, event->name);
5725
5726 event->handler = NULL;
5727 event->context = NULL;
5728 return 0;
5729 }
5730
5731not_found:
5732 for (next = &pevent->handlers; *next; next = &(*next)->next) {
5733 handle = *next;
5734 if (handle_matches(handle, id, sys_name, event_name,
5735 func, context))
5736 break;
5737 }
5738
5739 if (!(*next))
5740 return -1;
5741
5742 *next = handle->next;
5743 free_handler(handle);
5744
5745 return 0;
5746}
5747
5628/** 5748/**
5629 * pevent_alloc - create a pevent handle 5749 * pevent_alloc - create a pevent handle
5630 */ 5750 */
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 8d73d2594f65..791c539374c7 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -23,6 +23,7 @@
23#include <stdbool.h> 23#include <stdbool.h>
24#include <stdarg.h> 24#include <stdarg.h>
25#include <regex.h> 25#include <regex.h>
26#include <string.h>
26 27
27#ifndef __maybe_unused 28#ifndef __maybe_unused
28#define __maybe_unused __attribute__((unused)) 29#define __maybe_unused __attribute__((unused))
@@ -57,6 +58,12 @@ struct pevent_record {
57#endif 58#endif
58}; 59};
59 60
61enum trace_seq_fail {
62 TRACE_SEQ__GOOD,
63 TRACE_SEQ__BUFFER_POISONED,
64 TRACE_SEQ__MEM_ALLOC_FAILED,
65};
66
60/* 67/*
61 * Trace sequences are used to allow a function to call several other functions 68 * Trace sequences are used to allow a function to call several other functions
62 * to create a string of data to use (up to a max of PAGE_SIZE). 69 * to create a string of data to use (up to a max of PAGE_SIZE).
@@ -67,6 +74,7 @@ struct trace_seq {
67 unsigned int buffer_size; 74 unsigned int buffer_size;
68 unsigned int len; 75 unsigned int len;
69 unsigned int readpos; 76 unsigned int readpos;
77 enum trace_seq_fail state;
70}; 78};
71 79
72void trace_seq_init(struct trace_seq *s); 80void trace_seq_init(struct trace_seq *s);
@@ -97,7 +105,7 @@ typedef int (*pevent_event_handler_func)(struct trace_seq *s,
97 void *context); 105 void *context);
98 106
99typedef int (*pevent_plugin_load_func)(struct pevent *pevent); 107typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
100typedef int (*pevent_plugin_unload_func)(void); 108typedef int (*pevent_plugin_unload_func)(struct pevent *pevent);
101 109
102struct plugin_option { 110struct plugin_option {
103 struct plugin_option *next; 111 struct plugin_option *next;
@@ -122,7 +130,7 @@ struct plugin_option {
122 * PEVENT_PLUGIN_UNLOADER: (optional) 130 * PEVENT_PLUGIN_UNLOADER: (optional)
123 * The function called just before unloading 131 * The function called just before unloading
124 * 132 *
125 * int PEVENT_PLUGIN_UNLOADER(void) 133 * int PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
126 * 134 *
127 * PEVENT_PLUGIN_OPTIONS: (optional) 135 * PEVENT_PLUGIN_OPTIONS: (optional)
128 * Plugin options that can be set before loading 136 * Plugin options that can be set before loading
@@ -355,12 +363,35 @@ enum pevent_flag {
355 _PE(READ_FORMAT_FAILED, "failed to read event format"), \ 363 _PE(READ_FORMAT_FAILED, "failed to read event format"), \
356 _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ 364 _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \
357 _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ 365 _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\
358 _PE(INVALID_ARG_TYPE, "invalid argument type") 366 _PE(INVALID_ARG_TYPE, "invalid argument type"), \
367 _PE(INVALID_EXP_TYPE, "invalid expression type"), \
368 _PE(INVALID_OP_TYPE, "invalid operator type"), \
369 _PE(INVALID_EVENT_NAME, "invalid event name"), \
370 _PE(EVENT_NOT_FOUND, "no event found"), \
371 _PE(SYNTAX_ERROR, "syntax error"), \
372 _PE(ILLEGAL_RVALUE, "illegal rvalue"), \
373 _PE(ILLEGAL_LVALUE, "illegal lvalue for string comparison"), \
374 _PE(INVALID_REGEX, "regex did not compute"), \
375 _PE(ILLEGAL_STRING_CMP, "illegal comparison for string"), \
376 _PE(ILLEGAL_INTEGER_CMP,"illegal comparison for integer"), \
377 _PE(REPARENT_NOT_OP, "cannot reparent other than OP"), \
378 _PE(REPARENT_FAILED, "failed to reparent filter OP"), \
379 _PE(BAD_FILTER_ARG, "bad arg in filter tree"), \
380 _PE(UNEXPECTED_TYPE, "unexpected type (not a value)"), \
381 _PE(ILLEGAL_TOKEN, "illegal token"), \
382 _PE(INVALID_PAREN, "open parenthesis cannot come here"), \
383 _PE(UNBALANCED_PAREN, "unbalanced number of parenthesis"), \
384 _PE(UNKNOWN_TOKEN, "unknown token"), \
385 _PE(FILTER_NOT_FOUND, "no filter found"), \
386 _PE(NOT_A_NUMBER, "must have number field"), \
387 _PE(NO_FILTER, "no filters exists"), \
388 _PE(FILTER_MISS, "record does not match to filter")
359 389
360#undef _PE 390#undef _PE
361#define _PE(__code, __str) PEVENT_ERRNO__ ## __code 391#define _PE(__code, __str) PEVENT_ERRNO__ ## __code
362enum pevent_errno { 392enum pevent_errno {
363 PEVENT_ERRNO__SUCCESS = 0, 393 PEVENT_ERRNO__SUCCESS = 0,
394 PEVENT_ERRNO__FILTER_MATCH = PEVENT_ERRNO__SUCCESS,
364 395
365 /* 396 /*
366 * Choose an arbitrary negative big number not to clash with standard 397 * Choose an arbitrary negative big number not to clash with standard
@@ -377,6 +408,12 @@ enum pevent_errno {
377}; 408};
378#undef _PE 409#undef _PE
379 410
411struct plugin_list;
412
413struct plugin_list *traceevent_load_plugins(struct pevent *pevent);
414void traceevent_unload_plugins(struct plugin_list *plugin_list,
415 struct pevent *pevent);
416
380struct cmdline; 417struct cmdline;
381struct cmdline_list; 418struct cmdline_list;
382struct func_map; 419struct func_map;
@@ -522,6 +559,15 @@ __data2host8(struct pevent *pevent, unsigned long long data)
522 __data2host8(pevent, __val); \ 559 __data2host8(pevent, __val); \
523}) 560})
524 561
562static inline int traceevent_host_bigendian(void)
563{
564 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
565 unsigned int val;
566
567 memcpy(&val, str, 4);
568 return val == 0x01020304;
569}
570
525/* taken from kernel/trace/trace.h */ 571/* taken from kernel/trace/trace.h */
526enum trace_flag_type { 572enum trace_flag_type {
527 TRACE_FLAG_IRQS_OFF = 0x01, 573 TRACE_FLAG_IRQS_OFF = 0x01,
@@ -547,7 +593,9 @@ int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long siz
547 593
548enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, 594enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
549 unsigned long size, const char *sys); 595 unsigned long size, const char *sys);
550enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, 596enum pevent_errno pevent_parse_format(struct pevent *pevent,
597 struct event_format **eventp,
598 const char *buf,
551 unsigned long size, const char *sys); 599 unsigned long size, const char *sys);
552void pevent_free_format(struct event_format *event); 600void pevent_free_format(struct event_format *event);
553 601
@@ -576,10 +624,15 @@ int pevent_print_func_field(struct trace_seq *s, const char *fmt,
576int pevent_register_event_handler(struct pevent *pevent, int id, 624int pevent_register_event_handler(struct pevent *pevent, int id,
577 const char *sys_name, const char *event_name, 625 const char *sys_name, const char *event_name,
578 pevent_event_handler_func func, void *context); 626 pevent_event_handler_func func, void *context);
627int pevent_unregister_event_handler(struct pevent *pevent, int id,
628 const char *sys_name, const char *event_name,
629 pevent_event_handler_func func, void *context);
579int pevent_register_print_function(struct pevent *pevent, 630int pevent_register_print_function(struct pevent *pevent,
580 pevent_func_handler func, 631 pevent_func_handler func,
581 enum pevent_func_arg_type ret_type, 632 enum pevent_func_arg_type ret_type,
582 char *name, ...); 633 char *name, ...);
634int pevent_unregister_print_function(struct pevent *pevent,
635 pevent_func_handler func, char *name);
583 636
584struct format_field *pevent_find_common_field(struct event_format *event, const char *name); 637struct format_field *pevent_find_common_field(struct event_format *event, const char *name);
585struct format_field *pevent_find_field(struct event_format *event, const char *name); 638struct format_field *pevent_find_field(struct event_format *event, const char *name);
@@ -811,18 +864,22 @@ struct filter_type {
811 struct filter_arg *filter; 864 struct filter_arg *filter;
812}; 865};
813 866
867#define PEVENT_FILTER_ERROR_BUFSZ 1024
868
814struct event_filter { 869struct event_filter {
815 struct pevent *pevent; 870 struct pevent *pevent;
816 int filters; 871 int filters;
817 struct filter_type *event_filters; 872 struct filter_type *event_filters;
873 char error_buffer[PEVENT_FILTER_ERROR_BUFSZ];
818}; 874};
819 875
820struct event_filter *pevent_filter_alloc(struct pevent *pevent); 876struct event_filter *pevent_filter_alloc(struct pevent *pevent);
821 877
822#define FILTER_NONE -2 878/* for backward compatibility */
823#define FILTER_NOEXIST -1 879#define FILTER_NONE PEVENT_ERRNO__FILTER_NOT_FOUND
824#define FILTER_MISS 0 880#define FILTER_NOEXIST PEVENT_ERRNO__NO_FILTER
825#define FILTER_MATCH 1 881#define FILTER_MISS PEVENT_ERRNO__FILTER_MISS
882#define FILTER_MATCH PEVENT_ERRNO__FILTER_MATCH
826 883
827enum filter_trivial_type { 884enum filter_trivial_type {
828 FILTER_TRIVIAL_FALSE, 885 FILTER_TRIVIAL_FALSE,
@@ -830,20 +887,21 @@ enum filter_trivial_type {
830 FILTER_TRIVIAL_BOTH, 887 FILTER_TRIVIAL_BOTH,
831}; 888};
832 889
833int pevent_filter_add_filter_str(struct event_filter *filter, 890enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
834 const char *filter_str, 891 const char *filter_str);
835 char **error_str);
836 892
893enum pevent_errno pevent_filter_match(struct event_filter *filter,
894 struct pevent_record *record);
837 895
838int pevent_filter_match(struct event_filter *filter, 896int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err,
839 struct pevent_record *record); 897 char *buf, size_t buflen);
840 898
841int pevent_event_filtered(struct event_filter *filter, 899int pevent_event_filtered(struct event_filter *filter,
842 int event_id); 900 int event_id);
843 901
844void pevent_filter_reset(struct event_filter *filter); 902void pevent_filter_reset(struct event_filter *filter);
845 903
846void pevent_filter_clear_trivial(struct event_filter *filter, 904int pevent_filter_clear_trivial(struct event_filter *filter,
847 enum filter_trivial_type type); 905 enum filter_trivial_type type);
848 906
849void pevent_filter_free(struct event_filter *filter); 907void pevent_filter_free(struct event_filter *filter);
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c
new file mode 100644
index 000000000000..0c8bf6780e4d
--- /dev/null
+++ b/tools/lib/traceevent/event-plugin.c
@@ -0,0 +1,215 @@
1/*
2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20
21#include <string.h>
22#include <dlfcn.h>
23#include <stdlib.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <unistd.h>
27#include <dirent.h>
28#include "event-parse.h"
29#include "event-utils.h"
30
31#define LOCAL_PLUGIN_DIR ".traceevent/plugins"
32
33struct plugin_list {
34 struct plugin_list *next;
35 char *name;
36 void *handle;
37};
38
39static void
40load_plugin(struct pevent *pevent, const char *path,
41 const char *file, void *data)
42{
43 struct plugin_list **plugin_list = data;
44 pevent_plugin_load_func func;
45 struct plugin_list *list;
46 const char *alias;
47 char *plugin;
48 void *handle;
49
50 plugin = malloc(strlen(path) + strlen(file) + 2);
51 if (!plugin) {
52 warning("could not allocate plugin memory\n");
53 return;
54 }
55
56 strcpy(plugin, path);
57 strcat(plugin, "/");
58 strcat(plugin, file);
59
60 handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
61 if (!handle) {
62 warning("could not load plugin '%s'\n%s\n",
63 plugin, dlerror());
64 goto out_free;
65 }
66
67 alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME);
68 if (!alias)
69 alias = file;
70
71 func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME);
72 if (!func) {
73 warning("could not find func '%s' in plugin '%s'\n%s\n",
74 PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror());
75 goto out_free;
76 }
77
78 list = malloc(sizeof(*list));
79 if (!list) {
80 warning("could not allocate plugin memory\n");
81 goto out_free;
82 }
83
84 list->next = *plugin_list;
85 list->handle = handle;
86 list->name = plugin;
87 *plugin_list = list;
88
89 pr_stat("registering plugin: %s", plugin);
90 func(pevent);
91 return;
92
93 out_free:
94 free(plugin);
95}
96
97static void
98load_plugins_dir(struct pevent *pevent, const char *suffix,
99 const char *path,
100 void (*load_plugin)(struct pevent *pevent,
101 const char *path,
102 const char *name,
103 void *data),
104 void *data)
105{
106 struct dirent *dent;
107 struct stat st;
108 DIR *dir;
109 int ret;
110
111 ret = stat(path, &st);
112 if (ret < 0)
113 return;
114
115 if (!S_ISDIR(st.st_mode))
116 return;
117
118 dir = opendir(path);
119 if (!dir)
120 return;
121
122 while ((dent = readdir(dir))) {
123 const char *name = dent->d_name;
124
125 if (strcmp(name, ".") == 0 ||
126 strcmp(name, "..") == 0)
127 continue;
128
129 /* Only load plugins that end in suffix */
130 if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
131 continue;
132
133 load_plugin(pevent, path, name, data);
134 }
135
136 closedir(dir);
137}
138
139static void
140load_plugins(struct pevent *pevent, const char *suffix,
141 void (*load_plugin)(struct pevent *pevent,
142 const char *path,
143 const char *name,
144 void *data),
145 void *data)
146{
147 char *home;
148 char *path;
149 char *envdir;
150
151 /*
152 * If a system plugin directory was defined,
153 * check that first.
154 */
155#ifdef PLUGIN_DIR
156 load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data);
157#endif
158
159 /*
160 * Next let the environment-set plugin directory
161 * override the system defaults.
162 */
163 envdir = getenv("TRACEEVENT_PLUGIN_DIR");
164 if (envdir)
165 load_plugins_dir(pevent, suffix, envdir, load_plugin, data);
166
167 /*
168 * Now let the home directory override the environment
169 * or system defaults.
170 */
171 home = getenv("HOME");
172 if (!home)
173 return;
174
175 path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2);
176 if (!path) {
177 warning("could not allocate plugin memory\n");
178 return;
179 }
180
181 strcpy(path, home);
182 strcat(path, "/");
183 strcat(path, LOCAL_PLUGIN_DIR);
184
185 load_plugins_dir(pevent, suffix, path, load_plugin, data);
186
187 free(path);
188}
189
190struct plugin_list*
191traceevent_load_plugins(struct pevent *pevent)
192{
193 struct plugin_list *list = NULL;
194
195 load_plugins(pevent, ".so", load_plugin, &list);
196 return list;
197}
198
199void
200traceevent_unload_plugins(struct plugin_list *plugin_list, struct pevent *pevent)
201{
202 pevent_plugin_unload_func func;
203 struct plugin_list *list;
204
205 while (plugin_list) {
206 list = plugin_list;
207 plugin_list = list->next;
208 func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME);
209 if (func)
210 func(pevent);
211 dlclose(list->handle);
212 free(list->name);
213 free(list);
214 }
215}
diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h
index e76c9acb92cd..d1dc2170e402 100644
--- a/tools/lib/traceevent/event-utils.h
+++ b/tools/lib/traceevent/event-utils.h
@@ -23,18 +23,14 @@
23#include <ctype.h> 23#include <ctype.h>
24 24
25/* Can be overridden */ 25/* Can be overridden */
26void die(const char *fmt, ...);
27void *malloc_or_die(unsigned int size);
28void warning(const char *fmt, ...); 26void warning(const char *fmt, ...);
29void pr_stat(const char *fmt, ...); 27void pr_stat(const char *fmt, ...);
30void vpr_stat(const char *fmt, va_list ap); 28void vpr_stat(const char *fmt, va_list ap);
31 29
32/* Always available */ 30/* Always available */
33void __die(const char *fmt, ...);
34void __warning(const char *fmt, ...); 31void __warning(const char *fmt, ...);
35void __pr_stat(const char *fmt, ...); 32void __pr_stat(const char *fmt, ...);
36 33
37void __vdie(const char *fmt, ...);
38void __vwarning(const char *fmt, ...); 34void __vwarning(const char *fmt, ...);
39void __vpr_stat(const char *fmt, ...); 35void __vpr_stat(const char *fmt, ...);
40 36
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
index 2500e75583fc..b50234402fc2 100644
--- a/tools/lib/traceevent/parse-filter.c
+++ b/tools/lib/traceevent/parse-filter.c
@@ -38,41 +38,31 @@ struct event_list {
38 struct event_format *event; 38 struct event_format *event;
39}; 39};
40 40
41#define MAX_ERR_STR_SIZE 256 41static void show_error(char *error_buf, const char *fmt, ...)
42
43static void show_error(char **error_str, const char *fmt, ...)
44{ 42{
45 unsigned long long index; 43 unsigned long long index;
46 const char *input; 44 const char *input;
47 char *error;
48 va_list ap; 45 va_list ap;
49 int len; 46 int len;
50 int i; 47 int i;
51 48
52 if (!error_str)
53 return;
54
55 input = pevent_get_input_buf(); 49 input = pevent_get_input_buf();
56 index = pevent_get_input_buf_ptr(); 50 index = pevent_get_input_buf_ptr();
57 len = input ? strlen(input) : 0; 51 len = input ? strlen(input) : 0;
58 52
59 error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3);
60
61 if (len) { 53 if (len) {
62 strcpy(error, input); 54 strcpy(error_buf, input);
63 error[len] = '\n'; 55 error_buf[len] = '\n';
64 for (i = 1; i < len && i < index; i++) 56 for (i = 1; i < len && i < index; i++)
65 error[len+i] = ' '; 57 error_buf[len+i] = ' ';
66 error[len + i] = '^'; 58 error_buf[len + i] = '^';
67 error[len + i + 1] = '\n'; 59 error_buf[len + i + 1] = '\n';
68 len += i+2; 60 len += i+2;
69 } 61 }
70 62
71 va_start(ap, fmt); 63 va_start(ap, fmt);
72 vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap); 64 vsnprintf(error_buf + len, PEVENT_FILTER_ERROR_BUFSZ - len, fmt, ap);
73 va_end(ap); 65 va_end(ap);
74
75 *error_str = error;
76} 66}
77 67
78static void free_token(char *token) 68static void free_token(char *token)
@@ -95,7 +85,11 @@ static enum event_type read_token(char **tok)
95 (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && 85 (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
96 pevent_peek_char() == '~') { 86 pevent_peek_char() == '~') {
97 /* append it */ 87 /* append it */
98 *tok = malloc_or_die(3); 88 *tok = malloc(3);
89 if (*tok == NULL) {
90 free_token(token);
91 return EVENT_ERROR;
92 }
99 sprintf(*tok, "%c%c", *token, '~'); 93 sprintf(*tok, "%c%c", *token, '~');
100 free_token(token); 94 free_token(token);
101 /* Now remove the '~' from the buffer */ 95 /* Now remove the '~' from the buffer */
@@ -147,11 +141,13 @@ add_filter_type(struct event_filter *filter, int id)
147 if (filter_type) 141 if (filter_type)
148 return filter_type; 142 return filter_type;
149 143
150 filter->event_filters = realloc(filter->event_filters, 144 filter_type = realloc(filter->event_filters,
151 sizeof(*filter->event_filters) * 145 sizeof(*filter->event_filters) *
152 (filter->filters + 1)); 146 (filter->filters + 1));
153 if (!filter->event_filters) 147 if (!filter_type)
154 die("Could not allocate filter"); 148 return NULL;
149
150 filter->event_filters = filter_type;
155 151
156 for (i = 0; i < filter->filters; i++) { 152 for (i = 0; i < filter->filters; i++) {
157 if (filter->event_filters[i].event_id > id) 153 if (filter->event_filters[i].event_id > id)
@@ -182,7 +178,10 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent)
182{ 178{
183 struct event_filter *filter; 179 struct event_filter *filter;
184 180
185 filter = malloc_or_die(sizeof(*filter)); 181 filter = malloc(sizeof(*filter));
182 if (filter == NULL)
183 return NULL;
184
186 memset(filter, 0, sizeof(*filter)); 185 memset(filter, 0, sizeof(*filter));
187 filter->pevent = pevent; 186 filter->pevent = pevent;
188 pevent_ref(pevent); 187 pevent_ref(pevent);
@@ -192,12 +191,7 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent)
192 191
193static struct filter_arg *allocate_arg(void) 192static struct filter_arg *allocate_arg(void)
194{ 193{
195 struct filter_arg *arg; 194 return calloc(1, sizeof(struct filter_arg));
196
197 arg = malloc_or_die(sizeof(*arg));
198 memset(arg, 0, sizeof(*arg));
199
200 return arg;
201} 195}
202 196
203static void free_arg(struct filter_arg *arg) 197static void free_arg(struct filter_arg *arg)
@@ -242,15 +236,19 @@ static void free_arg(struct filter_arg *arg)
242 free(arg); 236 free(arg);
243} 237}
244 238
245static void add_event(struct event_list **events, 239static int add_event(struct event_list **events,
246 struct event_format *event) 240 struct event_format *event)
247{ 241{
248 struct event_list *list; 242 struct event_list *list;
249 243
250 list = malloc_or_die(sizeof(*list)); 244 list = malloc(sizeof(*list));
245 if (list == NULL)
246 return -1;
247
251 list->next = *events; 248 list->next = *events;
252 *events = list; 249 *events = list;
253 list->event = event; 250 list->event = event;
251 return 0;
254} 252}
255 253
256static int event_match(struct event_format *event, 254static int event_match(struct event_format *event,
@@ -265,7 +263,7 @@ static int event_match(struct event_format *event,
265 !regexec(ereg, event->name, 0, NULL, 0); 263 !regexec(ereg, event->name, 0, NULL, 0);
266} 264}
267 265
268static int 266static enum pevent_errno
269find_event(struct pevent *pevent, struct event_list **events, 267find_event(struct pevent *pevent, struct event_list **events,
270 char *sys_name, char *event_name) 268 char *sys_name, char *event_name)
271{ 269{
@@ -273,6 +271,7 @@ find_event(struct pevent *pevent, struct event_list **events,
273 regex_t ereg; 271 regex_t ereg;
274 regex_t sreg; 272 regex_t sreg;
275 int match = 0; 273 int match = 0;
274 int fail = 0;
276 char *reg; 275 char *reg;
277 int ret; 276 int ret;
278 int i; 277 int i;
@@ -283,23 +282,31 @@ find_event(struct pevent *pevent, struct event_list **events,
283 sys_name = NULL; 282 sys_name = NULL;
284 } 283 }
285 284
286 reg = malloc_or_die(strlen(event_name) + 3); 285 reg = malloc(strlen(event_name) + 3);
286 if (reg == NULL)
287 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
288
287 sprintf(reg, "^%s$", event_name); 289 sprintf(reg, "^%s$", event_name);
288 290
289 ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); 291 ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
290 free(reg); 292 free(reg);
291 293
292 if (ret) 294 if (ret)
293 return -1; 295 return PEVENT_ERRNO__INVALID_EVENT_NAME;
294 296
295 if (sys_name) { 297 if (sys_name) {
296 reg = malloc_or_die(strlen(sys_name) + 3); 298 reg = malloc(strlen(sys_name) + 3);
299 if (reg == NULL) {
300 regfree(&ereg);
301 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
302 }
303
297 sprintf(reg, "^%s$", sys_name); 304 sprintf(reg, "^%s$", sys_name);
298 ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); 305 ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
299 free(reg); 306 free(reg);
300 if (ret) { 307 if (ret) {
301 regfree(&ereg); 308 regfree(&ereg);
302 return -1; 309 return PEVENT_ERRNO__INVALID_EVENT_NAME;
303 } 310 }
304 } 311 }
305 312
@@ -307,7 +314,10 @@ find_event(struct pevent *pevent, struct event_list **events,
307 event = pevent->events[i]; 314 event = pevent->events[i];
308 if (event_match(event, sys_name ? &sreg : NULL, &ereg)) { 315 if (event_match(event, sys_name ? &sreg : NULL, &ereg)) {
309 match = 1; 316 match = 1;
310 add_event(events, event); 317 if (add_event(events, event) < 0) {
318 fail = 1;
319 break;
320 }
311 } 321 }
312 } 322 }
313 323
@@ -316,7 +326,9 @@ find_event(struct pevent *pevent, struct event_list **events,
316 regfree(&sreg); 326 regfree(&sreg);
317 327
318 if (!match) 328 if (!match)
319 return -1; 329 return PEVENT_ERRNO__EVENT_NOT_FOUND;
330 if (fail)
331 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
320 332
321 return 0; 333 return 0;
322} 334}
@@ -332,14 +344,18 @@ static void free_events(struct event_list *events)
332 } 344 }
333} 345}
334 346
335static struct filter_arg * 347static enum pevent_errno
336create_arg_item(struct event_format *event, const char *token, 348create_arg_item(struct event_format *event, const char *token,
337 enum event_type type, char **error_str) 349 enum event_type type, struct filter_arg **parg, char *error_str)
338{ 350{
339 struct format_field *field; 351 struct format_field *field;
340 struct filter_arg *arg; 352 struct filter_arg *arg;
341 353
342 arg = allocate_arg(); 354 arg = allocate_arg();
355 if (arg == NULL) {
356 show_error(error_str, "failed to allocate filter arg");
357 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
358 }
343 359
344 switch (type) { 360 switch (type) {
345 361
@@ -349,8 +365,11 @@ create_arg_item(struct event_format *event, const char *token,
349 arg->value.type = 365 arg->value.type =
350 type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR; 366 type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR;
351 arg->value.str = strdup(token); 367 arg->value.str = strdup(token);
352 if (!arg->value.str) 368 if (!arg->value.str) {
353 die("malloc string"); 369 free_arg(arg);
370 show_error(error_str, "failed to allocate string filter arg");
371 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
372 }
354 break; 373 break;
355 case EVENT_ITEM: 374 case EVENT_ITEM:
356 /* if it is a number, then convert it */ 375 /* if it is a number, then convert it */
@@ -377,11 +396,11 @@ create_arg_item(struct event_format *event, const char *token,
377 break; 396 break;
378 default: 397 default:
379 free_arg(arg); 398 free_arg(arg);
380 show_error(error_str, "expected a value but found %s", 399 show_error(error_str, "expected a value but found %s", token);
381 token); 400 return PEVENT_ERRNO__UNEXPECTED_TYPE;
382 return NULL;
383 } 401 }
384 return arg; 402 *parg = arg;
403 return 0;
385} 404}
386 405
387static struct filter_arg * 406static struct filter_arg *
@@ -390,6 +409,9 @@ create_arg_op(enum filter_op_type btype)
390 struct filter_arg *arg; 409 struct filter_arg *arg;
391 410
392 arg = allocate_arg(); 411 arg = allocate_arg();
412 if (!arg)
413 return NULL;
414
393 arg->type = FILTER_ARG_OP; 415 arg->type = FILTER_ARG_OP;
394 arg->op.type = btype; 416 arg->op.type = btype;
395 417
@@ -402,6 +424,9 @@ create_arg_exp(enum filter_exp_type etype)
402 struct filter_arg *arg; 424 struct filter_arg *arg;
403 425
404 arg = allocate_arg(); 426 arg = allocate_arg();
427 if (!arg)
428 return NULL;
429
405 arg->type = FILTER_ARG_EXP; 430 arg->type = FILTER_ARG_EXP;
406 arg->op.type = etype; 431 arg->op.type = etype;
407 432
@@ -414,6 +439,9 @@ create_arg_cmp(enum filter_exp_type etype)
414 struct filter_arg *arg; 439 struct filter_arg *arg;
415 440
416 arg = allocate_arg(); 441 arg = allocate_arg();
442 if (!arg)
443 return NULL;
444
417 /* Use NUM and change if necessary */ 445 /* Use NUM and change if necessary */
418 arg->type = FILTER_ARG_NUM; 446 arg->type = FILTER_ARG_NUM;
419 arg->op.type = etype; 447 arg->op.type = etype;
@@ -421,8 +449,8 @@ create_arg_cmp(enum filter_exp_type etype)
421 return arg; 449 return arg;
422} 450}
423 451
424static int add_right(struct filter_arg *op, struct filter_arg *arg, 452static enum pevent_errno
425 char **error_str) 453add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str)
426{ 454{
427 struct filter_arg *left; 455 struct filter_arg *left;
428 char *str; 456 char *str;
@@ -453,9 +481,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
453 case FILTER_ARG_FIELD: 481 case FILTER_ARG_FIELD:
454 break; 482 break;
455 default: 483 default:
456 show_error(error_str, 484 show_error(error_str, "Illegal rvalue");
457 "Illegal rvalue"); 485 return PEVENT_ERRNO__ILLEGAL_RVALUE;
458 return -1;
459 } 486 }
460 487
461 /* 488 /*
@@ -502,7 +529,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
502 if (left->type != FILTER_ARG_FIELD) { 529 if (left->type != FILTER_ARG_FIELD) {
503 show_error(error_str, 530 show_error(error_str,
504 "Illegal lvalue for string comparison"); 531 "Illegal lvalue for string comparison");
505 return -1; 532 return PEVENT_ERRNO__ILLEGAL_LVALUE;
506 } 533 }
507 534
508 /* Make sure this is a valid string compare */ 535 /* Make sure this is a valid string compare */
@@ -521,25 +548,31 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
521 show_error(error_str, 548 show_error(error_str,
522 "RegEx '%s' did not compute", 549 "RegEx '%s' did not compute",
523 str); 550 str);
524 return -1; 551 return PEVENT_ERRNO__INVALID_REGEX;
525 } 552 }
526 break; 553 break;
527 default: 554 default:
528 show_error(error_str, 555 show_error(error_str,
529 "Illegal comparison for string"); 556 "Illegal comparison for string");
530 return -1; 557 return PEVENT_ERRNO__ILLEGAL_STRING_CMP;
531 } 558 }
532 559
533 op->type = FILTER_ARG_STR; 560 op->type = FILTER_ARG_STR;
534 op->str.type = op_type; 561 op->str.type = op_type;
535 op->str.field = left->field.field; 562 op->str.field = left->field.field;
536 op->str.val = strdup(str); 563 op->str.val = strdup(str);
537 if (!op->str.val) 564 if (!op->str.val) {
538 die("malloc string"); 565 show_error(error_str, "Failed to allocate string filter");
566 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
567 }
539 /* 568 /*
540 * Need a buffer to copy data for tests 569 * Need a buffer to copy data for tests
541 */ 570 */
542 op->str.buffer = malloc_or_die(op->str.field->size + 1); 571 op->str.buffer = malloc(op->str.field->size + 1);
572 if (!op->str.buffer) {
573 show_error(error_str, "Failed to allocate string filter");
574 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
575 }
543 /* Null terminate this buffer */ 576 /* Null terminate this buffer */
544 op->str.buffer[op->str.field->size] = 0; 577 op->str.buffer[op->str.field->size] = 0;
545 578
@@ -557,7 +590,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
557 case FILTER_CMP_NOT_REGEX: 590 case FILTER_CMP_NOT_REGEX:
558 show_error(error_str, 591 show_error(error_str,
559 "Op not allowed with integers"); 592 "Op not allowed with integers");
560 return -1; 593 return PEVENT_ERRNO__ILLEGAL_INTEGER_CMP;
561 594
562 default: 595 default:
563 break; 596 break;
@@ -577,9 +610,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
577 return 0; 610 return 0;
578 611
579 out_fail: 612 out_fail:
580 show_error(error_str, 613 show_error(error_str, "Syntax error");
581 "Syntax error"); 614 return PEVENT_ERRNO__SYNTAX_ERROR;
582 return -1;
583} 615}
584 616
585static struct filter_arg * 617static struct filter_arg *
@@ -592,7 +624,7 @@ rotate_op_right(struct filter_arg *a, struct filter_arg *b)
592 return arg; 624 return arg;
593} 625}
594 626
595static int add_left(struct filter_arg *op, struct filter_arg *arg) 627static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg)
596{ 628{
597 switch (op->type) { 629 switch (op->type) {
598 case FILTER_ARG_EXP: 630 case FILTER_ARG_EXP:
@@ -611,11 +643,11 @@ static int add_left(struct filter_arg *op, struct filter_arg *arg)
611 /* left arg of compares must be a field */ 643 /* left arg of compares must be a field */
612 if (arg->type != FILTER_ARG_FIELD && 644 if (arg->type != FILTER_ARG_FIELD &&
613 arg->type != FILTER_ARG_BOOLEAN) 645 arg->type != FILTER_ARG_BOOLEAN)
614 return -1; 646 return PEVENT_ERRNO__INVALID_ARG_TYPE;
615 op->num.left = arg; 647 op->num.left = arg;
616 break; 648 break;
617 default: 649 default:
618 return -1; 650 return PEVENT_ERRNO__INVALID_ARG_TYPE;
619 } 651 }
620 return 0; 652 return 0;
621} 653}
@@ -728,15 +760,18 @@ enum filter_vals {
728 FILTER_VAL_TRUE, 760 FILTER_VAL_TRUE,
729}; 761};
730 762
731void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, 763static enum pevent_errno
732 struct filter_arg *arg) 764reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
765 struct filter_arg *arg, char *error_str)
733{ 766{
734 struct filter_arg *other_child; 767 struct filter_arg *other_child;
735 struct filter_arg **ptr; 768 struct filter_arg **ptr;
736 769
737 if (parent->type != FILTER_ARG_OP && 770 if (parent->type != FILTER_ARG_OP &&
738 arg->type != FILTER_ARG_OP) 771 arg->type != FILTER_ARG_OP) {
739 die("can not reparent other than OP"); 772 show_error(error_str, "can not reparent other than OP");
773 return PEVENT_ERRNO__REPARENT_NOT_OP;
774 }
740 775
741 /* Get the sibling */ 776 /* Get the sibling */
742 if (old_child->op.right == arg) { 777 if (old_child->op.right == arg) {
@@ -745,8 +780,10 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
745 } else if (old_child->op.left == arg) { 780 } else if (old_child->op.left == arg) {
746 ptr = &old_child->op.left; 781 ptr = &old_child->op.left;
747 other_child = old_child->op.right; 782 other_child = old_child->op.right;
748 } else 783 } else {
749 die("Error in reparent op, find other child"); 784 show_error(error_str, "Error in reparent op, find other child");
785 return PEVENT_ERRNO__REPARENT_FAILED;
786 }
750 787
751 /* Detach arg from old_child */ 788 /* Detach arg from old_child */
752 *ptr = NULL; 789 *ptr = NULL;
@@ -757,23 +794,29 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
757 *parent = *arg; 794 *parent = *arg;
758 /* Free arg without recussion */ 795 /* Free arg without recussion */
759 free(arg); 796 free(arg);
760 return; 797 return 0;
761 } 798 }
762 799
763 if (parent->op.right == old_child) 800 if (parent->op.right == old_child)
764 ptr = &parent->op.right; 801 ptr = &parent->op.right;
765 else if (parent->op.left == old_child) 802 else if (parent->op.left == old_child)
766 ptr = &parent->op.left; 803 ptr = &parent->op.left;
767 else 804 else {
768 die("Error in reparent op"); 805 show_error(error_str, "Error in reparent op");
806 return PEVENT_ERRNO__REPARENT_FAILED;
807 }
808
769 *ptr = arg; 809 *ptr = arg;
770 810
771 free_arg(old_child); 811 free_arg(old_child);
812 return 0;
772} 813}
773 814
774enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) 815/* Returns either filter_vals (success) or pevent_errno (failfure) */
816static int test_arg(struct filter_arg *parent, struct filter_arg *arg,
817 char *error_str)
775{ 818{
776 enum filter_vals lval, rval; 819 int lval, rval;
777 820
778 switch (arg->type) { 821 switch (arg->type) {
779 822
@@ -788,63 +831,68 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
788 return FILTER_VAL_NORM; 831 return FILTER_VAL_NORM;
789 832
790 case FILTER_ARG_EXP: 833 case FILTER_ARG_EXP:
791 lval = test_arg(arg, arg->exp.left); 834 lval = test_arg(arg, arg->exp.left, error_str);
792 if (lval != FILTER_VAL_NORM) 835 if (lval != FILTER_VAL_NORM)
793 return lval; 836 return lval;
794 rval = test_arg(arg, arg->exp.right); 837 rval = test_arg(arg, arg->exp.right, error_str);
795 if (rval != FILTER_VAL_NORM) 838 if (rval != FILTER_VAL_NORM)
796 return rval; 839 return rval;
797 return FILTER_VAL_NORM; 840 return FILTER_VAL_NORM;
798 841
799 case FILTER_ARG_NUM: 842 case FILTER_ARG_NUM:
800 lval = test_arg(arg, arg->num.left); 843 lval = test_arg(arg, arg->num.left, error_str);
801 if (lval != FILTER_VAL_NORM) 844 if (lval != FILTER_VAL_NORM)
802 return lval; 845 return lval;
803 rval = test_arg(arg, arg->num.right); 846 rval = test_arg(arg, arg->num.right, error_str);
804 if (rval != FILTER_VAL_NORM) 847 if (rval != FILTER_VAL_NORM)
805 return rval; 848 return rval;
806 return FILTER_VAL_NORM; 849 return FILTER_VAL_NORM;
807 850
808 case FILTER_ARG_OP: 851 case FILTER_ARG_OP:
809 if (arg->op.type != FILTER_OP_NOT) { 852 if (arg->op.type != FILTER_OP_NOT) {
810 lval = test_arg(arg, arg->op.left); 853 lval = test_arg(arg, arg->op.left, error_str);
811 switch (lval) { 854 switch (lval) {
812 case FILTER_VAL_NORM: 855 case FILTER_VAL_NORM:
813 break; 856 break;
814 case FILTER_VAL_TRUE: 857 case FILTER_VAL_TRUE:
815 if (arg->op.type == FILTER_OP_OR) 858 if (arg->op.type == FILTER_OP_OR)
816 return FILTER_VAL_TRUE; 859 return FILTER_VAL_TRUE;
817 rval = test_arg(arg, arg->op.right); 860 rval = test_arg(arg, arg->op.right, error_str);
818 if (rval != FILTER_VAL_NORM) 861 if (rval != FILTER_VAL_NORM)
819 return rval; 862 return rval;
820 863
821 reparent_op_arg(parent, arg, arg->op.right); 864 return reparent_op_arg(parent, arg, arg->op.right,
822 return FILTER_VAL_NORM; 865 error_str);
823 866
824 case FILTER_VAL_FALSE: 867 case FILTER_VAL_FALSE:
825 if (arg->op.type == FILTER_OP_AND) 868 if (arg->op.type == FILTER_OP_AND)
826 return FILTER_VAL_FALSE; 869 return FILTER_VAL_FALSE;
827 rval = test_arg(arg, arg->op.right); 870 rval = test_arg(arg, arg->op.right, error_str);
828 if (rval != FILTER_VAL_NORM) 871 if (rval != FILTER_VAL_NORM)
829 return rval; 872 return rval;
830 873
831 reparent_op_arg(parent, arg, arg->op.right); 874 return reparent_op_arg(parent, arg, arg->op.right,
832 return FILTER_VAL_NORM; 875 error_str);
876
877 default:
878 return lval;
833 } 879 }
834 } 880 }
835 881
836 rval = test_arg(arg, arg->op.right); 882 rval = test_arg(arg, arg->op.right, error_str);
837 switch (rval) { 883 switch (rval) {
838 case FILTER_VAL_NORM: 884 case FILTER_VAL_NORM:
885 default:
839 break; 886 break;
887
840 case FILTER_VAL_TRUE: 888 case FILTER_VAL_TRUE:
841 if (arg->op.type == FILTER_OP_OR) 889 if (arg->op.type == FILTER_OP_OR)
842 return FILTER_VAL_TRUE; 890 return FILTER_VAL_TRUE;
843 if (arg->op.type == FILTER_OP_NOT) 891 if (arg->op.type == FILTER_OP_NOT)
844 return FILTER_VAL_FALSE; 892 return FILTER_VAL_FALSE;
845 893
846 reparent_op_arg(parent, arg, arg->op.left); 894 return reparent_op_arg(parent, arg, arg->op.left,
847 return FILTER_VAL_NORM; 895 error_str);
848 896
849 case FILTER_VAL_FALSE: 897 case FILTER_VAL_FALSE:
850 if (arg->op.type == FILTER_OP_AND) 898 if (arg->op.type == FILTER_OP_AND)
@@ -852,41 +900,56 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
852 if (arg->op.type == FILTER_OP_NOT) 900 if (arg->op.type == FILTER_OP_NOT)
853 return FILTER_VAL_TRUE; 901 return FILTER_VAL_TRUE;
854 902
855 reparent_op_arg(parent, arg, arg->op.left); 903 return reparent_op_arg(parent, arg, arg->op.left,
856 return FILTER_VAL_NORM; 904 error_str);
857 } 905 }
858 906
859 return FILTER_VAL_NORM; 907 return rval;
860 default: 908 default:
861 die("bad arg in filter tree"); 909 show_error(error_str, "bad arg in filter tree");
910 return PEVENT_ERRNO__BAD_FILTER_ARG;
862 } 911 }
863 return FILTER_VAL_NORM; 912 return FILTER_VAL_NORM;
864} 913}
865 914
866/* Remove any unknown event fields */ 915/* Remove any unknown event fields */
867static struct filter_arg *collapse_tree(struct filter_arg *arg) 916static int collapse_tree(struct filter_arg *arg,
917 struct filter_arg **arg_collapsed, char *error_str)
868{ 918{
869 enum filter_vals ret; 919 int ret;
870 920
871 ret = test_arg(arg, arg); 921 ret = test_arg(arg, arg, error_str);
872 switch (ret) { 922 switch (ret) {
873 case FILTER_VAL_NORM: 923 case FILTER_VAL_NORM:
874 return arg; 924 break;
875 925
876 case FILTER_VAL_TRUE: 926 case FILTER_VAL_TRUE:
877 case FILTER_VAL_FALSE: 927 case FILTER_VAL_FALSE:
878 free_arg(arg); 928 free_arg(arg);
879 arg = allocate_arg(); 929 arg = allocate_arg();
880 arg->type = FILTER_ARG_BOOLEAN; 930 if (arg) {
881 arg->boolean.value = ret == FILTER_VAL_TRUE; 931 arg->type = FILTER_ARG_BOOLEAN;
932 arg->boolean.value = ret == FILTER_VAL_TRUE;
933 } else {
934 show_error(error_str, "Failed to allocate filter arg");
935 ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
936 }
937 break;
938
939 default:
940 /* test_arg() already set the error_str */
941 free_arg(arg);
942 arg = NULL;
943 break;
882 } 944 }
883 945
884 return arg; 946 *arg_collapsed = arg;
947 return ret;
885} 948}
886 949
887static int 950static enum pevent_errno
888process_filter(struct event_format *event, struct filter_arg **parg, 951process_filter(struct event_format *event, struct filter_arg **parg,
889 char **error_str, int not) 952 char *error_str, int not)
890{ 953{
891 enum event_type type; 954 enum event_type type;
892 char *token = NULL; 955 char *token = NULL;
@@ -898,7 +961,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
898 enum filter_op_type btype; 961 enum filter_op_type btype;
899 enum filter_exp_type etype; 962 enum filter_exp_type etype;
900 enum filter_cmp_type ctype; 963 enum filter_cmp_type ctype;
901 int ret; 964 enum pevent_errno ret;
902 965
903 *parg = NULL; 966 *parg = NULL;
904 967
@@ -909,8 +972,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
909 case EVENT_SQUOTE: 972 case EVENT_SQUOTE:
910 case EVENT_DQUOTE: 973 case EVENT_DQUOTE:
911 case EVENT_ITEM: 974 case EVENT_ITEM:
912 arg = create_arg_item(event, token, type, error_str); 975 ret = create_arg_item(event, token, type, &arg, error_str);
913 if (!arg) 976 if (ret < 0)
914 goto fail; 977 goto fail;
915 if (!left_item) 978 if (!left_item)
916 left_item = arg; 979 left_item = arg;
@@ -923,20 +986,20 @@ process_filter(struct event_format *event, struct filter_arg **parg,
923 if (not) { 986 if (not) {
924 arg = NULL; 987 arg = NULL;
925 if (current_op) 988 if (current_op)
926 goto fail_print; 989 goto fail_syntax;
927 free(token); 990 free(token);
928 *parg = current_exp; 991 *parg = current_exp;
929 return 0; 992 return 0;
930 } 993 }
931 } else 994 } else
932 goto fail_print; 995 goto fail_syntax;
933 arg = NULL; 996 arg = NULL;
934 break; 997 break;
935 998
936 case EVENT_DELIM: 999 case EVENT_DELIM:
937 if (*token == ',') { 1000 if (*token == ',') {
938 show_error(error_str, 1001 show_error(error_str, "Illegal token ','");
939 "Illegal token ','"); 1002 ret = PEVENT_ERRNO__ILLEGAL_TOKEN;
940 goto fail; 1003 goto fail;
941 } 1004 }
942 1005
@@ -944,19 +1007,23 @@ process_filter(struct event_format *event, struct filter_arg **parg,
944 if (left_item) { 1007 if (left_item) {
945 show_error(error_str, 1008 show_error(error_str,
946 "Open paren can not come after item"); 1009 "Open paren can not come after item");
1010 ret = PEVENT_ERRNO__INVALID_PAREN;
947 goto fail; 1011 goto fail;
948 } 1012 }
949 if (current_exp) { 1013 if (current_exp) {
950 show_error(error_str, 1014 show_error(error_str,
951 "Open paren can not come after expression"); 1015 "Open paren can not come after expression");
1016 ret = PEVENT_ERRNO__INVALID_PAREN;
952 goto fail; 1017 goto fail;
953 } 1018 }
954 1019
955 ret = process_filter(event, &arg, error_str, 0); 1020 ret = process_filter(event, &arg, error_str, 0);
956 if (ret != 1) { 1021 if (ret != PEVENT_ERRNO__UNBALANCED_PAREN) {
957 if (ret == 0) 1022 if (ret == 0) {
958 show_error(error_str, 1023 show_error(error_str,
959 "Unbalanced number of '('"); 1024 "Unbalanced number of '('");
1025 ret = PEVENT_ERRNO__UNBALANCED_PAREN;
1026 }
960 goto fail; 1027 goto fail;
961 } 1028 }
962 ret = 0; 1029 ret = 0;
@@ -964,7 +1031,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
964 /* A not wants just one expression */ 1031 /* A not wants just one expression */
965 if (not) { 1032 if (not) {
966 if (current_op) 1033 if (current_op)
967 goto fail_print; 1034 goto fail_syntax;
968 *parg = arg; 1035 *parg = arg;
969 return 0; 1036 return 0;
970 } 1037 }
@@ -979,19 +1046,19 @@ process_filter(struct event_format *event, struct filter_arg **parg,
979 1046
980 } else { /* ')' */ 1047 } else { /* ')' */
981 if (!current_op && !current_exp) 1048 if (!current_op && !current_exp)
982 goto fail_print; 1049 goto fail_syntax;
983 1050
984 /* Make sure everything is finished at this level */ 1051 /* Make sure everything is finished at this level */
985 if (current_exp && !check_op_done(current_exp)) 1052 if (current_exp && !check_op_done(current_exp))
986 goto fail_print; 1053 goto fail_syntax;
987 if (current_op && !check_op_done(current_op)) 1054 if (current_op && !check_op_done(current_op))
988 goto fail_print; 1055 goto fail_syntax;
989 1056
990 if (current_op) 1057 if (current_op)
991 *parg = current_op; 1058 *parg = current_op;
992 else 1059 else
993 *parg = current_exp; 1060 *parg = current_exp;
994 return 1; 1061 return PEVENT_ERRNO__UNBALANCED_PAREN;
995 } 1062 }
996 break; 1063 break;
997 1064
@@ -1003,21 +1070,22 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1003 case OP_BOOL: 1070 case OP_BOOL:
1004 /* Logic ops need a left expression */ 1071 /* Logic ops need a left expression */
1005 if (!current_exp && !current_op) 1072 if (!current_exp && !current_op)
1006 goto fail_print; 1073 goto fail_syntax;
1007 /* fall through */ 1074 /* fall through */
1008 case OP_NOT: 1075 case OP_NOT:
1009 /* logic only processes ops and exp */ 1076 /* logic only processes ops and exp */
1010 if (left_item) 1077 if (left_item)
1011 goto fail_print; 1078 goto fail_syntax;
1012 break; 1079 break;
1013 case OP_EXP: 1080 case OP_EXP:
1014 case OP_CMP: 1081 case OP_CMP:
1015 if (!left_item) 1082 if (!left_item)
1016 goto fail_print; 1083 goto fail_syntax;
1017 break; 1084 break;
1018 case OP_NONE: 1085 case OP_NONE:
1019 show_error(error_str, 1086 show_error(error_str,
1020 "Unknown op token %s", token); 1087 "Unknown op token %s", token);
1088 ret = PEVENT_ERRNO__UNKNOWN_TOKEN;
1021 goto fail; 1089 goto fail;
1022 } 1090 }
1023 1091
@@ -1025,6 +1093,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1025 switch (op_type) { 1093 switch (op_type) {
1026 case OP_BOOL: 1094 case OP_BOOL:
1027 arg = create_arg_op(btype); 1095 arg = create_arg_op(btype);
1096 if (arg == NULL)
1097 goto fail_alloc;
1028 if (current_op) 1098 if (current_op)
1029 ret = add_left(arg, current_op); 1099 ret = add_left(arg, current_op);
1030 else 1100 else
@@ -1035,6 +1105,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1035 1105
1036 case OP_NOT: 1106 case OP_NOT:
1037 arg = create_arg_op(btype); 1107 arg = create_arg_op(btype);
1108 if (arg == NULL)
1109 goto fail_alloc;
1038 if (current_op) 1110 if (current_op)
1039 ret = add_right(current_op, arg, error_str); 1111 ret = add_right(current_op, arg, error_str);
1040 if (ret < 0) 1112 if (ret < 0)
@@ -1054,6 +1126,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1054 arg = create_arg_exp(etype); 1126 arg = create_arg_exp(etype);
1055 else 1127 else
1056 arg = create_arg_cmp(ctype); 1128 arg = create_arg_cmp(ctype);
1129 if (arg == NULL)
1130 goto fail_alloc;
1057 1131
1058 if (current_op) 1132 if (current_op)
1059 ret = add_right(current_op, arg, error_str); 1133 ret = add_right(current_op, arg, error_str);
@@ -1062,7 +1136,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1062 ret = add_left(arg, left_item); 1136 ret = add_left(arg, left_item);
1063 if (ret < 0) { 1137 if (ret < 0) {
1064 arg = NULL; 1138 arg = NULL;
1065 goto fail_print; 1139 goto fail_syntax;
1066 } 1140 }
1067 current_exp = arg; 1141 current_exp = arg;
1068 break; 1142 break;
@@ -1071,57 +1145,64 @@ process_filter(struct event_format *event, struct filter_arg **parg,
1071 } 1145 }
1072 arg = NULL; 1146 arg = NULL;
1073 if (ret < 0) 1147 if (ret < 0)
1074 goto fail_print; 1148 goto fail_syntax;
1075 break; 1149 break;
1076 case EVENT_NONE: 1150 case EVENT_NONE:
1077 break; 1151 break;
1152 case EVENT_ERROR:
1153 goto fail_alloc;
1078 default: 1154 default:
1079 goto fail_print; 1155 goto fail_syntax;
1080 } 1156 }
1081 } while (type != EVENT_NONE); 1157 } while (type != EVENT_NONE);
1082 1158
1083 if (!current_op && !current_exp) 1159 if (!current_op && !current_exp)
1084 goto fail_print; 1160 goto fail_syntax;
1085 1161
1086 if (!current_op) 1162 if (!current_op)
1087 current_op = current_exp; 1163 current_op = current_exp;
1088 1164
1089 current_op = collapse_tree(current_op); 1165 ret = collapse_tree(current_op, parg, error_str);
1166 if (ret < 0)
1167 goto fail;
1090 1168
1091 *parg = current_op; 1169 *parg = current_op;
1092 1170
1093 return 0; 1171 return 0;
1094 1172
1095 fail_print: 1173 fail_alloc:
1174 show_error(error_str, "failed to allocate filter arg");
1175 ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
1176 goto fail;
1177 fail_syntax:
1096 show_error(error_str, "Syntax error"); 1178 show_error(error_str, "Syntax error");
1179 ret = PEVENT_ERRNO__SYNTAX_ERROR;
1097 fail: 1180 fail:
1098 free_arg(current_op); 1181 free_arg(current_op);
1099 free_arg(current_exp); 1182 free_arg(current_exp);
1100 free_arg(arg); 1183 free_arg(arg);
1101 free(token); 1184 free(token);
1102 return -1; 1185 return ret;
1103} 1186}
1104 1187
1105static int 1188static enum pevent_errno
1106process_event(struct event_format *event, const char *filter_str, 1189process_event(struct event_format *event, const char *filter_str,
1107 struct filter_arg **parg, char **error_str) 1190 struct filter_arg **parg, char *error_str)
1108{ 1191{
1109 int ret; 1192 int ret;
1110 1193
1111 pevent_buffer_init(filter_str, strlen(filter_str)); 1194 pevent_buffer_init(filter_str, strlen(filter_str));
1112 1195
1113 ret = process_filter(event, parg, error_str, 0); 1196 ret = process_filter(event, parg, error_str, 0);
1114 if (ret == 1) {
1115 show_error(error_str,
1116 "Unbalanced number of ')'");
1117 return -1;
1118 }
1119 if (ret < 0) 1197 if (ret < 0)
1120 return ret; 1198 return ret;
1121 1199
1122 /* If parg is NULL, then make it into FALSE */ 1200 /* If parg is NULL, then make it into FALSE */
1123 if (!*parg) { 1201 if (!*parg) {
1124 *parg = allocate_arg(); 1202 *parg = allocate_arg();
1203 if (*parg == NULL)
1204 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
1205
1125 (*parg)->type = FILTER_ARG_BOOLEAN; 1206 (*parg)->type = FILTER_ARG_BOOLEAN;
1126 (*parg)->boolean.value = FILTER_FALSE; 1207 (*parg)->boolean.value = FILTER_FALSE;
1127 } 1208 }
@@ -1129,13 +1210,13 @@ process_event(struct event_format *event, const char *filter_str,
1129 return 0; 1210 return 0;
1130} 1211}
1131 1212
1132static int filter_event(struct event_filter *filter, 1213static enum pevent_errno
1133 struct event_format *event, 1214filter_event(struct event_filter *filter, struct event_format *event,
1134 const char *filter_str, char **error_str) 1215 const char *filter_str, char *error_str)
1135{ 1216{
1136 struct filter_type *filter_type; 1217 struct filter_type *filter_type;
1137 struct filter_arg *arg; 1218 struct filter_arg *arg;
1138 int ret; 1219 enum pevent_errno ret;
1139 1220
1140 if (filter_str) { 1221 if (filter_str) {
1141 ret = process_event(event, filter_str, &arg, error_str); 1222 ret = process_event(event, filter_str, &arg, error_str);
@@ -1145,11 +1226,17 @@ static int filter_event(struct event_filter *filter,
1145 } else { 1226 } else {
1146 /* just add a TRUE arg */ 1227 /* just add a TRUE arg */
1147 arg = allocate_arg(); 1228 arg = allocate_arg();
1229 if (arg == NULL)
1230 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
1231
1148 arg->type = FILTER_ARG_BOOLEAN; 1232 arg->type = FILTER_ARG_BOOLEAN;
1149 arg->boolean.value = FILTER_TRUE; 1233 arg->boolean.value = FILTER_TRUE;
1150 } 1234 }
1151 1235
1152 filter_type = add_filter_type(filter, event->id); 1236 filter_type = add_filter_type(filter, event->id);
1237 if (filter_type == NULL)
1238 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
1239
1153 if (filter_type->filter) 1240 if (filter_type->filter)
1154 free_arg(filter_type->filter); 1241 free_arg(filter_type->filter);
1155 filter_type->filter = arg; 1242 filter_type->filter = arg;
@@ -1157,22 +1244,24 @@ static int filter_event(struct event_filter *filter,
1157 return 0; 1244 return 0;
1158} 1245}
1159 1246
1247static void filter_init_error_buf(struct event_filter *filter)
1248{
1249 /* clear buffer to reset show error */
1250 pevent_buffer_init("", 0);
1251 filter->error_buffer[0] = '\0';
1252}
1253
1160/** 1254/**
1161 * pevent_filter_add_filter_str - add a new filter 1255 * pevent_filter_add_filter_str - add a new filter
1162 * @filter: the event filter to add to 1256 * @filter: the event filter to add to
1163 * @filter_str: the filter string that contains the filter 1257 * @filter_str: the filter string that contains the filter
1164 * @error_str: string containing reason for failed filter
1165 *
1166 * Returns 0 if the filter was successfully added
1167 * -1 if there was an error.
1168 * 1258 *
1169 * On error, if @error_str points to a string pointer, 1259 * Returns 0 if the filter was successfully added or a
1170 * it is set to the reason that the filter failed. 1260 * negative error code. Use pevent_filter_strerror() to see
1171 * This string must be freed with "free". 1261 * actual error message in case of error.
1172 */ 1262 */
1173int pevent_filter_add_filter_str(struct event_filter *filter, 1263enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
1174 const char *filter_str, 1264 const char *filter_str)
1175 char **error_str)
1176{ 1265{
1177 struct pevent *pevent = filter->pevent; 1266 struct pevent *pevent = filter->pevent;
1178 struct event_list *event; 1267 struct event_list *event;
@@ -1183,15 +1272,11 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
1183 char *event_name = NULL; 1272 char *event_name = NULL;
1184 char *sys_name = NULL; 1273 char *sys_name = NULL;
1185 char *sp; 1274 char *sp;
1186 int rtn = 0; 1275 enum pevent_errno rtn = 0; /* PEVENT_ERRNO__SUCCESS */
1187 int len; 1276 int len;
1188 int ret; 1277 int ret;
1189 1278
1190 /* clear buffer to reset show error */ 1279 filter_init_error_buf(filter);
1191 pevent_buffer_init("", 0);
1192
1193 if (error_str)
1194 *error_str = NULL;
1195 1280
1196 filter_start = strchr(filter_str, ':'); 1281 filter_start = strchr(filter_str, ':');
1197 if (filter_start) 1282 if (filter_start)
@@ -1199,7 +1284,6 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
1199 else 1284 else
1200 len = strlen(filter_str); 1285 len = strlen(filter_str);
1201 1286
1202
1203 do { 1287 do {
1204 next_event = strchr(filter_str, ','); 1288 next_event = strchr(filter_str, ',');
1205 if (next_event && 1289 if (next_event &&
@@ -1210,7 +1294,12 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
1210 else 1294 else
1211 len = strlen(filter_str); 1295 len = strlen(filter_str);
1212 1296
1213 this_event = malloc_or_die(len + 1); 1297 this_event = malloc(len + 1);
1298 if (this_event == NULL) {
1299 /* This can only happen when events is NULL, but still */
1300 free_events(events);
1301 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
1302 }
1214 memcpy(this_event, filter_str, len); 1303 memcpy(this_event, filter_str, len);
1215 this_event[len] = 0; 1304 this_event[len] = 0;
1216 1305
@@ -1223,27 +1312,18 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
1223 event_name = strtok_r(NULL, "/", &sp); 1312 event_name = strtok_r(NULL, "/", &sp);
1224 1313
1225 if (!sys_name) { 1314 if (!sys_name) {
1226 show_error(error_str, "No filter found");
1227 /* This can only happen when events is NULL, but still */ 1315 /* This can only happen when events is NULL, but still */
1228 free_events(events); 1316 free_events(events);
1229 free(this_event); 1317 free(this_event);
1230 return -1; 1318 return PEVENT_ERRNO__FILTER_NOT_FOUND;
1231 } 1319 }
1232 1320
1233 /* Find this event */ 1321 /* Find this event */
1234 ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); 1322 ret = find_event(pevent, &events, strim(sys_name), strim(event_name));
1235 if (ret < 0) { 1323 if (ret < 0) {
1236 if (event_name)
1237 show_error(error_str,
1238 "No event found under '%s.%s'",
1239 sys_name, event_name);
1240 else
1241 show_error(error_str,
1242 "No event found under '%s'",
1243 sys_name);
1244 free_events(events); 1324 free_events(events);
1245 free(this_event); 1325 free(this_event);
1246 return -1; 1326 return ret;
1247 } 1327 }
1248 free(this_event); 1328 free(this_event);
1249 } while (filter_str); 1329 } while (filter_str);
@@ -1255,7 +1335,7 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
1255 /* filter starts here */ 1335 /* filter starts here */
1256 for (event = events; event; event = event->next) { 1336 for (event = events; event; event = event->next) {
1257 ret = filter_event(filter, event->event, filter_start, 1337 ret = filter_event(filter, event->event, filter_start,
1258 error_str); 1338 filter->error_buffer);
1259 /* Failures are returned if a parse error happened */ 1339 /* Failures are returned if a parse error happened */
1260 if (ret < 0) 1340 if (ret < 0)
1261 rtn = ret; 1341 rtn = ret;
@@ -1263,8 +1343,10 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
1263 if (ret >= 0 && pevent->test_filters) { 1343 if (ret >= 0 && pevent->test_filters) {
1264 char *test; 1344 char *test;
1265 test = pevent_filter_make_string(filter, event->event->id); 1345 test = pevent_filter_make_string(filter, event->event->id);
1266 printf(" '%s: %s'\n", event->event->name, test); 1346 if (test) {
1267 free(test); 1347 printf(" '%s: %s'\n", event->event->name, test);
1348 free(test);
1349 }
1268 } 1350 }
1269 } 1351 }
1270 1352
@@ -1282,6 +1364,32 @@ static void free_filter_type(struct filter_type *filter_type)
1282} 1364}
1283 1365
1284/** 1366/**
1367 * pevent_filter_strerror - fill error message in a buffer
1368 * @filter: the event filter contains error
1369 * @err: the error code
1370 * @buf: the buffer to be filled in
1371 * @buflen: the size of the buffer
1372 *
1373 * Returns 0 if message was filled successfully, -1 if error
1374 */
1375int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err,
1376 char *buf, size_t buflen)
1377{
1378 if (err <= __PEVENT_ERRNO__START || err >= __PEVENT_ERRNO__END)
1379 return -1;
1380
1381 if (strlen(filter->error_buffer) > 0) {
1382 size_t len = snprintf(buf, buflen, "%s", filter->error_buffer);
1383
1384 if (len > buflen)
1385 return -1;
1386 return 0;
1387 }
1388
1389 return pevent_strerror(filter->pevent, err, buf, buflen);
1390}
1391
1392/**
1285 * pevent_filter_remove_event - remove a filter for an event 1393 * pevent_filter_remove_event - remove a filter for an event
1286 * @filter: the event filter to remove from 1394 * @filter: the event filter to remove from
1287 * @event_id: the event to remove a filter for 1395 * @event_id: the event to remove a filter for
@@ -1374,6 +1482,9 @@ static int copy_filter_type(struct event_filter *filter,
1374 if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) { 1482 if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) {
1375 /* Add trivial event */ 1483 /* Add trivial event */
1376 arg = allocate_arg(); 1484 arg = allocate_arg();
1485 if (arg == NULL)
1486 return -1;
1487
1377 arg->type = FILTER_ARG_BOOLEAN; 1488 arg->type = FILTER_ARG_BOOLEAN;
1378 if (strcmp(str, "TRUE") == 0) 1489 if (strcmp(str, "TRUE") == 0)
1379 arg->boolean.value = 1; 1490 arg->boolean.value = 1;
@@ -1381,6 +1492,9 @@ static int copy_filter_type(struct event_filter *filter,
1381 arg->boolean.value = 0; 1492 arg->boolean.value = 0;
1382 1493
1383 filter_type = add_filter_type(filter, event->id); 1494 filter_type = add_filter_type(filter, event->id);
1495 if (filter_type == NULL)
1496 return -1;
1497
1384 filter_type->filter = arg; 1498 filter_type->filter = arg;
1385 1499
1386 free(str); 1500 free(str);
@@ -1482,8 +1596,10 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source
1482 * @type: remove only true, false, or both 1596 * @type: remove only true, false, or both
1483 * 1597 *
1484 * Removes filters that only contain a TRUE or FALES boolean arg. 1598 * Removes filters that only contain a TRUE or FALES boolean arg.
1599 *
1600 * Returns 0 on success and -1 if there was a problem.
1485 */ 1601 */
1486void pevent_filter_clear_trivial(struct event_filter *filter, 1602int pevent_filter_clear_trivial(struct event_filter *filter,
1487 enum filter_trivial_type type) 1603 enum filter_trivial_type type)
1488{ 1604{
1489 struct filter_type *filter_type; 1605 struct filter_type *filter_type;
@@ -1492,13 +1608,15 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
1492 int i; 1608 int i;
1493 1609
1494 if (!filter->filters) 1610 if (!filter->filters)
1495 return; 1611 return 0;
1496 1612
1497 /* 1613 /*
1498 * Two steps, first get all ids with trivial filters. 1614 * Two steps, first get all ids with trivial filters.
1499 * then remove those ids. 1615 * then remove those ids.
1500 */ 1616 */
1501 for (i = 0; i < filter->filters; i++) { 1617 for (i = 0; i < filter->filters; i++) {
1618 int *new_ids;
1619
1502 filter_type = &filter->event_filters[i]; 1620 filter_type = &filter->event_filters[i];
1503 if (filter_type->filter->type != FILTER_ARG_BOOLEAN) 1621 if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
1504 continue; 1622 continue;
@@ -1513,19 +1631,24 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
1513 break; 1631 break;
1514 } 1632 }
1515 1633
1516 ids = realloc(ids, sizeof(*ids) * (count + 1)); 1634 new_ids = realloc(ids, sizeof(*ids) * (count + 1));
1517 if (!ids) 1635 if (!new_ids) {
1518 die("Can't allocate ids"); 1636 free(ids);
1637 return -1;
1638 }
1639
1640 ids = new_ids;
1519 ids[count++] = filter_type->event_id; 1641 ids[count++] = filter_type->event_id;
1520 } 1642 }
1521 1643
1522 if (!count) 1644 if (!count)
1523 return; 1645 return 0;
1524 1646
1525 for (i = 0; i < count; i++) 1647 for (i = 0; i < count; i++)
1526 pevent_filter_remove_event(filter, ids[i]); 1648 pevent_filter_remove_event(filter, ids[i]);
1527 1649
1528 free(ids); 1650 free(ids);
1651 return 0;
1529} 1652}
1530 1653
1531/** 1654/**
@@ -1565,8 +1688,8 @@ int pevent_filter_event_has_trivial(struct event_filter *filter,
1565 } 1688 }
1566} 1689}
1567 1690
1568static int test_filter(struct event_format *event, 1691static int test_filter(struct event_format *event, struct filter_arg *arg,
1569 struct filter_arg *arg, struct pevent_record *record); 1692 struct pevent_record *record, enum pevent_errno *err);
1570 1693
1571static const char * 1694static const char *
1572get_comm(struct event_format *event, struct pevent_record *record) 1695get_comm(struct event_format *event, struct pevent_record *record)
@@ -1612,15 +1735,24 @@ get_value(struct event_format *event,
1612} 1735}
1613 1736
1614static unsigned long long 1737static unsigned long long
1615get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record); 1738get_arg_value(struct event_format *event, struct filter_arg *arg,
1739 struct pevent_record *record, enum pevent_errno *err);
1616 1740
1617static unsigned long long 1741static unsigned long long
1618get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) 1742get_exp_value(struct event_format *event, struct filter_arg *arg,
1743 struct pevent_record *record, enum pevent_errno *err)
1619{ 1744{
1620 unsigned long long lval, rval; 1745 unsigned long long lval, rval;
1621 1746
1622 lval = get_arg_value(event, arg->exp.left, record); 1747 lval = get_arg_value(event, arg->exp.left, record, err);
1623 rval = get_arg_value(event, arg->exp.right, record); 1748 rval = get_arg_value(event, arg->exp.right, record, err);
1749
1750 if (*err) {
1751 /*
1752 * There was an error, no need to process anymore.
1753 */
1754 return 0;
1755 }
1624 1756
1625 switch (arg->exp.type) { 1757 switch (arg->exp.type) {
1626 case FILTER_EXP_ADD: 1758 case FILTER_EXP_ADD:
@@ -1655,39 +1787,51 @@ get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_
1655 1787
1656 case FILTER_EXP_NOT: 1788 case FILTER_EXP_NOT:
1657 default: 1789 default:
1658 die("error in exp"); 1790 if (!*err)
1791 *err = PEVENT_ERRNO__INVALID_EXP_TYPE;
1659 } 1792 }
1660 return 0; 1793 return 0;
1661} 1794}
1662 1795
1663static unsigned long long 1796static unsigned long long
1664get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) 1797get_arg_value(struct event_format *event, struct filter_arg *arg,
1798 struct pevent_record *record, enum pevent_errno *err)
1665{ 1799{
1666 switch (arg->type) { 1800 switch (arg->type) {
1667 case FILTER_ARG_FIELD: 1801 case FILTER_ARG_FIELD:
1668 return get_value(event, arg->field.field, record); 1802 return get_value(event, arg->field.field, record);
1669 1803
1670 case FILTER_ARG_VALUE: 1804 case FILTER_ARG_VALUE:
1671 if (arg->value.type != FILTER_NUMBER) 1805 if (arg->value.type != FILTER_NUMBER) {
1672 die("must have number field!"); 1806 if (!*err)
1807 *err = PEVENT_ERRNO__NOT_A_NUMBER;
1808 }
1673 return arg->value.val; 1809 return arg->value.val;
1674 1810
1675 case FILTER_ARG_EXP: 1811 case FILTER_ARG_EXP:
1676 return get_exp_value(event, arg, record); 1812 return get_exp_value(event, arg, record, err);
1677 1813
1678 default: 1814 default:
1679 die("oops in filter"); 1815 if (!*err)
1816 *err = PEVENT_ERRNO__INVALID_ARG_TYPE;
1680 } 1817 }
1681 return 0; 1818 return 0;
1682} 1819}
1683 1820
1684static int test_num(struct event_format *event, 1821static int test_num(struct event_format *event, struct filter_arg *arg,
1685 struct filter_arg *arg, struct pevent_record *record) 1822 struct pevent_record *record, enum pevent_errno *err)
1686{ 1823{
1687 unsigned long long lval, rval; 1824 unsigned long long lval, rval;
1688 1825
1689 lval = get_arg_value(event, arg->num.left, record); 1826 lval = get_arg_value(event, arg->num.left, record, err);
1690 rval = get_arg_value(event, arg->num.right, record); 1827 rval = get_arg_value(event, arg->num.right, record, err);
1828
1829 if (*err) {
1830 /*
1831 * There was an error, no need to process anymore.
1832 */
1833 return 0;
1834 }
1691 1835
1692 switch (arg->num.type) { 1836 switch (arg->num.type) {
1693 case FILTER_CMP_EQ: 1837 case FILTER_CMP_EQ:
@@ -1709,7 +1853,8 @@ static int test_num(struct event_format *event,
1709 return lval <= rval; 1853 return lval <= rval;
1710 1854
1711 default: 1855 default:
1712 /* ?? */ 1856 if (!*err)
1857 *err = PEVENT_ERRNO__ILLEGAL_INTEGER_CMP;
1713 return 0; 1858 return 0;
1714 } 1859 }
1715} 1860}
@@ -1756,8 +1901,8 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r
1756 return val; 1901 return val;
1757} 1902}
1758 1903
1759static int test_str(struct event_format *event, 1904static int test_str(struct event_format *event, struct filter_arg *arg,
1760 struct filter_arg *arg, struct pevent_record *record) 1905 struct pevent_record *record, enum pevent_errno *err)
1761{ 1906{
1762 const char *val; 1907 const char *val;
1763 1908
@@ -1781,48 +1926,57 @@ static int test_str(struct event_format *event,
1781 return regexec(&arg->str.reg, val, 0, NULL, 0); 1926 return regexec(&arg->str.reg, val, 0, NULL, 0);
1782 1927
1783 default: 1928 default:
1784 /* ?? */ 1929 if (!*err)
1930 *err = PEVENT_ERRNO__ILLEGAL_STRING_CMP;
1785 return 0; 1931 return 0;
1786 } 1932 }
1787} 1933}
1788 1934
1789static int test_op(struct event_format *event, 1935static int test_op(struct event_format *event, struct filter_arg *arg,
1790 struct filter_arg *arg, struct pevent_record *record) 1936 struct pevent_record *record, enum pevent_errno *err)
1791{ 1937{
1792 switch (arg->op.type) { 1938 switch (arg->op.type) {
1793 case FILTER_OP_AND: 1939 case FILTER_OP_AND:
1794 return test_filter(event, arg->op.left, record) && 1940 return test_filter(event, arg->op.left, record, err) &&
1795 test_filter(event, arg->op.right, record); 1941 test_filter(event, arg->op.right, record, err);
1796 1942
1797 case FILTER_OP_OR: 1943 case FILTER_OP_OR:
1798 return test_filter(event, arg->op.left, record) || 1944 return test_filter(event, arg->op.left, record, err) ||
1799 test_filter(event, arg->op.right, record); 1945 test_filter(event, arg->op.right, record, err);
1800 1946
1801 case FILTER_OP_NOT: 1947 case FILTER_OP_NOT:
1802 return !test_filter(event, arg->op.right, record); 1948 return !test_filter(event, arg->op.right, record, err);
1803 1949
1804 default: 1950 default:
1805 /* ?? */ 1951 if (!*err)
1952 *err = PEVENT_ERRNO__INVALID_OP_TYPE;
1806 return 0; 1953 return 0;
1807 } 1954 }
1808} 1955}
1809 1956
1810static int test_filter(struct event_format *event, 1957static int test_filter(struct event_format *event, struct filter_arg *arg,
1811 struct filter_arg *arg, struct pevent_record *record) 1958 struct pevent_record *record, enum pevent_errno *err)
1812{ 1959{
1960 if (*err) {
1961 /*
1962 * There was an error, no need to process anymore.
1963 */
1964 return 0;
1965 }
1966
1813 switch (arg->type) { 1967 switch (arg->type) {
1814 case FILTER_ARG_BOOLEAN: 1968 case FILTER_ARG_BOOLEAN:
1815 /* easy case */ 1969 /* easy case */
1816 return arg->boolean.value; 1970 return arg->boolean.value;
1817 1971
1818 case FILTER_ARG_OP: 1972 case FILTER_ARG_OP:
1819 return test_op(event, arg, record); 1973 return test_op(event, arg, record, err);
1820 1974
1821 case FILTER_ARG_NUM: 1975 case FILTER_ARG_NUM:
1822 return test_num(event, arg, record); 1976 return test_num(event, arg, record, err);
1823 1977
1824 case FILTER_ARG_STR: 1978 case FILTER_ARG_STR:
1825 return test_str(event, arg, record); 1979 return test_str(event, arg, record, err);
1826 1980
1827 case FILTER_ARG_EXP: 1981 case FILTER_ARG_EXP:
1828 case FILTER_ARG_VALUE: 1982 case FILTER_ARG_VALUE:
@@ -1831,11 +1985,11 @@ static int test_filter(struct event_format *event,
1831 * Expressions, fields and values evaluate 1985 * Expressions, fields and values evaluate
1832 * to true if they return non zero 1986 * to true if they return non zero
1833 */ 1987 */
1834 return !!get_arg_value(event, arg, record); 1988 return !!get_arg_value(event, arg, record, err);
1835 1989
1836 default: 1990 default:
1837 die("oops!"); 1991 if (!*err)
1838 /* ?? */ 1992 *err = PEVENT_ERRNO__INVALID_ARG_TYPE;
1839 return 0; 1993 return 0;
1840 } 1994 }
1841} 1995}
@@ -1848,8 +2002,7 @@ static int test_filter(struct event_format *event,
1848 * Returns 1 if filter found for @event_id 2002 * Returns 1 if filter found for @event_id
1849 * otherwise 0; 2003 * otherwise 0;
1850 */ 2004 */
1851int pevent_event_filtered(struct event_filter *filter, 2005int pevent_event_filtered(struct event_filter *filter, int event_id)
1852 int event_id)
1853{ 2006{
1854 struct filter_type *filter_type; 2007 struct filter_type *filter_type;
1855 2008
@@ -1866,31 +2019,38 @@ int pevent_event_filtered(struct event_filter *filter,
1866 * @filter: filter struct with filter information 2019 * @filter: filter struct with filter information
1867 * @record: the record to test against the filter 2020 * @record: the record to test against the filter
1868 * 2021 *
1869 * Returns: 2022 * Returns: match result or error code (prefixed with PEVENT_ERRNO__)
1870 * 1 - filter found for event and @record matches 2023 * FILTER_MATCH - filter found for event and @record matches
1871 * 0 - filter found for event and @record does not match 2024 * FILTER_MISS - filter found for event and @record does not match
1872 * -1 - no filter found for @record's event 2025 * FILTER_NOT_FOUND - no filter found for @record's event
1873 * -2 - if no filters exist 2026 * NO_FILTER - if no filters exist
2027 * otherwise - error occurred during test
1874 */ 2028 */
1875int pevent_filter_match(struct event_filter *filter, 2029enum pevent_errno pevent_filter_match(struct event_filter *filter,
1876 struct pevent_record *record) 2030 struct pevent_record *record)
1877{ 2031{
1878 struct pevent *pevent = filter->pevent; 2032 struct pevent *pevent = filter->pevent;
1879 struct filter_type *filter_type; 2033 struct filter_type *filter_type;
1880 int event_id; 2034 int event_id;
2035 int ret;
2036 enum pevent_errno err = 0;
2037
2038 filter_init_error_buf(filter);
1881 2039
1882 if (!filter->filters) 2040 if (!filter->filters)
1883 return FILTER_NONE; 2041 return PEVENT_ERRNO__NO_FILTER;
1884 2042
1885 event_id = pevent_data_type(pevent, record); 2043 event_id = pevent_data_type(pevent, record);
1886 2044
1887 filter_type = find_filter_type(filter, event_id); 2045 filter_type = find_filter_type(filter, event_id);
1888
1889 if (!filter_type) 2046 if (!filter_type)
1890 return FILTER_NOEXIST; 2047 return PEVENT_ERRNO__FILTER_NOT_FOUND;
2048
2049 ret = test_filter(filter_type->event, filter_type->filter, record, &err);
2050 if (err)
2051 return err;
1891 2052
1892 return test_filter(filter_type->event, filter_type->filter, record) ? 2053 return ret ? PEVENT_ERRNO__FILTER_MATCH : PEVENT_ERRNO__FILTER_MISS;
1893 FILTER_MATCH : FILTER_MISS;
1894} 2054}
1895 2055
1896static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) 2056static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
@@ -1902,7 +2062,6 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
1902 int left_val = -1; 2062 int left_val = -1;
1903 int right_val = -1; 2063 int right_val = -1;
1904 int val; 2064 int val;
1905 int len;
1906 2065
1907 switch (arg->op.type) { 2066 switch (arg->op.type) {
1908 case FILTER_OP_AND: 2067 case FILTER_OP_AND:
@@ -1949,11 +2108,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
1949 default: 2108 default:
1950 break; 2109 break;
1951 } 2110 }
1952 str = malloc_or_die(6); 2111 asprintf(&str, val ? "TRUE" : "FALSE");
1953 if (val)
1954 strcpy(str, "TRUE");
1955 else
1956 strcpy(str, "FALSE");
1957 break; 2112 break;
1958 } 2113 }
1959 } 2114 }
@@ -1971,10 +2126,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
1971 break; 2126 break;
1972 } 2127 }
1973 2128
1974 len = strlen(left) + strlen(right) + strlen(op) + 10; 2129 asprintf(&str, "(%s) %s (%s)", left, op, right);
1975 str = malloc_or_die(len);
1976 snprintf(str, len, "(%s) %s (%s)",
1977 left, op, right);
1978 break; 2130 break;
1979 2131
1980 case FILTER_OP_NOT: 2132 case FILTER_OP_NOT:
@@ -1990,16 +2142,10 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
1990 right_val = 0; 2142 right_val = 0;
1991 if (right_val >= 0) { 2143 if (right_val >= 0) {
1992 /* just return the opposite */ 2144 /* just return the opposite */
1993 str = malloc_or_die(6); 2145 asprintf(&str, right_val ? "FALSE" : "TRUE");
1994 if (right_val)
1995 strcpy(str, "FALSE");
1996 else
1997 strcpy(str, "TRUE");
1998 break; 2146 break;
1999 } 2147 }
2000 len = strlen(right) + strlen(op) + 3; 2148 asprintf(&str, "%s(%s)", op, right);
2001 str = malloc_or_die(len);
2002 snprintf(str, len, "%s(%s)", op, right);
2003 break; 2149 break;
2004 2150
2005 default: 2151 default:
@@ -2013,11 +2159,9 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
2013 2159
2014static char *val_to_str(struct event_filter *filter, struct filter_arg *arg) 2160static char *val_to_str(struct event_filter *filter, struct filter_arg *arg)
2015{ 2161{
2016 char *str; 2162 char *str = NULL;
2017
2018 str = malloc_or_die(30);
2019 2163
2020 snprintf(str, 30, "%lld", arg->value.val); 2164 asprintf(&str, "%lld", arg->value.val);
2021 2165
2022 return str; 2166 return str;
2023} 2167}
@@ -2033,7 +2177,6 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
2033 char *rstr; 2177 char *rstr;
2034 char *op; 2178 char *op;
2035 char *str = NULL; 2179 char *str = NULL;
2036 int len;
2037 2180
2038 lstr = arg_to_str(filter, arg->exp.left); 2181 lstr = arg_to_str(filter, arg->exp.left);
2039 rstr = arg_to_str(filter, arg->exp.right); 2182 rstr = arg_to_str(filter, arg->exp.right);
@@ -2072,12 +2215,11 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
2072 op = "^"; 2215 op = "^";
2073 break; 2216 break;
2074 default: 2217 default:
2075 die("oops in exp"); 2218 op = "[ERROR IN EXPRESSION TYPE]";
2219 break;
2076 } 2220 }
2077 2221
2078 len = strlen(op) + strlen(lstr) + strlen(rstr) + 4; 2222 asprintf(&str, "%s %s %s", lstr, op, rstr);
2079 str = malloc_or_die(len);
2080 snprintf(str, len, "%s %s %s", lstr, op, rstr);
2081out: 2223out:
2082 free(lstr); 2224 free(lstr);
2083 free(rstr); 2225 free(rstr);
@@ -2091,7 +2233,6 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
2091 char *rstr; 2233 char *rstr;
2092 char *str = NULL; 2234 char *str = NULL;
2093 char *op = NULL; 2235 char *op = NULL;
2094 int len;
2095 2236
2096 lstr = arg_to_str(filter, arg->num.left); 2237 lstr = arg_to_str(filter, arg->num.left);
2097 rstr = arg_to_str(filter, arg->num.right); 2238 rstr = arg_to_str(filter, arg->num.right);
@@ -2122,10 +2263,7 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
2122 if (!op) 2263 if (!op)
2123 op = "<="; 2264 op = "<=";
2124 2265
2125 len = strlen(lstr) + strlen(op) + strlen(rstr) + 4; 2266 asprintf(&str, "%s %s %s", lstr, op, rstr);
2126 str = malloc_or_die(len);
2127 sprintf(str, "%s %s %s", lstr, op, rstr);
2128
2129 break; 2267 break;
2130 2268
2131 default: 2269 default:
@@ -2143,7 +2281,6 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
2143{ 2281{
2144 char *str = NULL; 2282 char *str = NULL;
2145 char *op = NULL; 2283 char *op = NULL;
2146 int len;
2147 2284
2148 switch (arg->str.type) { 2285 switch (arg->str.type) {
2149 case FILTER_CMP_MATCH: 2286 case FILTER_CMP_MATCH:
@@ -2161,12 +2298,8 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
2161 if (!op) 2298 if (!op)
2162 op = "!~"; 2299 op = "!~";
2163 2300
2164 len = strlen(arg->str.field->name) + strlen(op) + 2301 asprintf(&str, "%s %s \"%s\"",
2165 strlen(arg->str.val) + 6; 2302 arg->str.field->name, op, arg->str.val);
2166 str = malloc_or_die(len);
2167 snprintf(str, len, "%s %s \"%s\"",
2168 arg->str.field->name,
2169 op, arg->str.val);
2170 break; 2303 break;
2171 2304
2172 default: 2305 default:
@@ -2178,15 +2311,11 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
2178 2311
2179static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) 2312static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
2180{ 2313{
2181 char *str; 2314 char *str = NULL;
2182 2315
2183 switch (arg->type) { 2316 switch (arg->type) {
2184 case FILTER_ARG_BOOLEAN: 2317 case FILTER_ARG_BOOLEAN:
2185 str = malloc_or_die(6); 2318 asprintf(&str, arg->boolean.value ? "TRUE" : "FALSE");
2186 if (arg->boolean.value)
2187 strcpy(str, "TRUE");
2188 else
2189 strcpy(str, "FALSE");
2190 return str; 2319 return str;
2191 2320
2192 case FILTER_ARG_OP: 2321 case FILTER_ARG_OP:
@@ -2221,7 +2350,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
2221 * 2350 *
2222 * Returns a string that displays the filter contents. 2351 * Returns a string that displays the filter contents.
2223 * This string must be freed with free(str). 2352 * This string must be freed with free(str).
2224 * NULL is returned if no filter is found. 2353 * NULL is returned if no filter is found or allocation failed.
2225 */ 2354 */
2226char * 2355char *
2227pevent_filter_make_string(struct event_filter *filter, int event_id) 2356pevent_filter_make_string(struct event_filter *filter, int event_id)
diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c
index bba701cf10e6..eda07fa31dca 100644
--- a/tools/lib/traceevent/parse-utils.c
+++ b/tools/lib/traceevent/parse-utils.c
@@ -25,40 +25,6 @@
25 25
26#define __weak __attribute__((weak)) 26#define __weak __attribute__((weak))
27 27
28void __vdie(const char *fmt, va_list ap)
29{
30 int ret = errno;
31
32 if (errno)
33 perror("trace-cmd");
34 else
35 ret = -1;
36
37 fprintf(stderr, " ");
38 vfprintf(stderr, fmt, ap);
39
40 fprintf(stderr, "\n");
41 exit(ret);
42}
43
44void __die(const char *fmt, ...)
45{
46 va_list ap;
47
48 va_start(ap, fmt);
49 __vdie(fmt, ap);
50 va_end(ap);
51}
52
53void __weak die(const char *fmt, ...)
54{
55 va_list ap;
56
57 va_start(ap, fmt);
58 __vdie(fmt, ap);
59 va_end(ap);
60}
61
62void __vwarning(const char *fmt, va_list ap) 28void __vwarning(const char *fmt, va_list ap)
63{ 29{
64 if (errno) 30 if (errno)
@@ -117,13 +83,3 @@ void __weak pr_stat(const char *fmt, ...)
117 __vpr_stat(fmt, ap); 83 __vpr_stat(fmt, ap);
118 va_end(ap); 84 va_end(ap);
119} 85}
120
121void __weak *malloc_or_die(unsigned int size)
122{
123 void *data;
124
125 data = malloc(size);
126 if (!data)
127 die("malloc");
128 return data;
129}
diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c
new file mode 100644
index 000000000000..c066b25905f8
--- /dev/null
+++ b/tools/lib/traceevent/plugin_cfg80211.c
@@ -0,0 +1,30 @@
1#include <stdio.h>
2#include <string.h>
3#include <inttypes.h>
4#include <endian.h>
5#include "event-parse.h"
6
7static unsigned long long
8process___le16_to_cpup(struct trace_seq *s,
9 unsigned long long *args)
10{
11 uint16_t *val = (uint16_t *) (unsigned long) args[0];
12 return val ? (long long) le16toh(*val) : 0;
13}
14
15int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
16{
17 pevent_register_print_function(pevent,
18 process___le16_to_cpup,
19 PEVENT_FUNC_ARG_INT,
20 "__le16_to_cpup",
21 PEVENT_FUNC_ARG_PTR,
22 PEVENT_FUNC_ARG_VOID);
23 return 0;
24}
25
26void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
27{
28 pevent_unregister_print_function(pevent, process___le16_to_cpup,
29 "__le16_to_cpup");
30}
diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c
new file mode 100644
index 000000000000..80ba4ff1fe84
--- /dev/null
+++ b/tools/lib/traceevent/plugin_function.c
@@ -0,0 +1,163 @@
1/*
2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "event-parse.h"
25#include "event-utils.h"
26
27static struct func_stack {
28 int size;
29 char **stack;
30} *fstack;
31
32static int cpus = -1;
33
34#define STK_BLK 10
35
36static void add_child(struct func_stack *stack, const char *child, int pos)
37{
38 int i;
39
40 if (!child)
41 return;
42
43 if (pos < stack->size)
44 free(stack->stack[pos]);
45 else {
46 char **ptr;
47
48 ptr = realloc(stack->stack, sizeof(char *) *
49 (stack->size + STK_BLK));
50 if (!ptr) {
51 warning("could not allocate plugin memory\n");
52 return;
53 }
54
55 stack->stack = ptr;
56
57 for (i = stack->size; i < stack->size + STK_BLK; i++)
58 stack->stack[i] = NULL;
59 stack->size += STK_BLK;
60 }
61
62 stack->stack[pos] = strdup(child);
63}
64
65static int add_and_get_index(const char *parent, const char *child, int cpu)
66{
67 int i;
68
69 if (cpu < 0)
70 return 0;
71
72 if (cpu > cpus) {
73 struct func_stack *ptr;
74
75 ptr = realloc(fstack, sizeof(*fstack) * (cpu + 1));
76 if (!ptr) {
77 warning("could not allocate plugin memory\n");
78 return 0;
79 }
80
81 fstack = ptr;
82
83 /* Account for holes in the cpu count */
84 for (i = cpus + 1; i <= cpu; i++)
85 memset(&fstack[i], 0, sizeof(fstack[i]));
86 cpus = cpu;
87 }
88
89 for (i = 0; i < fstack[cpu].size && fstack[cpu].stack[i]; i++) {
90 if (strcmp(parent, fstack[cpu].stack[i]) == 0) {
91 add_child(&fstack[cpu], child, i+1);
92 return i;
93 }
94 }
95
96 /* Not found */
97 add_child(&fstack[cpu], parent, 0);
98 add_child(&fstack[cpu], child, 1);
99 return 0;
100}
101
102static int function_handler(struct trace_seq *s, struct pevent_record *record,
103 struct event_format *event, void *context)
104{
105 struct pevent *pevent = event->pevent;
106 unsigned long long function;
107 unsigned long long pfunction;
108 const char *func;
109 const char *parent;
110 int index;
111
112 if (pevent_get_field_val(s, event, "ip", record, &function, 1))
113 return trace_seq_putc(s, '!');
114
115 func = pevent_find_function(pevent, function);
116
117 if (pevent_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
118 return trace_seq_putc(s, '!');
119
120 parent = pevent_find_function(pevent, pfunction);
121
122 index = add_and_get_index(parent, func, record->cpu);
123
124 trace_seq_printf(s, "%*s", index*3, "");
125
126 if (func)
127 trace_seq_printf(s, "%s", func);
128 else
129 trace_seq_printf(s, "0x%llx", function);
130
131 trace_seq_printf(s, " <-- ");
132 if (parent)
133 trace_seq_printf(s, "%s", parent);
134 else
135 trace_seq_printf(s, "0x%llx", pfunction);
136
137 return 0;
138}
139
140int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
141{
142 pevent_register_event_handler(pevent, -1, "ftrace", "function",
143 function_handler, NULL);
144 return 0;
145}
146
147void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
148{
149 int i, x;
150
151 pevent_unregister_event_handler(pevent, -1, "ftrace", "function",
152 function_handler, NULL);
153
154 for (i = 0; i <= cpus; i++) {
155 for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++)
156 free(fstack[i].stack[x]);
157 free(fstack[i].stack);
158 }
159
160 free(fstack);
161 fstack = NULL;
162 cpus = -1;
163}
diff --git a/tools/lib/traceevent/plugin_hrtimer.c b/tools/lib/traceevent/plugin_hrtimer.c
new file mode 100644
index 000000000000..12bf14cc1152
--- /dev/null
+++ b/tools/lib/traceevent/plugin_hrtimer.c
@@ -0,0 +1,88 @@
1/*
2 * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 * Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net>
4 *
5 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation;
9 * version 2.1 of the License (not later!)
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, see <http://www.gnu.org/licenses>
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "event-parse.h"
26
27static int timer_expire_handler(struct trace_seq *s,
28 struct pevent_record *record,
29 struct event_format *event, void *context)
30{
31 trace_seq_printf(s, "hrtimer=");
32
33 if (pevent_print_num_field(s, "0x%llx", event, "timer",
34 record, 0) == -1)
35 pevent_print_num_field(s, "0x%llx", event, "hrtimer",
36 record, 1);
37
38 trace_seq_printf(s, " now=");
39
40 pevent_print_num_field(s, "%llu", event, "now", record, 1);
41
42 pevent_print_func_field(s, " function=%s", event, "function",
43 record, 0);
44 return 0;
45}
46
47static int timer_start_handler(struct trace_seq *s,
48 struct pevent_record *record,
49 struct event_format *event, void *context)
50{
51 trace_seq_printf(s, "hrtimer=");
52
53 if (pevent_print_num_field(s, "0x%llx", event, "timer",
54 record, 0) == -1)
55 pevent_print_num_field(s, "0x%llx", event, "hrtimer",
56 record, 1);
57
58 pevent_print_func_field(s, " function=%s", event, "function",
59 record, 0);
60
61 trace_seq_printf(s, " expires=");
62 pevent_print_num_field(s, "%llu", event, "expires", record, 1);
63
64 trace_seq_printf(s, " softexpires=");
65 pevent_print_num_field(s, "%llu", event, "softexpires", record, 1);
66 return 0;
67}
68
69int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
70{
71 pevent_register_event_handler(pevent, -1,
72 "timer", "hrtimer_expire_entry",
73 timer_expire_handler, NULL);
74
75 pevent_register_event_handler(pevent, -1, "timer", "hrtimer_start",
76 timer_start_handler, NULL);
77 return 0;
78}
79
80void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
81{
82 pevent_unregister_event_handler(pevent, -1,
83 "timer", "hrtimer_expire_entry",
84 timer_expire_handler, NULL);
85
86 pevent_unregister_event_handler(pevent, -1, "timer", "hrtimer_start",
87 timer_start_handler, NULL);
88}
diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugin_jbd2.c
new file mode 100644
index 000000000000..0db714c721be
--- /dev/null
+++ b/tools/lib/traceevent/plugin_jbd2.c
@@ -0,0 +1,77 @@
1/*
2 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "event-parse.h"
25
26#define MINORBITS 20
27#define MINORMASK ((1U << MINORBITS) - 1)
28
29#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
30#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
31
32static unsigned long long
33process_jbd2_dev_to_name(struct trace_seq *s,
34 unsigned long long *args)
35{
36 unsigned int dev = args[0];
37
38 trace_seq_printf(s, "%d:%d", MAJOR(dev), MINOR(dev));
39 return 0;
40}
41
42static unsigned long long
43process_jiffies_to_msecs(struct trace_seq *s,
44 unsigned long long *args)
45{
46 unsigned long long jiffies = args[0];
47
48 trace_seq_printf(s, "%lld", jiffies);
49 return jiffies;
50}
51
52int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
53{
54 pevent_register_print_function(pevent,
55 process_jbd2_dev_to_name,
56 PEVENT_FUNC_ARG_STRING,
57 "jbd2_dev_to_name",
58 PEVENT_FUNC_ARG_INT,
59 PEVENT_FUNC_ARG_VOID);
60
61 pevent_register_print_function(pevent,
62 process_jiffies_to_msecs,
63 PEVENT_FUNC_ARG_LONG,
64 "jiffies_to_msecs",
65 PEVENT_FUNC_ARG_LONG,
66 PEVENT_FUNC_ARG_VOID);
67 return 0;
68}
69
70void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
71{
72 pevent_unregister_print_function(pevent, process_jbd2_dev_to_name,
73 "jbd2_dev_to_name");
74
75 pevent_unregister_print_function(pevent, process_jiffies_to_msecs,
76 "jiffies_to_msecs");
77}
diff --git a/tools/lib/traceevent/plugin_kmem.c b/tools/lib/traceevent/plugin_kmem.c
new file mode 100644
index 000000000000..70650ff48d78
--- /dev/null
+++ b/tools/lib/traceevent/plugin_kmem.c
@@ -0,0 +1,94 @@
1/*
2 * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "event-parse.h"
25
26static int call_site_handler(struct trace_seq *s, struct pevent_record *record,
27 struct event_format *event, void *context)
28{
29 struct format_field *field;
30 unsigned long long val, addr;
31 void *data = record->data;
32 const char *func;
33
34 field = pevent_find_field(event, "call_site");
35 if (!field)
36 return 1;
37
38 if (pevent_read_number_field(field, data, &val))
39 return 1;
40
41 func = pevent_find_function(event->pevent, val);
42 if (!func)
43 return 1;
44
45 addr = pevent_find_function_address(event->pevent, val);
46
47 trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr));
48 return 1;
49}
50
51int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
52{
53 pevent_register_event_handler(pevent, -1, "kmem", "kfree",
54 call_site_handler, NULL);
55
56 pevent_register_event_handler(pevent, -1, "kmem", "kmalloc",
57 call_site_handler, NULL);
58
59 pevent_register_event_handler(pevent, -1, "kmem", "kmalloc_node",
60 call_site_handler, NULL);
61
62 pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
63 call_site_handler, NULL);
64
65 pevent_register_event_handler(pevent, -1, "kmem",
66 "kmem_cache_alloc_node",
67 call_site_handler, NULL);
68
69 pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_free",
70 call_site_handler, NULL);
71 return 0;
72}
73
74void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
75{
76 pevent_unregister_event_handler(pevent, -1, "kmem", "kfree",
77 call_site_handler, NULL);
78
79 pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc",
80 call_site_handler, NULL);
81
82 pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node",
83 call_site_handler, NULL);
84
85 pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
86 call_site_handler, NULL);
87
88 pevent_unregister_event_handler(pevent, -1, "kmem",
89 "kmem_cache_alloc_node",
90 call_site_handler, NULL);
91
92 pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free",
93 call_site_handler, NULL);
94}
diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c
new file mode 100644
index 000000000000..9e0e8c61b43b
--- /dev/null
+++ b/tools/lib/traceevent/plugin_kvm.c
@@ -0,0 +1,465 @@
1/*
2 * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <stdint.h>
24
25#include "event-parse.h"
26
27#ifdef HAVE_UDIS86
28
29#include <udis86.h>
30
31static ud_t ud;
32
33static void init_disassembler(void)
34{
35 ud_init(&ud);
36 ud_set_syntax(&ud, UD_SYN_ATT);
37}
38
39static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
40 int cr0_pe, int eflags_vm,
41 int cs_d, int cs_l)
42{
43 int mode;
44
45 if (!cr0_pe)
46 mode = 16;
47 else if (eflags_vm)
48 mode = 16;
49 else if (cs_l)
50 mode = 64;
51 else if (cs_d)
52 mode = 32;
53 else
54 mode = 16;
55
56 ud_set_pc(&ud, rip);
57 ud_set_mode(&ud, mode);
58 ud_set_input_buffer(&ud, insn, len);
59 ud_disassemble(&ud);
60 return ud_insn_asm(&ud);
61}
62
63#else
64
65static void init_disassembler(void)
66{
67}
68
69static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
70 int cr0_pe, int eflags_vm,
71 int cs_d, int cs_l)
72{
73 static char out[15*3+1];
74 int i;
75
76 for (i = 0; i < len; ++i)
77 sprintf(out + i * 3, "%02x ", insn[i]);
78 out[len*3-1] = '\0';
79 return out;
80}
81
82#endif
83
84
85#define VMX_EXIT_REASONS \
86 _ER(EXCEPTION_NMI, 0) \
87 _ER(EXTERNAL_INTERRUPT, 1) \
88 _ER(TRIPLE_FAULT, 2) \
89 _ER(PENDING_INTERRUPT, 7) \
90 _ER(NMI_WINDOW, 8) \
91 _ER(TASK_SWITCH, 9) \
92 _ER(CPUID, 10) \
93 _ER(HLT, 12) \
94 _ER(INVD, 13) \
95 _ER(INVLPG, 14) \
96 _ER(RDPMC, 15) \
97 _ER(RDTSC, 16) \
98 _ER(VMCALL, 18) \
99 _ER(VMCLEAR, 19) \
100 _ER(VMLAUNCH, 20) \
101 _ER(VMPTRLD, 21) \
102 _ER(VMPTRST, 22) \
103 _ER(VMREAD, 23) \
104 _ER(VMRESUME, 24) \
105 _ER(VMWRITE, 25) \
106 _ER(VMOFF, 26) \
107 _ER(VMON, 27) \
108 _ER(CR_ACCESS, 28) \
109 _ER(DR_ACCESS, 29) \
110 _ER(IO_INSTRUCTION, 30) \
111 _ER(MSR_READ, 31) \
112 _ER(MSR_WRITE, 32) \
113 _ER(MWAIT_INSTRUCTION, 36) \
114 _ER(MONITOR_INSTRUCTION, 39) \
115 _ER(PAUSE_INSTRUCTION, 40) \
116 _ER(MCE_DURING_VMENTRY, 41) \
117 _ER(TPR_BELOW_THRESHOLD, 43) \
118 _ER(APIC_ACCESS, 44) \
119 _ER(EOI_INDUCED, 45) \
120 _ER(EPT_VIOLATION, 48) \
121 _ER(EPT_MISCONFIG, 49) \
122 _ER(INVEPT, 50) \
123 _ER(PREEMPTION_TIMER, 52) \
124 _ER(WBINVD, 54) \
125 _ER(XSETBV, 55) \
126 _ER(APIC_WRITE, 56) \
127 _ER(INVPCID, 58)
128
129#define SVM_EXIT_REASONS \
130 _ER(EXIT_READ_CR0, 0x000) \
131 _ER(EXIT_READ_CR3, 0x003) \
132 _ER(EXIT_READ_CR4, 0x004) \
133 _ER(EXIT_READ_CR8, 0x008) \
134 _ER(EXIT_WRITE_CR0, 0x010) \
135 _ER(EXIT_WRITE_CR3, 0x013) \
136 _ER(EXIT_WRITE_CR4, 0x014) \
137 _ER(EXIT_WRITE_CR8, 0x018) \
138 _ER(EXIT_READ_DR0, 0x020) \
139 _ER(EXIT_READ_DR1, 0x021) \
140 _ER(EXIT_READ_DR2, 0x022) \
141 _ER(EXIT_READ_DR3, 0x023) \
142 _ER(EXIT_READ_DR4, 0x024) \
143 _ER(EXIT_READ_DR5, 0x025) \
144 _ER(EXIT_READ_DR6, 0x026) \
145 _ER(EXIT_READ_DR7, 0x027) \
146 _ER(EXIT_WRITE_DR0, 0x030) \
147 _ER(EXIT_WRITE_DR1, 0x031) \
148 _ER(EXIT_WRITE_DR2, 0x032) \
149 _ER(EXIT_WRITE_DR3, 0x033) \
150 _ER(EXIT_WRITE_DR4, 0x034) \
151 _ER(EXIT_WRITE_DR5, 0x035) \
152 _ER(EXIT_WRITE_DR6, 0x036) \
153 _ER(EXIT_WRITE_DR7, 0x037) \
154 _ER(EXIT_EXCP_BASE, 0x040) \
155 _ER(EXIT_INTR, 0x060) \
156 _ER(EXIT_NMI, 0x061) \
157 _ER(EXIT_SMI, 0x062) \
158 _ER(EXIT_INIT, 0x063) \
159 _ER(EXIT_VINTR, 0x064) \
160 _ER(EXIT_CR0_SEL_WRITE, 0x065) \
161 _ER(EXIT_IDTR_READ, 0x066) \
162 _ER(EXIT_GDTR_READ, 0x067) \
163 _ER(EXIT_LDTR_READ, 0x068) \
164 _ER(EXIT_TR_READ, 0x069) \
165 _ER(EXIT_IDTR_WRITE, 0x06a) \
166 _ER(EXIT_GDTR_WRITE, 0x06b) \
167 _ER(EXIT_LDTR_WRITE, 0x06c) \
168 _ER(EXIT_TR_WRITE, 0x06d) \
169 _ER(EXIT_RDTSC, 0x06e) \
170 _ER(EXIT_RDPMC, 0x06f) \
171 _ER(EXIT_PUSHF, 0x070) \
172 _ER(EXIT_POPF, 0x071) \
173 _ER(EXIT_CPUID, 0x072) \
174 _ER(EXIT_RSM, 0x073) \
175 _ER(EXIT_IRET, 0x074) \
176 _ER(EXIT_SWINT, 0x075) \
177 _ER(EXIT_INVD, 0x076) \
178 _ER(EXIT_PAUSE, 0x077) \
179 _ER(EXIT_HLT, 0x078) \
180 _ER(EXIT_INVLPG, 0x079) \
181 _ER(EXIT_INVLPGA, 0x07a) \
182 _ER(EXIT_IOIO, 0x07b) \
183 _ER(EXIT_MSR, 0x07c) \
184 _ER(EXIT_TASK_SWITCH, 0x07d) \
185 _ER(EXIT_FERR_FREEZE, 0x07e) \
186 _ER(EXIT_SHUTDOWN, 0x07f) \
187 _ER(EXIT_VMRUN, 0x080) \
188 _ER(EXIT_VMMCALL, 0x081) \
189 _ER(EXIT_VMLOAD, 0x082) \
190 _ER(EXIT_VMSAVE, 0x083) \
191 _ER(EXIT_STGI, 0x084) \
192 _ER(EXIT_CLGI, 0x085) \
193 _ER(EXIT_SKINIT, 0x086) \
194 _ER(EXIT_RDTSCP, 0x087) \
195 _ER(EXIT_ICEBP, 0x088) \
196 _ER(EXIT_WBINVD, 0x089) \
197 _ER(EXIT_MONITOR, 0x08a) \
198 _ER(EXIT_MWAIT, 0x08b) \
199 _ER(EXIT_MWAIT_COND, 0x08c) \
200 _ER(EXIT_NPF, 0x400) \
201 _ER(EXIT_ERR, -1)
202
203#define _ER(reason, val) { #reason, val },
204struct str_values {
205 const char *str;
206 int val;
207};
208
209static struct str_values vmx_exit_reasons[] = {
210 VMX_EXIT_REASONS
211 { NULL, -1}
212};
213
214static struct str_values svm_exit_reasons[] = {
215 SVM_EXIT_REASONS
216 { NULL, -1}
217};
218
219static struct isa_exit_reasons {
220 unsigned isa;
221 struct str_values *strings;
222} isa_exit_reasons[] = {
223 { .isa = 1, .strings = vmx_exit_reasons },
224 { .isa = 2, .strings = svm_exit_reasons },
225 { }
226};
227
228static const char *find_exit_reason(unsigned isa, int val)
229{
230 struct str_values *strings = NULL;
231 int i;
232
233 for (i = 0; isa_exit_reasons[i].strings; ++i)
234 if (isa_exit_reasons[i].isa == isa) {
235 strings = isa_exit_reasons[i].strings;
236 break;
237 }
238 if (!strings)
239 return "UNKNOWN-ISA";
240 for (i = 0; strings[i].val >= 0; i++)
241 if (strings[i].val == val)
242 break;
243 if (strings[i].str)
244 return strings[i].str;
245 return "UNKNOWN";
246}
247
248static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record,
249 struct event_format *event, void *context)
250{
251 unsigned long long isa;
252 unsigned long long val;
253 unsigned long long info1 = 0, info2 = 0;
254
255 if (pevent_get_field_val(s, event, "exit_reason", record, &val, 1) < 0)
256 return -1;
257
258 if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0)
259 isa = 1;
260
261 trace_seq_printf(s, "reason %s", find_exit_reason(isa, val));
262
263 pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
264
265 if (pevent_get_field_val(s, event, "info1", record, &info1, 0) >= 0
266 && pevent_get_field_val(s, event, "info2", record, &info2, 0) >= 0)
267 trace_seq_printf(s, " info %llx %llx", info1, info2);
268
269 return 0;
270}
271
272#define KVM_EMUL_INSN_F_CR0_PE (1 << 0)
273#define KVM_EMUL_INSN_F_EFL_VM (1 << 1)
274#define KVM_EMUL_INSN_F_CS_D (1 << 2)
275#define KVM_EMUL_INSN_F_CS_L (1 << 3)
276
277static int kvm_emulate_insn_handler(struct trace_seq *s,
278 struct pevent_record *record,
279 struct event_format *event, void *context)
280{
281 unsigned long long rip, csbase, len, flags, failed;
282 int llen;
283 uint8_t *insn;
284 const char *disasm;
285
286 if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0)
287 return -1;
288
289 if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0)
290 return -1;
291
292 if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0)
293 return -1;
294
295 if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0)
296 return -1;
297
298 if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0)
299 return -1;
300
301 insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1);
302 if (!insn)
303 return -1;
304
305 disasm = disassemble(insn, len, rip,
306 flags & KVM_EMUL_INSN_F_CR0_PE,
307 flags & KVM_EMUL_INSN_F_EFL_VM,
308 flags & KVM_EMUL_INSN_F_CS_D,
309 flags & KVM_EMUL_INSN_F_CS_L);
310
311 trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm,
312 failed ? " FAIL" : "");
313 return 0;
314}
315
316union kvm_mmu_page_role {
317 unsigned word;
318 struct {
319 unsigned glevels:4;
320 unsigned level:4;
321 unsigned quadrant:2;
322 unsigned pad_for_nice_hex_output:6;
323 unsigned direct:1;
324 unsigned access:3;
325 unsigned invalid:1;
326 unsigned cr4_pge:1;
327 unsigned nxe:1;
328 };
329};
330
331static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record,
332 struct event_format *event, void *context)
333{
334 unsigned long long val;
335 static const char *access_str[] = {
336 "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux"
337 };
338 union kvm_mmu_page_role role;
339
340 if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0)
341 return -1;
342
343 role.word = (int)val;
344
345 /*
346 * We can only use the structure if file is of the same
347 * endianess.
348 */
349 if (pevent_is_file_bigendian(event->pevent) ==
350 pevent_is_host_bigendian(event->pevent)) {
351
352 trace_seq_printf(s, "%u/%u q%u%s %s%s %spge %snxe",
353 role.level,
354 role.glevels,
355 role.quadrant,
356 role.direct ? " direct" : "",
357 access_str[role.access],
358 role.invalid ? " invalid" : "",
359 role.cr4_pge ? "" : "!",
360 role.nxe ? "" : "!");
361 } else
362 trace_seq_printf(s, "WORD: %08x", role.word);
363
364 pevent_print_num_field(s, " root %u ", event,
365 "root_count", record, 1);
366
367 if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0)
368 return -1;
369
370 trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0);
371 return 0;
372}
373
374static int kvm_mmu_get_page_handler(struct trace_seq *s,
375 struct pevent_record *record,
376 struct event_format *event, void *context)
377{
378 unsigned long long val;
379
380 if (pevent_get_field_val(s, event, "created", record, &val, 1) < 0)
381 return -1;
382
383 trace_seq_printf(s, "%s ", val ? "new" : "existing");
384
385 if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0)
386 return -1;
387
388 trace_seq_printf(s, "sp gfn %llx ", val);
389 return kvm_mmu_print_role(s, record, event, context);
390}
391
392#define PT_WRITABLE_SHIFT 1
393#define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT)
394
395static unsigned long long
396process_is_writable_pte(struct trace_seq *s, unsigned long long *args)
397{
398 unsigned long pte = args[0];
399 return pte & PT_WRITABLE_MASK;
400}
401
402int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
403{
404 init_disassembler();
405
406 pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit",
407 kvm_exit_handler, NULL);
408
409 pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
410 kvm_emulate_insn_handler, NULL);
411
412 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
413 kvm_mmu_get_page_handler, NULL);
414
415 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
416 kvm_mmu_print_role, NULL);
417
418 pevent_register_event_handler(pevent, -1,
419 "kvmmmu", "kvm_mmu_unsync_page",
420 kvm_mmu_print_role, NULL);
421
422 pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
423 kvm_mmu_print_role, NULL);
424
425 pevent_register_event_handler(pevent, -1, "kvmmmu",
426 "kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
427 NULL);
428
429 pevent_register_print_function(pevent,
430 process_is_writable_pte,
431 PEVENT_FUNC_ARG_INT,
432 "is_writable_pte",
433 PEVENT_FUNC_ARG_LONG,
434 PEVENT_FUNC_ARG_VOID);
435 return 0;
436}
437
438void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
439{
440 pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_exit",
441 kvm_exit_handler, NULL);
442
443 pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
444 kvm_emulate_insn_handler, NULL);
445
446 pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
447 kvm_mmu_get_page_handler, NULL);
448
449 pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
450 kvm_mmu_print_role, NULL);
451
452 pevent_unregister_event_handler(pevent, -1,
453 "kvmmmu", "kvm_mmu_unsync_page",
454 kvm_mmu_print_role, NULL);
455
456 pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
457 kvm_mmu_print_role, NULL);
458
459 pevent_unregister_event_handler(pevent, -1, "kvmmmu",
460 "kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
461 NULL);
462
463 pevent_unregister_print_function(pevent, process_is_writable_pte,
464 "is_writable_pte");
465}
diff --git a/tools/lib/traceevent/plugin_mac80211.c b/tools/lib/traceevent/plugin_mac80211.c
new file mode 100644
index 000000000000..7e15a0f1c2fd
--- /dev/null
+++ b/tools/lib/traceevent/plugin_mac80211.c
@@ -0,0 +1,102 @@
1/*
2 * Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "event-parse.h"
25
26#define INDENT 65
27
28static void print_string(struct trace_seq *s, struct event_format *event,
29 const char *name, const void *data)
30{
31 struct format_field *f = pevent_find_field(event, name);
32 int offset;
33 int length;
34
35 if (!f) {
36 trace_seq_printf(s, "NOTFOUND:%s", name);
37 return;
38 }
39
40 offset = f->offset;
41 length = f->size;
42
43 if (!strncmp(f->type, "__data_loc", 10)) {
44 unsigned long long v;
45 if (pevent_read_number_field(f, data, &v)) {
46 trace_seq_printf(s, "invalid_data_loc");
47 return;
48 }
49 offset = v & 0xffff;
50 length = v >> 16;
51 }
52
53 trace_seq_printf(s, "%.*s", length, (char *)data + offset);
54}
55
56#define SF(fn) pevent_print_num_field(s, fn ":%d", event, fn, record, 0)
57#define SFX(fn) pevent_print_num_field(s, fn ":%#x", event, fn, record, 0)
58#define SP() trace_seq_putc(s, ' ')
59
60static int drv_bss_info_changed(struct trace_seq *s,
61 struct pevent_record *record,
62 struct event_format *event, void *context)
63{
64 void *data = record->data;
65
66 print_string(s, event, "wiphy_name", data);
67 trace_seq_printf(s, " vif:");
68 print_string(s, event, "vif_name", data);
69 pevent_print_num_field(s, "(%d)", event, "vif_type", record, 1);
70
71 trace_seq_printf(s, "\n%*s", INDENT, "");
72 SF("assoc"); SP();
73 SF("aid"); SP();
74 SF("cts"); SP();
75 SF("shortpre"); SP();
76 SF("shortslot"); SP();
77 SF("dtimper"); SP();
78 trace_seq_printf(s, "\n%*s", INDENT, "");
79 SF("bcnint"); SP();
80 SFX("assoc_cap"); SP();
81 SFX("basic_rates"); SP();
82 SF("enable_beacon");
83 trace_seq_printf(s, "\n%*s", INDENT, "");
84 SF("ht_operation_mode");
85
86 return 0;
87}
88
89int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
90{
91 pevent_register_event_handler(pevent, -1, "mac80211",
92 "drv_bss_info_changed",
93 drv_bss_info_changed, NULL);
94 return 0;
95}
96
97void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
98{
99 pevent_unregister_event_handler(pevent, -1, "mac80211",
100 "drv_bss_info_changed",
101 drv_bss_info_changed, NULL);
102}
diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugin_sched_switch.c
new file mode 100644
index 000000000000..f1ce60065258
--- /dev/null
+++ b/tools/lib/traceevent/plugin_sched_switch.c
@@ -0,0 +1,160 @@
1/*
2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "event-parse.h"
25
26static void write_state(struct trace_seq *s, int val)
27{
28 const char states[] = "SDTtZXxW";
29 int found = 0;
30 int i;
31
32 for (i = 0; i < (sizeof(states) - 1); i++) {
33 if (!(val & (1 << i)))
34 continue;
35
36 if (found)
37 trace_seq_putc(s, '|');
38
39 found = 1;
40 trace_seq_putc(s, states[i]);
41 }
42
43 if (!found)
44 trace_seq_putc(s, 'R');
45}
46
47static void write_and_save_comm(struct format_field *field,
48 struct pevent_record *record,
49 struct trace_seq *s, int pid)
50{
51 const char *comm;
52 int len;
53
54 comm = (char *)(record->data + field->offset);
55 len = s->len;
56 trace_seq_printf(s, "%.*s",
57 field->size, comm);
58
59 /* make sure the comm has a \0 at the end. */
60 trace_seq_terminate(s);
61 comm = &s->buffer[len];
62
63 /* Help out the comm to ids. This will handle dups */
64 pevent_register_comm(field->event->pevent, comm, pid);
65}
66
67static int sched_wakeup_handler(struct trace_seq *s,
68 struct pevent_record *record,
69 struct event_format *event, void *context)
70{
71 struct format_field *field;
72 unsigned long long val;
73
74 if (pevent_get_field_val(s, event, "pid", record, &val, 1))
75 return trace_seq_putc(s, '!');
76
77 field = pevent_find_any_field(event, "comm");
78 if (field) {
79 write_and_save_comm(field, record, s, val);
80 trace_seq_putc(s, ':');
81 }
82 trace_seq_printf(s, "%lld", val);
83
84 if (pevent_get_field_val(s, event, "prio", record, &val, 0) == 0)
85 trace_seq_printf(s, " [%lld]", val);
86
87 if (pevent_get_field_val(s, event, "success", record, &val, 1) == 0)
88 trace_seq_printf(s, " success=%lld", val);
89
90 if (pevent_get_field_val(s, event, "target_cpu", record, &val, 0) == 0)
91 trace_seq_printf(s, " CPU:%03llu", val);
92
93 return 0;
94}
95
96static int sched_switch_handler(struct trace_seq *s,
97 struct pevent_record *record,
98 struct event_format *event, void *context)
99{
100 struct format_field *field;
101 unsigned long long val;
102
103 if (pevent_get_field_val(s, event, "prev_pid", record, &val, 1))
104 return trace_seq_putc(s, '!');
105
106 field = pevent_find_any_field(event, "prev_comm");
107 if (field) {
108 write_and_save_comm(field, record, s, val);
109 trace_seq_putc(s, ':');
110 }
111 trace_seq_printf(s, "%lld ", val);
112
113 if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0)
114 trace_seq_printf(s, "[%lld] ", val);
115
116 if (pevent_get_field_val(s, event, "prev_state", record, &val, 0) == 0)
117 write_state(s, val);
118
119 trace_seq_puts(s, " ==> ");
120
121 if (pevent_get_field_val(s, event, "next_pid", record, &val, 1))
122 return trace_seq_putc(s, '!');
123
124 field = pevent_find_any_field(event, "next_comm");
125 if (field) {
126 write_and_save_comm(field, record, s, val);
127 trace_seq_putc(s, ':');
128 }
129 trace_seq_printf(s, "%lld", val);
130
131 if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0)
132 trace_seq_printf(s, " [%lld]", val);
133
134 return 0;
135}
136
137int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
138{
139 pevent_register_event_handler(pevent, -1, "sched", "sched_switch",
140 sched_switch_handler, NULL);
141
142 pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup",
143 sched_wakeup_handler, NULL);
144
145 pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup_new",
146 sched_wakeup_handler, NULL);
147 return 0;
148}
149
150void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
151{
152 pevent_unregister_event_handler(pevent, -1, "sched", "sched_switch",
153 sched_switch_handler, NULL);
154
155 pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup",
156 sched_wakeup_handler, NULL);
157
158 pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new",
159 sched_wakeup_handler, NULL);
160}
diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c
new file mode 100644
index 000000000000..eda326fc8620
--- /dev/null
+++ b/tools/lib/traceevent/plugin_scsi.c
@@ -0,0 +1,429 @@
1#include <stdio.h>
2#include <string.h>
3#include <inttypes.h>
4#include "event-parse.h"
5
6typedef unsigned long sector_t;
7typedef uint64_t u64;
8typedef unsigned int u32;
9
10/*
11 * SCSI opcodes
12 */
13#define TEST_UNIT_READY 0x00
14#define REZERO_UNIT 0x01
15#define REQUEST_SENSE 0x03
16#define FORMAT_UNIT 0x04
17#define READ_BLOCK_LIMITS 0x05
18#define REASSIGN_BLOCKS 0x07
19#define INITIALIZE_ELEMENT_STATUS 0x07
20#define READ_6 0x08
21#define WRITE_6 0x0a
22#define SEEK_6 0x0b
23#define READ_REVERSE 0x0f
24#define WRITE_FILEMARKS 0x10
25#define SPACE 0x11
26#define INQUIRY 0x12
27#define RECOVER_BUFFERED_DATA 0x14
28#define MODE_SELECT 0x15
29#define RESERVE 0x16
30#define RELEASE 0x17
31#define COPY 0x18
32#define ERASE 0x19
33#define MODE_SENSE 0x1a
34#define START_STOP 0x1b
35#define RECEIVE_DIAGNOSTIC 0x1c
36#define SEND_DIAGNOSTIC 0x1d
37#define ALLOW_MEDIUM_REMOVAL 0x1e
38
39#define READ_FORMAT_CAPACITIES 0x23
40#define SET_WINDOW 0x24
41#define READ_CAPACITY 0x25
42#define READ_10 0x28
43#define WRITE_10 0x2a
44#define SEEK_10 0x2b
45#define POSITION_TO_ELEMENT 0x2b
46#define WRITE_VERIFY 0x2e
47#define VERIFY 0x2f
48#define SEARCH_HIGH 0x30
49#define SEARCH_EQUAL 0x31
50#define SEARCH_LOW 0x32
51#define SET_LIMITS 0x33
52#define PRE_FETCH 0x34
53#define READ_POSITION 0x34
54#define SYNCHRONIZE_CACHE 0x35
55#define LOCK_UNLOCK_CACHE 0x36
56#define READ_DEFECT_DATA 0x37
57#define MEDIUM_SCAN 0x38
58#define COMPARE 0x39
59#define COPY_VERIFY 0x3a
60#define WRITE_BUFFER 0x3b
61#define READ_BUFFER 0x3c
62#define UPDATE_BLOCK 0x3d
63#define READ_LONG 0x3e
64#define WRITE_LONG 0x3f
65#define CHANGE_DEFINITION 0x40
66#define WRITE_SAME 0x41
67#define UNMAP 0x42
68#define READ_TOC 0x43
69#define READ_HEADER 0x44
70#define GET_EVENT_STATUS_NOTIFICATION 0x4a
71#define LOG_SELECT 0x4c
72#define LOG_SENSE 0x4d
73#define XDWRITEREAD_10 0x53
74#define MODE_SELECT_10 0x55
75#define RESERVE_10 0x56
76#define RELEASE_10 0x57
77#define MODE_SENSE_10 0x5a
78#define PERSISTENT_RESERVE_IN 0x5e
79#define PERSISTENT_RESERVE_OUT 0x5f
80#define VARIABLE_LENGTH_CMD 0x7f
81#define REPORT_LUNS 0xa0
82#define SECURITY_PROTOCOL_IN 0xa2
83#define MAINTENANCE_IN 0xa3
84#define MAINTENANCE_OUT 0xa4
85#define MOVE_MEDIUM 0xa5
86#define EXCHANGE_MEDIUM 0xa6
87#define READ_12 0xa8
88#define WRITE_12 0xaa
89#define READ_MEDIA_SERIAL_NUMBER 0xab
90#define WRITE_VERIFY_12 0xae
91#define VERIFY_12 0xaf
92#define SEARCH_HIGH_12 0xb0
93#define SEARCH_EQUAL_12 0xb1
94#define SEARCH_LOW_12 0xb2
95#define SECURITY_PROTOCOL_OUT 0xb5
96#define READ_ELEMENT_STATUS 0xb8
97#define SEND_VOLUME_TAG 0xb6
98#define WRITE_LONG_2 0xea
99#define EXTENDED_COPY 0x83
100#define RECEIVE_COPY_RESULTS 0x84
101#define ACCESS_CONTROL_IN 0x86
102#define ACCESS_CONTROL_OUT 0x87
103#define READ_16 0x88
104#define WRITE_16 0x8a
105#define READ_ATTRIBUTE 0x8c
106#define WRITE_ATTRIBUTE 0x8d
107#define VERIFY_16 0x8f
108#define SYNCHRONIZE_CACHE_16 0x91
109#define WRITE_SAME_16 0x93
110#define SERVICE_ACTION_IN 0x9e
111/* values for service action in */
112#define SAI_READ_CAPACITY_16 0x10
113#define SAI_GET_LBA_STATUS 0x12
114/* values for VARIABLE_LENGTH_CMD service action codes
115 * see spc4r17 Section D.3.5, table D.7 and D.8 */
116#define VLC_SA_RECEIVE_CREDENTIAL 0x1800
117/* values for maintenance in */
118#define MI_REPORT_IDENTIFYING_INFORMATION 0x05
119#define MI_REPORT_TARGET_PGS 0x0a
120#define MI_REPORT_ALIASES 0x0b
121#define MI_REPORT_SUPPORTED_OPERATION_CODES 0x0c
122#define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0d
123#define MI_REPORT_PRIORITY 0x0e
124#define MI_REPORT_TIMESTAMP 0x0f
125#define MI_MANAGEMENT_PROTOCOL_IN 0x10
126/* value for MI_REPORT_TARGET_PGS ext header */
127#define MI_EXT_HDR_PARAM_FMT 0x20
128/* values for maintenance out */
129#define MO_SET_IDENTIFYING_INFORMATION 0x06
130#define MO_SET_TARGET_PGS 0x0a
131#define MO_CHANGE_ALIASES 0x0b
132#define MO_SET_PRIORITY 0x0e
133#define MO_SET_TIMESTAMP 0x0f
134#define MO_MANAGEMENT_PROTOCOL_OUT 0x10
135/* values for variable length command */
136#define XDREAD_32 0x03
137#define XDWRITE_32 0x04
138#define XPWRITE_32 0x06
139#define XDWRITEREAD_32 0x07
140#define READ_32 0x09
141#define VERIFY_32 0x0a
142#define WRITE_32 0x0b
143#define WRITE_SAME_32 0x0d
144
145#define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f)
146#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9])
147
148static const char *
149scsi_trace_misc(struct trace_seq *, unsigned char *, int);
150
151static const char *
152scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len)
153{
154 const char *ret = p->buffer + p->len;
155 sector_t lba = 0, txlen = 0;
156
157 lba |= ((cdb[1] & 0x1F) << 16);
158 lba |= (cdb[2] << 8);
159 lba |= cdb[3];
160 txlen = cdb[4];
161
162 trace_seq_printf(p, "lba=%llu txlen=%llu",
163 (unsigned long long)lba, (unsigned long long)txlen);
164 trace_seq_putc(p, 0);
165 return ret;
166}
167
168static const char *
169scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len)
170{
171 const char *ret = p->buffer + p->len;
172 sector_t lba = 0, txlen = 0;
173
174 lba |= (cdb[2] << 24);
175 lba |= (cdb[3] << 16);
176 lba |= (cdb[4] << 8);
177 lba |= cdb[5];
178 txlen |= (cdb[7] << 8);
179 txlen |= cdb[8];
180
181 trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
182 (unsigned long long)lba, (unsigned long long)txlen,
183 cdb[1] >> 5);
184
185 if (cdb[0] == WRITE_SAME)
186 trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
187
188 trace_seq_putc(p, 0);
189 return ret;
190}
191
192static const char *
193scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len)
194{
195 const char *ret = p->buffer + p->len;
196 sector_t lba = 0, txlen = 0;
197
198 lba |= (cdb[2] << 24);
199 lba |= (cdb[3] << 16);
200 lba |= (cdb[4] << 8);
201 lba |= cdb[5];
202 txlen |= (cdb[6] << 24);
203 txlen |= (cdb[7] << 16);
204 txlen |= (cdb[8] << 8);
205 txlen |= cdb[9];
206
207 trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
208 (unsigned long long)lba, (unsigned long long)txlen,
209 cdb[1] >> 5);
210 trace_seq_putc(p, 0);
211 return ret;
212}
213
214static const char *
215scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len)
216{
217 const char *ret = p->buffer + p->len;
218 sector_t lba = 0, txlen = 0;
219
220 lba |= ((u64)cdb[2] << 56);
221 lba |= ((u64)cdb[3] << 48);
222 lba |= ((u64)cdb[4] << 40);
223 lba |= ((u64)cdb[5] << 32);
224 lba |= (cdb[6] << 24);
225 lba |= (cdb[7] << 16);
226 lba |= (cdb[8] << 8);
227 lba |= cdb[9];
228 txlen |= (cdb[10] << 24);
229 txlen |= (cdb[11] << 16);
230 txlen |= (cdb[12] << 8);
231 txlen |= cdb[13];
232
233 trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
234 (unsigned long long)lba, (unsigned long long)txlen,
235 cdb[1] >> 5);
236
237 if (cdb[0] == WRITE_SAME_16)
238 trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
239
240 trace_seq_putc(p, 0);
241 return ret;
242}
243
244static const char *
245scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)
246{
247 const char *ret = p->buffer + p->len, *cmd;
248 sector_t lba = 0, txlen = 0;
249 u32 ei_lbrt = 0;
250
251 switch (SERVICE_ACTION32(cdb)) {
252 case READ_32:
253 cmd = "READ";
254 break;
255 case VERIFY_32:
256 cmd = "VERIFY";
257 break;
258 case WRITE_32:
259 cmd = "WRITE";
260 break;
261 case WRITE_SAME_32:
262 cmd = "WRITE_SAME";
263 break;
264 default:
265 trace_seq_printf(p, "UNKNOWN");
266 goto out;
267 }
268
269 lba |= ((u64)cdb[12] << 56);
270 lba |= ((u64)cdb[13] << 48);
271 lba |= ((u64)cdb[14] << 40);
272 lba |= ((u64)cdb[15] << 32);
273 lba |= (cdb[16] << 24);
274 lba |= (cdb[17] << 16);
275 lba |= (cdb[18] << 8);
276 lba |= cdb[19];
277 ei_lbrt |= (cdb[20] << 24);
278 ei_lbrt |= (cdb[21] << 16);
279 ei_lbrt |= (cdb[22] << 8);
280 ei_lbrt |= cdb[23];
281 txlen |= (cdb[28] << 24);
282 txlen |= (cdb[29] << 16);
283 txlen |= (cdb[30] << 8);
284 txlen |= cdb[31];
285
286 trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u",
287 cmd, (unsigned long long)lba,
288 (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt);
289
290 if (SERVICE_ACTION32(cdb) == WRITE_SAME_32)
291 trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1);
292
293out:
294 trace_seq_putc(p, 0);
295 return ret;
296}
297
298static const char *
299scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len)
300{
301 const char *ret = p->buffer + p->len;
302 unsigned int regions = cdb[7] << 8 | cdb[8];
303
304 trace_seq_printf(p, "regions=%u", (regions - 8) / 16);
305 trace_seq_putc(p, 0);
306 return ret;
307}
308
309static const char *
310scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)
311{
312 const char *ret = p->buffer + p->len, *cmd;
313 sector_t lba = 0;
314 u32 alloc_len = 0;
315
316 switch (SERVICE_ACTION16(cdb)) {
317 case SAI_READ_CAPACITY_16:
318 cmd = "READ_CAPACITY_16";
319 break;
320 case SAI_GET_LBA_STATUS:
321 cmd = "GET_LBA_STATUS";
322 break;
323 default:
324 trace_seq_printf(p, "UNKNOWN");
325 goto out;
326 }
327
328 lba |= ((u64)cdb[2] << 56);
329 lba |= ((u64)cdb[3] << 48);
330 lba |= ((u64)cdb[4] << 40);
331 lba |= ((u64)cdb[5] << 32);
332 lba |= (cdb[6] << 24);
333 lba |= (cdb[7] << 16);
334 lba |= (cdb[8] << 8);
335 lba |= cdb[9];
336 alloc_len |= (cdb[10] << 24);
337 alloc_len |= (cdb[11] << 16);
338 alloc_len |= (cdb[12] << 8);
339 alloc_len |= cdb[13];
340
341 trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd,
342 (unsigned long long)lba, alloc_len);
343
344out:
345 trace_seq_putc(p, 0);
346 return ret;
347}
348
349static const char *
350scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len)
351{
352 switch (SERVICE_ACTION32(cdb)) {
353 case READ_32:
354 case VERIFY_32:
355 case WRITE_32:
356 case WRITE_SAME_32:
357 return scsi_trace_rw32(p, cdb, len);
358 default:
359 return scsi_trace_misc(p, cdb, len);
360 }
361}
362
363static const char *
364scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len)
365{
366 const char *ret = p->buffer + p->len;
367
368 trace_seq_printf(p, "-");
369 trace_seq_putc(p, 0);
370 return ret;
371}
372
373const char *
374scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len)
375{
376 switch (cdb[0]) {
377 case READ_6:
378 case WRITE_6:
379 return scsi_trace_rw6(p, cdb, len);
380 case READ_10:
381 case VERIFY:
382 case WRITE_10:
383 case WRITE_SAME:
384 return scsi_trace_rw10(p, cdb, len);
385 case READ_12:
386 case VERIFY_12:
387 case WRITE_12:
388 return scsi_trace_rw12(p, cdb, len);
389 case READ_16:
390 case VERIFY_16:
391 case WRITE_16:
392 case WRITE_SAME_16:
393 return scsi_trace_rw16(p, cdb, len);
394 case UNMAP:
395 return scsi_trace_unmap(p, cdb, len);
396 case SERVICE_ACTION_IN:
397 return scsi_trace_service_action_in(p, cdb, len);
398 case VARIABLE_LENGTH_CMD:
399 return scsi_trace_varlen(p, cdb, len);
400 default:
401 return scsi_trace_misc(p, cdb, len);
402 }
403}
404
405unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s,
406 unsigned long long *args)
407{
408 scsi_trace_parse_cdb(s, (unsigned char *) (unsigned long) args[1], args[2]);
409 return 0;
410}
411
412int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
413{
414 pevent_register_print_function(pevent,
415 process_scsi_trace_parse_cdb,
416 PEVENT_FUNC_ARG_STRING,
417 "scsi_trace_parse_cdb",
418 PEVENT_FUNC_ARG_PTR,
419 PEVENT_FUNC_ARG_PTR,
420 PEVENT_FUNC_ARG_INT,
421 PEVENT_FUNC_ARG_VOID);
422 return 0;
423}
424
425void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
426{
427 pevent_unregister_print_function(pevent, process_scsi_trace_parse_cdb,
428 "scsi_trace_parse_cdb");
429}
diff --git a/tools/lib/traceevent/plugin_xen.c b/tools/lib/traceevent/plugin_xen.c
new file mode 100644
index 000000000000..3a413eaada68
--- /dev/null
+++ b/tools/lib/traceevent/plugin_xen.c
@@ -0,0 +1,136 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include "event-parse.h"
5
6#define __HYPERVISOR_set_trap_table 0
7#define __HYPERVISOR_mmu_update 1
8#define __HYPERVISOR_set_gdt 2
9#define __HYPERVISOR_stack_switch 3
10#define __HYPERVISOR_set_callbacks 4
11#define __HYPERVISOR_fpu_taskswitch 5
12#define __HYPERVISOR_sched_op_compat 6
13#define __HYPERVISOR_dom0_op 7
14#define __HYPERVISOR_set_debugreg 8
15#define __HYPERVISOR_get_debugreg 9
16#define __HYPERVISOR_update_descriptor 10
17#define __HYPERVISOR_memory_op 12
18#define __HYPERVISOR_multicall 13
19#define __HYPERVISOR_update_va_mapping 14
20#define __HYPERVISOR_set_timer_op 15
21#define __HYPERVISOR_event_channel_op_compat 16
22#define __HYPERVISOR_xen_version 17
23#define __HYPERVISOR_console_io 18
24#define __HYPERVISOR_physdev_op_compat 19
25#define __HYPERVISOR_grant_table_op 20
26#define __HYPERVISOR_vm_assist 21
27#define __HYPERVISOR_update_va_mapping_otherdomain 22
28#define __HYPERVISOR_iret 23 /* x86 only */
29#define __HYPERVISOR_vcpu_op 24
30#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
31#define __HYPERVISOR_mmuext_op 26
32#define __HYPERVISOR_acm_op 27
33#define __HYPERVISOR_nmi_op 28
34#define __HYPERVISOR_sched_op 29
35#define __HYPERVISOR_callback_op 30
36#define __HYPERVISOR_xenoprof_op 31
37#define __HYPERVISOR_event_channel_op 32
38#define __HYPERVISOR_physdev_op 33
39#define __HYPERVISOR_hvm_op 34
40#define __HYPERVISOR_tmem_op 38
41
42/* Architecture-specific hypercall definitions. */
43#define __HYPERVISOR_arch_0 48
44#define __HYPERVISOR_arch_1 49
45#define __HYPERVISOR_arch_2 50
46#define __HYPERVISOR_arch_3 51
47#define __HYPERVISOR_arch_4 52
48#define __HYPERVISOR_arch_5 53
49#define __HYPERVISOR_arch_6 54
50#define __HYPERVISOR_arch_7 55
51
52#define N(x) [__HYPERVISOR_##x] = "("#x")"
53static const char *xen_hypercall_names[] = {
54 N(set_trap_table),
55 N(mmu_update),
56 N(set_gdt),
57 N(stack_switch),
58 N(set_callbacks),
59 N(fpu_taskswitch),
60 N(sched_op_compat),
61 N(dom0_op),
62 N(set_debugreg),
63 N(get_debugreg),
64 N(update_descriptor),
65 N(memory_op),
66 N(multicall),
67 N(update_va_mapping),
68 N(set_timer_op),
69 N(event_channel_op_compat),
70 N(xen_version),
71 N(console_io),
72 N(physdev_op_compat),
73 N(grant_table_op),
74 N(vm_assist),
75 N(update_va_mapping_otherdomain),
76 N(iret),
77 N(vcpu_op),
78 N(set_segment_base),
79 N(mmuext_op),
80 N(acm_op),
81 N(nmi_op),
82 N(sched_op),
83 N(callback_op),
84 N(xenoprof_op),
85 N(event_channel_op),
86 N(physdev_op),
87 N(hvm_op),
88
89/* Architecture-specific hypercall definitions. */
90 N(arch_0),
91 N(arch_1),
92 N(arch_2),
93 N(arch_3),
94 N(arch_4),
95 N(arch_5),
96 N(arch_6),
97 N(arch_7),
98};
99#undef N
100
101#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
102
103static const char *xen_hypercall_name(unsigned op)
104{
105 if (op < ARRAY_SIZE(xen_hypercall_names) &&
106 xen_hypercall_names[op] != NULL)
107 return xen_hypercall_names[op];
108
109 return "";
110}
111
112unsigned long long process_xen_hypercall_name(struct trace_seq *s,
113 unsigned long long *args)
114{
115 unsigned int op = args[0];
116
117 trace_seq_printf(s, "%s", xen_hypercall_name(op));
118 return 0;
119}
120
121int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
122{
123 pevent_register_print_function(pevent,
124 process_xen_hypercall_name,
125 PEVENT_FUNC_ARG_STRING,
126 "xen_hypercall_name",
127 PEVENT_FUNC_ARG_INT,
128 PEVENT_FUNC_ARG_VOID);
129 return 0;
130}
131
132void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
133{
134 pevent_unregister_print_function(pevent, process_xen_hypercall_name,
135 "xen_hypercall_name");
136}
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c
index d7f2e68bc5b9..ec3bd16a5488 100644
--- a/tools/lib/traceevent/trace-seq.c
+++ b/tools/lib/traceevent/trace-seq.c
@@ -22,6 +22,7 @@
22#include <string.h> 22#include <string.h>
23#include <stdarg.h> 23#include <stdarg.h>
24 24
25#include <asm/bug.h>
25#include "event-parse.h" 26#include "event-parse.h"
26#include "event-utils.h" 27#include "event-utils.h"
27 28
@@ -32,10 +33,21 @@
32#define TRACE_SEQ_POISON ((void *)0xdeadbeef) 33#define TRACE_SEQ_POISON ((void *)0xdeadbeef)
33#define TRACE_SEQ_CHECK(s) \ 34#define TRACE_SEQ_CHECK(s) \
34do { \ 35do { \
35 if ((s)->buffer == TRACE_SEQ_POISON) \ 36 if (WARN_ONCE((s)->buffer == TRACE_SEQ_POISON, \
36 die("Usage of trace_seq after it was destroyed"); \ 37 "Usage of trace_seq after it was destroyed")) \
38 (s)->state = TRACE_SEQ__BUFFER_POISONED; \
37} while (0) 39} while (0)
38 40
41#define TRACE_SEQ_CHECK_RET_N(s, n) \
42do { \
43 TRACE_SEQ_CHECK(s); \
44 if ((s)->state != TRACE_SEQ__GOOD) \
45 return n; \
46} while (0)
47
48#define TRACE_SEQ_CHECK_RET(s) TRACE_SEQ_CHECK_RET_N(s, )
49#define TRACE_SEQ_CHECK_RET0(s) TRACE_SEQ_CHECK_RET_N(s, 0)
50
39/** 51/**
40 * trace_seq_init - initialize the trace_seq structure 52 * trace_seq_init - initialize the trace_seq structure
41 * @s: a pointer to the trace_seq structure to initialize 53 * @s: a pointer to the trace_seq structure to initialize
@@ -45,7 +57,11 @@ void trace_seq_init(struct trace_seq *s)
45 s->len = 0; 57 s->len = 0;
46 s->readpos = 0; 58 s->readpos = 0;
47 s->buffer_size = TRACE_SEQ_BUF_SIZE; 59 s->buffer_size = TRACE_SEQ_BUF_SIZE;
48 s->buffer = malloc_or_die(s->buffer_size); 60 s->buffer = malloc(s->buffer_size);
61 if (s->buffer != NULL)
62 s->state = TRACE_SEQ__GOOD;
63 else
64 s->state = TRACE_SEQ__MEM_ALLOC_FAILED;
49} 65}
50 66
51/** 67/**
@@ -71,17 +87,23 @@ void trace_seq_destroy(struct trace_seq *s)
71{ 87{
72 if (!s) 88 if (!s)
73 return; 89 return;
74 TRACE_SEQ_CHECK(s); 90 TRACE_SEQ_CHECK_RET(s);
75 free(s->buffer); 91 free(s->buffer);
76 s->buffer = TRACE_SEQ_POISON; 92 s->buffer = TRACE_SEQ_POISON;
77} 93}
78 94
79static void expand_buffer(struct trace_seq *s) 95static void expand_buffer(struct trace_seq *s)
80{ 96{
97 char *buf;
98
99 buf = realloc(s->buffer, s->buffer_size + TRACE_SEQ_BUF_SIZE);
100 if (WARN_ONCE(!buf, "Can't allocate trace_seq buffer memory")) {
101 s->state = TRACE_SEQ__MEM_ALLOC_FAILED;
102 return;
103 }
104
105 s->buffer = buf;
81 s->buffer_size += TRACE_SEQ_BUF_SIZE; 106 s->buffer_size += TRACE_SEQ_BUF_SIZE;
82 s->buffer = realloc(s->buffer, s->buffer_size);
83 if (!s->buffer)
84 die("Can't allocate trace_seq buffer memory");
85} 107}
86 108
87/** 109/**
@@ -105,9 +127,9 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
105 int len; 127 int len;
106 int ret; 128 int ret;
107 129
108 TRACE_SEQ_CHECK(s);
109
110 try_again: 130 try_again:
131 TRACE_SEQ_CHECK_RET0(s);
132
111 len = (s->buffer_size - 1) - s->len; 133 len = (s->buffer_size - 1) - s->len;
112 134
113 va_start(ap, fmt); 135 va_start(ap, fmt);
@@ -141,9 +163,9 @@ trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
141 int len; 163 int len;
142 int ret; 164 int ret;
143 165
144 TRACE_SEQ_CHECK(s);
145
146 try_again: 166 try_again:
167 TRACE_SEQ_CHECK_RET0(s);
168
147 len = (s->buffer_size - 1) - s->len; 169 len = (s->buffer_size - 1) - s->len;
148 170
149 ret = vsnprintf(s->buffer + s->len, len, fmt, args); 171 ret = vsnprintf(s->buffer + s->len, len, fmt, args);
@@ -172,13 +194,15 @@ int trace_seq_puts(struct trace_seq *s, const char *str)
172{ 194{
173 int len; 195 int len;
174 196
175 TRACE_SEQ_CHECK(s); 197 TRACE_SEQ_CHECK_RET0(s);
176 198
177 len = strlen(str); 199 len = strlen(str);
178 200
179 while (len > ((s->buffer_size - 1) - s->len)) 201 while (len > ((s->buffer_size - 1) - s->len))
180 expand_buffer(s); 202 expand_buffer(s);
181 203
204 TRACE_SEQ_CHECK_RET0(s);
205
182 memcpy(s->buffer + s->len, str, len); 206 memcpy(s->buffer + s->len, str, len);
183 s->len += len; 207 s->len += len;
184 208
@@ -187,11 +211,13 @@ int trace_seq_puts(struct trace_seq *s, const char *str)
187 211
188int trace_seq_putc(struct trace_seq *s, unsigned char c) 212int trace_seq_putc(struct trace_seq *s, unsigned char c)
189{ 213{
190 TRACE_SEQ_CHECK(s); 214 TRACE_SEQ_CHECK_RET0(s);
191 215
192 while (s->len >= (s->buffer_size - 1)) 216 while (s->len >= (s->buffer_size - 1))
193 expand_buffer(s); 217 expand_buffer(s);
194 218
219 TRACE_SEQ_CHECK_RET0(s);
220
195 s->buffer[s->len++] = c; 221 s->buffer[s->len++] = c;
196 222
197 return 1; 223 return 1;
@@ -199,7 +225,7 @@ int trace_seq_putc(struct trace_seq *s, unsigned char c)
199 225
200void trace_seq_terminate(struct trace_seq *s) 226void trace_seq_terminate(struct trace_seq *s)
201{ 227{
202 TRACE_SEQ_CHECK(s); 228 TRACE_SEQ_CHECK_RET(s);
203 229
204 /* There's always one character left on the buffer */ 230 /* There's always one character left on the buffer */
205 s->buffer[s->len] = 0; 231 s->buffer[s->len] = 0;
@@ -208,5 +234,16 @@ void trace_seq_terminate(struct trace_seq *s)
208int trace_seq_do_printf(struct trace_seq *s) 234int trace_seq_do_printf(struct trace_seq *s)
209{ 235{
210 TRACE_SEQ_CHECK(s); 236 TRACE_SEQ_CHECK(s);
211 return printf("%.*s", s->len, s->buffer); 237
238 switch (s->state) {
239 case TRACE_SEQ__GOOD:
240 return printf("%.*s", s->len, s->buffer);
241 case TRACE_SEQ__BUFFER_POISONED:
242 puts("Usage of trace_seq after it was destroyed");
243 break;
244 case TRACE_SEQ__MEM_ALLOC_FAILED:
245 puts("Can't allocate trace_seq buffer memory");
246 break;
247 }
248 return -1;
212} 249}
diff --git a/tools/perf/Documentation/perf-archive.txt b/tools/perf/Documentation/perf-archive.txt
index 5032a142853e..ac6ecbb3e669 100644
--- a/tools/perf/Documentation/perf-archive.txt
+++ b/tools/perf/Documentation/perf-archive.txt
@@ -12,9 +12,9 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command runs runs perf-buildid-list --with-hits, and collects the files 15This command runs perf-buildid-list --with-hits, and collects the files with the
16with the buildids found so that analysis of perf.data contents can be possible 16buildids found so that analysis of perf.data contents can be possible on another
17on another machine. 17machine.
18 18
19 19
20SEE ALSO 20SEE ALSO
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
index 6a06cefe9642..52276a6d2b75 100644
--- a/tools/perf/Documentation/perf-kvm.txt
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -10,9 +10,9 @@ SYNOPSIS
10[verse] 10[verse]
11'perf kvm' [--host] [--guest] [--guestmount=<path> 11'perf kvm' [--host] [--guest] [--guestmount=<path>
12 [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]] 12 [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]]
13 {top|record|report|diff|buildid-list} 13 {top|record|report|diff|buildid-list} [<options>]
14'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> 14'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path>
15 | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} 15 | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} [<options>]
16'perf kvm stat [record|report|live] [<options>] 16'perf kvm stat [record|report|live] [<options>]
17 17
18DESCRIPTION 18DESCRIPTION
@@ -24,10 +24,17 @@ There are a couple of variants of perf kvm:
24 of an arbitrary workload. 24 of an arbitrary workload.
25 25
26 'perf kvm record <command>' to record the performance counter profile 26 'perf kvm record <command>' to record the performance counter profile
27 of an arbitrary workload and save it into a perf data file. If both 27 of an arbitrary workload and save it into a perf data file. We set the
28 --host and --guest are input, the perf data file name is perf.data.kvm. 28 default behavior of perf kvm as --guest, so if neither --host nor --guest
29 If there is no --host but --guest, the file name is perf.data.guest. 29 is input, the perf data file name is perf.data.guest. If --host is input,
30 If there is no --guest but --host, the file name is perf.data.host. 30 the perf data file name is perf.data.kvm. If you want to record data into
31 perf.data.host, please input --host --no-guest. The behaviors are shown as
32 following:
33 Default('') -> perf.data.guest
34 --host -> perf.data.kvm
35 --guest -> perf.data.guest
36 --host --guest -> perf.data.kvm
37 --host --no-guest -> perf.data.host
31 38
32 'perf kvm report' to display the performance counter profile information 39 'perf kvm report' to display the performance counter profile information
33 recorded via perf kvm record. 40 recorded via perf kvm record.
@@ -37,7 +44,9 @@ There are a couple of variants of perf kvm:
37 44
38 'perf kvm buildid-list' to display the buildids found in a perf data file, 45 'perf kvm buildid-list' to display the buildids found in a perf data file,
39 so that other tools can be used to fetch packages with matching symbol tables 46 so that other tools can be used to fetch packages with matching symbol tables
40 for use by perf report. 47 for use by perf report. As buildid is read from /sys/kernel/notes in os, then
48 if you want to list the buildid for guest, please make sure your perf data file
49 was captured with --guestmount in perf kvm record.
41 50
42 'perf kvm stat <command>' to run a command and gather performance counter 51 'perf kvm stat <command>' to run a command and gather performance counter
43 statistics. 52 statistics.
@@ -58,14 +67,14 @@ There are a couple of variants of perf kvm:
58OPTIONS 67OPTIONS
59------- 68-------
60-i:: 69-i::
61--input=:: 70--input=<path>::
62 Input file name. 71 Input file name.
63-o:: 72-o::
64--output:: 73--output=<path>::
65 Output file name. 74 Output file name.
66--host=:: 75--host::
67 Collect host side performance profile. 76 Collect host side performance profile.
68--guest=:: 77--guest::
69 Collect guest side performance profile. 78 Collect guest side performance profile.
70--guestmount=<path>:: 79--guestmount=<path>::
71 Guest os root file system mount directory. Users mounts guest os 80 Guest os root file system mount directory. Users mounts guest os
@@ -84,6 +93,9 @@ OPTIONS
84 kernel module information. Users copy it out from guest os. 93 kernel module information. Users copy it out from guest os.
85--guestvmlinux=<path>:: 94--guestvmlinux=<path>::
86 Guest os kernel vmlinux. 95 Guest os kernel vmlinux.
96-v::
97--verbose::
98 Be more verbose (show counter open errors, etc).
87 99
88STAT REPORT OPTIONS 100STAT REPORT OPTIONS
89------------------- 101-------------------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 43b42c4f4a91..c71b0f36d9e8 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -57,6 +57,8 @@ OPTIONS
57-t:: 57-t::
58--tid=:: 58--tid=::
59 Record events on existing thread ID (comma separated list). 59 Record events on existing thread ID (comma separated list).
60 This option also disables inheritance by default. Enable it by adding
61 --inherit.
60 62
61-u:: 63-u::
62--uid=:: 64--uid=::
@@ -66,8 +68,7 @@ OPTIONS
66--realtime=:: 68--realtime=::
67 Collect data with this RT SCHED_FIFO priority. 69 Collect data with this RT SCHED_FIFO priority.
68 70
69-D:: 71--no-buffering::
70--no-delay::
71 Collect data without buffering. 72 Collect data without buffering.
72 73
73-c:: 74-c::
@@ -201,11 +202,16 @@ abort events and some memory events in precise mode on modern Intel CPUs.
201--transaction:: 202--transaction::
202Record transaction flags for transaction related events. 203Record transaction flags for transaction related events.
203 204
204--force-per-cpu:: 205--per-thread::
205Force the use of per-cpu mmaps. By default, when tasks are specified (i.e. -p, 206Use per-thread mmaps. By default per-cpu mmaps are created. This option
206-t or -u options) per-thread mmaps are created. This option overrides that and 207overrides that and uses per-thread mmaps. A side-effect of that is that
207forces per-cpu mmaps. A side-effect of that is that inheritance is 208inheritance is automatically disabled. --per-thread is ignored with a warning
208automatically enabled. Add the -i option also to disable inheritance. 209if combined with -a or -C options.
210
211-D::
212--delay=::
213After starting the program, wait msecs before measuring. This is useful to
214filter out the startup phase of the program, which is often very different.
209 215
210SEE ALSO 216SEE ALSO
211-------- 217--------
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 10a279871251..8eab8a4bdeb8 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -237,6 +237,15 @@ OPTIONS
237 Do not show entries which have an overhead under that percent. 237 Do not show entries which have an overhead under that percent.
238 (Default: 0). 238 (Default: 0).
239 239
240--header::
241 Show header information in the perf.data file. This includes
242 various information like hostname, OS and perf version, cpu/mem
243 info, perf command line, event list and so on. Currently only
244 --stdio output supports this feature.
245
246--header-only::
247 Show only perf.data header (forces --stdio).
248
240SEE ALSO 249SEE ALSO
241-------- 250--------
242linkperf:perf-stat[1], linkperf:perf-annotate[1] 251linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index e9cbfcddfa3f..05f9a0a6784c 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -115,7 +115,7 @@ OPTIONS
115-f:: 115-f::
116--fields:: 116--fields::
117 Comma separated list of fields to print. Options are: 117 Comma separated list of fields to print. Options are:
118 comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff. 118 comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, srcline.
119 Field list can be prepended with the type, trace, sw or hw, 119 Field list can be prepended with the type, trace, sw or hw,
120 to indicate to which event type the field list applies. 120 to indicate to which event type the field list applies.
121 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace 121 e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace
@@ -203,6 +203,18 @@ OPTIONS
203--show-kernel-path:: 203--show-kernel-path::
204 Try to resolve the path of [kernel.kallsyms] 204 Try to resolve the path of [kernel.kallsyms]
205 205
206--show-task-events
207 Display task related events (e.g. FORK, COMM, EXIT).
208
209--show-mmap-events
210 Display mmap related events (e.g. MMAP, MMAP2).
211
212--header
213 Show perf.data header.
214
215--header-only
216 Show only perf.data header.
217
206SEE ALSO 218SEE ALSO
207-------- 219--------
208linkperf:perf-record[1], linkperf:perf-script-perl[1], 220linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 80c7da6732f2..29ee857c09c6 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -133,7 +133,7 @@ use --per-core in addition to -a. (system-wide). The output includes the
133core number and the number of online logical processors on that physical processor. 133core number and the number of online logical processors on that physical processor.
134 134
135-D msecs:: 135-D msecs::
136--initial-delay msecs:: 136--delay msecs::
137After starting the program, wait msecs before measuring. This is useful to 137After starting the program, wait msecs before measuring. This is useful to
138filter out the startup phase of the program, which is often very different. 138filter out the startup phase of the program, which is often very different.
139 139
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 3ff8bd4f0b4d..bc5990c33dc0 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -8,8 +8,7 @@ perf-timechart - Tool to visualize total system behavior during a workload
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf timechart' record <command> 11'perf timechart' [<timechart options>] {record} [<record options>]
12'perf timechart' [<options>]
13 12
14DESCRIPTION 13DESCRIPTION
15----------- 14-----------
@@ -21,8 +20,8 @@ There are two variants of perf timechart:
21 'perf timechart' to turn a trace into a Scalable Vector Graphics file, 20 'perf timechart' to turn a trace into a Scalable Vector Graphics file,
22 that can be viewed with popular SVG viewers such as 'Inkscape'. 21 that can be viewed with popular SVG viewers such as 'Inkscape'.
23 22
24OPTIONS 23TIMECHART OPTIONS
25------- 24-----------------
26-o:: 25-o::
27--output=:: 26--output=::
28 Select the output file (default: output.svg) 27 Select the output file (default: output.svg)
@@ -35,6 +34,9 @@ OPTIONS
35-P:: 34-P::
36--power-only:: 35--power-only::
37 Only output the CPU power section of the diagram 36 Only output the CPU power section of the diagram
37-T::
38--tasks-only::
39 Don't output processor state transitions
38-p:: 40-p::
39--process:: 41--process::
40 Select the processes to display, by name or PID 42 Select the processes to display, by name or PID
@@ -54,6 +56,38 @@ $ perf timechart
54 56
55 Written 10.2 seconds of trace to output.svg. 57 Written 10.2 seconds of trace to output.svg.
56 58
59Record system-wide timechart:
60
61 $ perf timechart record
62
63 then generate timechart and highlight 'gcc' tasks:
64
65 $ perf timechart --highlight gcc
66
67-n::
68--proc-num::
69 Print task info for at least given number of tasks.
70-t::
71--topology::
72 Sort CPUs according to topology.
73--highlight=<duration_nsecs|task_name>::
74 Highlight tasks (using different color) that run more than given
75 duration or tasks with given name. If number is given it's interpreted
76 as number of nanoseconds. If non-numeric string is given it's
77 interpreted as task name.
78
79RECORD OPTIONS
80--------------
81-P::
82--power-only::
83 Record only power-related events
84-T::
85--tasks-only::
86 Record only tasks-related events
87-g::
88--callchain::
89 Do call-graph (stack chain/backtrace) recording
90
57SEE ALSO 91SEE ALSO
58-------- 92--------
59linkperf:perf-record[1] 93linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 7de01dd79688..cdd8d4946dba 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -50,7 +50,6 @@ Default is to monitor all CPUS.
50--count-filter=<count>:: 50--count-filter=<count>::
51 Only display functions with more events than this. 51 Only display functions with more events than this.
52 52
53-g::
54--group:: 53--group::
55 Put the counters into a counter group. 54 Put the counters into a counter group.
56 55
@@ -143,12 +142,12 @@ Default is to monitor all CPUS.
143--asm-raw:: 142--asm-raw::
144 Show raw instruction encoding of assembly instructions. 143 Show raw instruction encoding of assembly instructions.
145 144
146-G:: 145-g::
147 Enables call-graph (stack chain/backtrace) recording. 146 Enables call-graph (stack chain/backtrace) recording.
148 147
149--call-graph:: 148--call-graph::
150 Setup and enable call-graph (stack chain/backtrace) recording, 149 Setup and enable call-graph (stack chain/backtrace) recording,
151 implies -G. 150 implies -g.
152 151
153--max-stack:: 152--max-stack::
154 Set the stack depth limit when parsing the callchain, anything 153 Set the stack depth limit when parsing the callchain, anything
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 025de796067c..f41572d0dd76 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -1,7 +1,11 @@
1tools/perf 1tools/perf
2tools/scripts 2tools/scripts
3tools/lib/traceevent 3tools/lib/traceevent
4tools/lib/lk 4tools/lib/api
5tools/lib/symbol/kallsyms.c
6tools/lib/symbol/kallsyms.h
7tools/include/asm/bug.h
8tools/include/linux/compiler.h
5include/linux/const.h 9include/linux/const.h
6include/linux/perf_event.h 10include/linux/perf_event.h
7include/linux/rbtree.h 11include/linux/rbtree.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 4835618a5608..cb2e5868c8e8 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -60,8 +60,11 @@ endef
60 60
61# 61#
62# Needed if no target specified: 62# Needed if no target specified:
63# (Except for tags and TAGS targets. The reason is that the
64# Makefile does not treat tags/TAGS as targets but as files
65# and thus won't rebuilt them once they are in place.)
63# 66#
64all: 67all tags TAGS:
65 $(print_msg) 68 $(print_msg)
66 $(make) 69 $(make)
67 70
@@ -72,8 +75,16 @@ clean:
72 $(make) 75 $(make)
73 76
74# 77#
78# The build-test target is not really parallel, don't print the jobs info:
79#
80build-test:
81 @$(MAKE) -f tests/make --no-print-directory
82
83#
75# All other targets get passed through: 84# All other targets get passed through:
76# 85#
77%: 86%:
78 $(print_msg) 87 $(print_msg)
79 $(make) 88 $(make)
89
90.PHONY: tags TAGS
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 7fc8f179cae7..7257e7e9e38a 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -76,6 +76,7 @@ $(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD
76 76
77CC = $(CROSS_COMPILE)gcc 77CC = $(CROSS_COMPILE)gcc
78AR = $(CROSS_COMPILE)ar 78AR = $(CROSS_COMPILE)ar
79PKG_CONFIG = $(CROSS_COMPILE)pkg-config
79 80
80RM = rm -f 81RM = rm -f
81LN = ln -f 82LN = ln -f
@@ -86,7 +87,7 @@ FLEX = flex
86BISON = bison 87BISON = bison
87STRIP = strip 88STRIP = strip
88 89
89LK_DIR = $(srctree)/tools/lib/lk/ 90LIB_DIR = $(srctree)/tools/lib/api/
90TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ 91TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
91 92
92# include config/Makefile by default and rule out 93# include config/Makefile by default and rule out
@@ -105,7 +106,7 @@ ifeq ($(config),1)
105include config/Makefile 106include config/Makefile
106endif 107endif
107 108
108export prefix bindir sharedir sysconfdir 109export prefix bindir sharedir sysconfdir DESTDIR
109 110
110# sparse is architecture-neutral, which means that we need to tell it 111# sparse is architecture-neutral, which means that we need to tell it
111# explicitly what architecture to check for. Fix this up for yours.. 112# explicitly what architecture to check for. Fix this up for yours..
@@ -127,20 +128,20 @@ strip-libs = $(filter-out -l%,$(1))
127ifneq ($(OUTPUT),) 128ifneq ($(OUTPUT),)
128 TE_PATH=$(OUTPUT) 129 TE_PATH=$(OUTPUT)
129ifneq ($(subdir),) 130ifneq ($(subdir),)
130 LK_PATH=$(OUTPUT)/../lib/lk/ 131 LIB_PATH=$(OUTPUT)/../lib/api/
131else 132else
132 LK_PATH=$(OUTPUT) 133 LIB_PATH=$(OUTPUT)
133endif 134endif
134else 135else
135 TE_PATH=$(TRACE_EVENT_DIR) 136 TE_PATH=$(TRACE_EVENT_DIR)
136 LK_PATH=$(LK_DIR) 137 LIB_PATH=$(LIB_DIR)
137endif 138endif
138 139
139LIBTRACEEVENT = $(TE_PATH)libtraceevent.a 140LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
140export LIBTRACEEVENT 141export LIBTRACEEVENT
141 142
142LIBLK = $(LK_PATH)liblk.a 143LIBAPIKFS = $(LIB_PATH)libapikfs.a
143export LIBLK 144export LIBAPIKFS
144 145
145# python extension build directories 146# python extension build directories
146PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ 147PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
@@ -151,7 +152,7 @@ export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
151python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so 152python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
152 153
153PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) 154PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
154PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK) 155PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPIKFS)
155 156
156$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) 157$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
157 $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ 158 $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \
@@ -202,6 +203,7 @@ $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
202 203
203LIB_FILE=$(OUTPUT)libperf.a 204LIB_FILE=$(OUTPUT)libperf.a
204 205
206LIB_H += ../lib/symbol/kallsyms.h
205LIB_H += ../../include/uapi/linux/perf_event.h 207LIB_H += ../../include/uapi/linux/perf_event.h
206LIB_H += ../../include/linux/rbtree.h 208LIB_H += ../../include/linux/rbtree.h
207LIB_H += ../../include/linux/list.h 209LIB_H += ../../include/linux/list.h
@@ -210,7 +212,7 @@ LIB_H += ../../include/linux/hash.h
210LIB_H += ../../include/linux/stringify.h 212LIB_H += ../../include/linux/stringify.h
211LIB_H += util/include/linux/bitmap.h 213LIB_H += util/include/linux/bitmap.h
212LIB_H += util/include/linux/bitops.h 214LIB_H += util/include/linux/bitops.h
213LIB_H += util/include/linux/compiler.h 215LIB_H += ../include/linux/compiler.h
214LIB_H += util/include/linux/const.h 216LIB_H += util/include/linux/const.h
215LIB_H += util/include/linux/ctype.h 217LIB_H += util/include/linux/ctype.h
216LIB_H += util/include/linux/kernel.h 218LIB_H += util/include/linux/kernel.h
@@ -225,7 +227,7 @@ LIB_H += util/include/linux/string.h
225LIB_H += util/include/linux/types.h 227LIB_H += util/include/linux/types.h
226LIB_H += util/include/linux/linkage.h 228LIB_H += util/include/linux/linkage.h
227LIB_H += util/include/asm/asm-offsets.h 229LIB_H += util/include/asm/asm-offsets.h
228LIB_H += util/include/asm/bug.h 230LIB_H += ../include/asm/bug.h
229LIB_H += util/include/asm/byteorder.h 231LIB_H += util/include/asm/byteorder.h
230LIB_H += util/include/asm/hweight.h 232LIB_H += util/include/asm/hweight.h
231LIB_H += util/include/asm/swab.h 233LIB_H += util/include/asm/swab.h
@@ -312,6 +314,7 @@ LIB_OBJS += $(OUTPUT)util/evlist.o
312LIB_OBJS += $(OUTPUT)util/evsel.o 314LIB_OBJS += $(OUTPUT)util/evsel.o
313LIB_OBJS += $(OUTPUT)util/exec_cmd.o 315LIB_OBJS += $(OUTPUT)util/exec_cmd.o
314LIB_OBJS += $(OUTPUT)util/help.o 316LIB_OBJS += $(OUTPUT)util/help.o
317LIB_OBJS += $(OUTPUT)util/kallsyms.o
315LIB_OBJS += $(OUTPUT)util/levenshtein.o 318LIB_OBJS += $(OUTPUT)util/levenshtein.o
316LIB_OBJS += $(OUTPUT)util/parse-options.o 319LIB_OBJS += $(OUTPUT)util/parse-options.o
317LIB_OBJS += $(OUTPUT)util/parse-events.o 320LIB_OBJS += $(OUTPUT)util/parse-events.o
@@ -353,6 +356,7 @@ LIB_OBJS += $(OUTPUT)util/pmu-bison.o
353LIB_OBJS += $(OUTPUT)util/trace-event-read.o 356LIB_OBJS += $(OUTPUT)util/trace-event-read.o
354LIB_OBJS += $(OUTPUT)util/trace-event-info.o 357LIB_OBJS += $(OUTPUT)util/trace-event-info.o
355LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o 358LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
359LIB_OBJS += $(OUTPUT)util/trace-event.o
356LIB_OBJS += $(OUTPUT)util/svghelper.o 360LIB_OBJS += $(OUTPUT)util/svghelper.o
357LIB_OBJS += $(OUTPUT)util/sort.o 361LIB_OBJS += $(OUTPUT)util/sort.o
358LIB_OBJS += $(OUTPUT)util/hist.o 362LIB_OBJS += $(OUTPUT)util/hist.o
@@ -438,7 +442,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
438BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o 442BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
439BUILTIN_OBJS += $(OUTPUT)builtin-mem.o 443BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
440 444
441PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT) 445PERFLIBS = $(LIB_FILE) $(LIBAPIKFS) $(LIBTRACEEVENT)
442 446
443# We choose to avoid "if .. else if .. else .. endif endif" 447# We choose to avoid "if .. else if .. else .. endif endif"
444# because maintaining the nesting to match is a pain. If 448# because maintaining the nesting to match is a pain. If
@@ -486,6 +490,7 @@ ifndef NO_SLANG
486 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o 490 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
487 LIB_OBJS += $(OUTPUT)ui/browsers/map.o 491 LIB_OBJS += $(OUTPUT)ui/browsers/map.o
488 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o 492 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
493 LIB_OBJS += $(OUTPUT)ui/browsers/header.o
489 LIB_OBJS += $(OUTPUT)ui/tui/setup.o 494 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
490 LIB_OBJS += $(OUTPUT)ui/tui/util.o 495 LIB_OBJS += $(OUTPUT)ui/tui/util.o
491 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o 496 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
@@ -671,6 +676,9 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
671$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS 676$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
672 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< 677 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $<
673 678
679$(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c $(OUTPUT)PERF-CFLAGS
680 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $<
681
674$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS 682$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
675 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 683 $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
676 684
@@ -710,26 +718,33 @@ $(LIB_FILE): $(LIB_OBJS)
710# libtraceevent.a 718# libtraceevent.a
711TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) 719TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch])
712 720
713$(LIBTRACEEVENT): $(TE_SOURCES) 721LIBTRACEEVENT_FLAGS = $(QUIET_SUBDIR1) O=$(OUTPUT)
714 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) CFLAGS="-g -Wall $(EXTRA_CFLAGS)" libtraceevent.a 722LIBTRACEEVENT_FLAGS += CFLAGS="-g -Wall $(EXTRA_CFLAGS)"
723LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ)
724
725$(LIBTRACEEVENT): $(TE_SOURCES) $(OUTPUT)PERF-CFLAGS
726 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) libtraceevent.a plugins
715 727
716$(LIBTRACEEVENT)-clean: 728$(LIBTRACEEVENT)-clean:
717 $(call QUIET_CLEAN, libtraceevent) 729 $(call QUIET_CLEAN, libtraceevent)
718 @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null 730 @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
719 731
720LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch]) 732install-traceevent-plugins: $(LIBTRACEEVENT)
733 $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins
734
735LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch])
721 736
722# if subdir is set, we've been called from above so target has been built 737# if subdir is set, we've been called from above so target has been built
723# already 738# already
724$(LIBLK): $(LIBLK_SOURCES) 739$(LIBAPIKFS): $(LIBAPIKFS_SOURCES)
725ifeq ($(subdir),) 740ifeq ($(subdir),)
726 $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a 741 $(QUIET_SUBDIR0)$(LIB_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libapikfs.a
727endif 742endif
728 743
729$(LIBLK)-clean: 744$(LIBAPIKFS)-clean:
730ifeq ($(subdir),) 745ifeq ($(subdir),)
731 $(call QUIET_CLEAN, liblk) 746 $(call QUIET_CLEAN, libapikfs)
732 @$(MAKE) -C $(LK_DIR) O=$(OUTPUT) clean >/dev/null 747 @$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
733endif 748endif
734 749
735help: 750help:
@@ -785,7 +800,7 @@ cscope:
785 800
786### Detect prefix changes 801### Detect prefix changes
787TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ 802TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
788 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) 803 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):$(plugindir_SQ)
789 804
790$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS 805$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
791 @FLAGS='$(TRACK_CFLAGS)'; \ 806 @FLAGS='$(TRACK_CFLAGS)'; \
@@ -840,16 +855,16 @@ ifndef NO_LIBPYTHON
840 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \ 855 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \
841 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 856 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
842endif 857endif
843 $(call QUIET_INSTALL, bash_completion-script) \ 858 $(call QUIET_INSTALL, perf_completion-script) \
844 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ 859 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \
845 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' 860 $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
846 $(call QUIET_INSTALL, tests) \ 861 $(call QUIET_INSTALL, tests) \
847 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ 862 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
848 $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ 863 $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \
849 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ 864 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
850 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' 865 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
851 866
852install: install-bin try-install-man 867install: install-bin try-install-man install-traceevent-plugins
853 868
854install-python_ext: 869install-python_ext:
855 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' 870 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
@@ -868,12 +883,11 @@ config-clean:
868 $(call QUIET_CLEAN, config) 883 $(call QUIET_CLEAN, config)
869 @$(MAKE) -C config/feature-checks clean >/dev/null 884 @$(MAKE) -C config/feature-checks clean >/dev/null
870 885
871clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean config-clean 886clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
872 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) 887 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
873 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf 888 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
874 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* 889 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
875 $(call QUIET_CLEAN, Documentation) 890 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
876 @$(MAKE) -C Documentation O=$(OUTPUT) clean >/dev/null
877 $(python-clean) 891 $(python-clean)
878 892
879# 893#
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c
index aacef07ebf31..42faf369211c 100644
--- a/tools/perf/arch/common.c
+++ b/tools/perf/arch/common.c
@@ -154,8 +154,7 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
154 } 154 }
155 if (lookup_path(buf)) 155 if (lookup_path(buf))
156 goto out; 156 goto out;
157 free(buf); 157 zfree(&buf);
158 buf = NULL;
159 } 158 }
160 159
161 if (!strcmp(arch, "arm")) 160 if (!strcmp(arch, "arm"))
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 4087ab19823c..0da603b79b61 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -69,15 +69,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
69 if (he == NULL) 69 if (he == NULL)
70 return -ENOMEM; 70 return -ENOMEM;
71 71
72 ret = 0; 72 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
73 if (he->ms.sym != NULL) {
74 struct annotation *notes = symbol__annotation(he->ms.sym);
75 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
76 return -ENOMEM;
77
78 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
79 }
80
81 evsel->hists.stats.total_period += sample->period; 73 evsel->hists.stats.total_period += sample->period;
82 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 74 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
83 return ret; 75 return ret;
@@ -188,8 +180,7 @@ find_next:
188 * symbol, free he->ms.sym->src to signal we already 180 * symbol, free he->ms.sym->src to signal we already
189 * processed this symbol. 181 * processed this symbol.
190 */ 182 */
191 free(notes->src); 183 zfree(&notes->src);
192 notes->src = NULL;
193 } 184 }
194 } 185 }
195} 186}
@@ -241,7 +232,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
241 perf_session__fprintf_dsos(session, stdout); 232 perf_session__fprintf_dsos(session, stdout);
242 233
243 total_nr_samples = 0; 234 total_nr_samples = 0;
244 list_for_each_entry(pos, &session->evlist->entries, node) { 235 evlist__for_each(session->evlist, pos) {
245 struct hists *hists = &pos->hists; 236 struct hists *hists = &pos->hists;
246 u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 237 u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
247 238
@@ -373,7 +364,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
373 364
374 if (argc) { 365 if (argc) {
375 /* 366 /*
376 * Special case: if there's an argument left then assume tha 367 * Special case: if there's an argument left then assume that
377 * it's a symbol filter: 368 * it's a symbol filter:
378 */ 369 */
379 if (argc > 1) 370 if (argc > 1)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 3b67ea2444bd..a77e31246c00 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -356,9 +356,10 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
356{ 356{
357 struct perf_evsel *e; 357 struct perf_evsel *e;
358 358
359 list_for_each_entry(e, &evlist->entries, node) 359 evlist__for_each(evlist, e) {
360 if (perf_evsel__match2(evsel, e)) 360 if (perf_evsel__match2(evsel, e))
361 return e; 361 return e;
362 }
362 363
363 return NULL; 364 return NULL;
364} 365}
@@ -367,7 +368,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
367{ 368{
368 struct perf_evsel *evsel; 369 struct perf_evsel *evsel;
369 370
370 list_for_each_entry(evsel, &evlist->entries, node) { 371 evlist__for_each(evlist, evsel) {
371 struct hists *hists = &evsel->hists; 372 struct hists *hists = &evsel->hists;
372 373
373 hists__collapse_resort(hists, NULL); 374 hists__collapse_resort(hists, NULL);
@@ -614,7 +615,7 @@ static void data_process(void)
614 struct perf_evsel *evsel_base; 615 struct perf_evsel *evsel_base;
615 bool first = true; 616 bool first = true;
616 617
617 list_for_each_entry(evsel_base, &evlist_base->entries, node) { 618 evlist__for_each(evlist_base, evsel_base) {
618 struct data__file *d; 619 struct data__file *d;
619 int i; 620 int i;
620 621
@@ -654,7 +655,7 @@ static void data__free(struct data__file *d)
654 for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) { 655 for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
655 struct diff_hpp_fmt *fmt = &d->fmt[col]; 656 struct diff_hpp_fmt *fmt = &d->fmt[col];
656 657
657 free(fmt->header); 658 zfree(&fmt->header);
658 } 659 }
659} 660}
660 661
@@ -769,6 +770,81 @@ static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
769 return ret; 770 return ret;
770} 771}
771 772
773static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
774 struct perf_hpp *hpp, struct hist_entry *he,
775 int comparison_method)
776{
777 struct diff_hpp_fmt *dfmt =
778 container_of(fmt, struct diff_hpp_fmt, fmt);
779 struct hist_entry *pair = get_pair_fmt(he, dfmt);
780 double diff;
781 s64 wdiff;
782 char pfmt[20] = " ";
783
784 if (!pair)
785 goto dummy_print;
786
787 switch (comparison_method) {
788 case COMPUTE_DELTA:
789 if (pair->diff.computed)
790 diff = pair->diff.period_ratio_delta;
791 else
792 diff = compute_delta(he, pair);
793
794 if (fabs(diff) < 0.01)
795 goto dummy_print;
796 scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1);
797 return percent_color_snprintf(hpp->buf, hpp->size,
798 pfmt, diff);
799 case COMPUTE_RATIO:
800 if (he->dummy)
801 goto dummy_print;
802 if (pair->diff.computed)
803 diff = pair->diff.period_ratio;
804 else
805 diff = compute_ratio(he, pair);
806
807 scnprintf(pfmt, 20, "%%%d.6f", dfmt->header_width);
808 return value_color_snprintf(hpp->buf, hpp->size,
809 pfmt, diff);
810 case COMPUTE_WEIGHTED_DIFF:
811 if (he->dummy)
812 goto dummy_print;
813 if (pair->diff.computed)
814 wdiff = pair->diff.wdiff;
815 else
816 wdiff = compute_wdiff(he, pair);
817
818 scnprintf(pfmt, 20, "%%14ld", dfmt->header_width);
819 return color_snprintf(hpp->buf, hpp->size,
820 get_percent_color(wdiff),
821 pfmt, wdiff);
822 default:
823 BUG_ON(1);
824 }
825dummy_print:
826 return scnprintf(hpp->buf, hpp->size, "%*s",
827 dfmt->header_width, pfmt);
828}
829
830static int hpp__color_delta(struct perf_hpp_fmt *fmt,
831 struct perf_hpp *hpp, struct hist_entry *he)
832{
833 return __hpp__color_compare(fmt, hpp, he, COMPUTE_DELTA);
834}
835
836static int hpp__color_ratio(struct perf_hpp_fmt *fmt,
837 struct perf_hpp *hpp, struct hist_entry *he)
838{
839 return __hpp__color_compare(fmt, hpp, he, COMPUTE_RATIO);
840}
841
842static int hpp__color_wdiff(struct perf_hpp_fmt *fmt,
843 struct perf_hpp *hpp, struct hist_entry *he)
844{
845 return __hpp__color_compare(fmt, hpp, he, COMPUTE_WEIGHTED_DIFF);
846}
847
772static void 848static void
773hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size) 849hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
774{ 850{
@@ -940,8 +1016,22 @@ static void data__hpp_register(struct data__file *d, int idx)
940 fmt->entry = hpp__entry_global; 1016 fmt->entry = hpp__entry_global;
941 1017
942 /* TODO more colors */ 1018 /* TODO more colors */
943 if (idx == PERF_HPP_DIFF__BASELINE) 1019 switch (idx) {
1020 case PERF_HPP_DIFF__BASELINE:
944 fmt->color = hpp__color_baseline; 1021 fmt->color = hpp__color_baseline;
1022 break;
1023 case PERF_HPP_DIFF__DELTA:
1024 fmt->color = hpp__color_delta;
1025 break;
1026 case PERF_HPP_DIFF__RATIO:
1027 fmt->color = hpp__color_ratio;
1028 break;
1029 case PERF_HPP_DIFF__WEIGHTED_DIFF:
1030 fmt->color = hpp__color_wdiff;
1031 break;
1032 default:
1033 break;
1034 }
945 1035
946 init_header(d, dfmt); 1036 init_header(d, dfmt);
947 perf_hpp__column_register(fmt); 1037 perf_hpp__column_register(fmt);
@@ -1000,8 +1090,7 @@ static int data_init(int argc, const char **argv)
1000 data__files_cnt = argc; 1090 data__files_cnt = argc;
1001 use_default = false; 1091 use_default = false;
1002 } 1092 }
1003 } else if (symbol_conf.default_guest_vmlinux_name || 1093 } else if (perf_guest) {
1004 symbol_conf.default_guest_kallsyms) {
1005 defaults[0] = "perf.data.host"; 1094 defaults[0] = "perf.data.host";
1006 defaults[1] = "perf.data.guest"; 1095 defaults[1] = "perf.data.guest";
1007 } 1096 }
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 20b0f12763b0..c99e0de7e54a 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -29,7 +29,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
29 if (session == NULL) 29 if (session == NULL)
30 return -ENOMEM; 30 return -ENOMEM;
31 31
32 list_for_each_entry(pos, &session->evlist->entries, node) 32 evlist__for_each(session->evlist, pos)
33 perf_evsel__fprintf(pos, details, stdout); 33 perf_evsel__fprintf(pos, details, stdout);
34 34
35 perf_session__delete(session); 35 perf_session__delete(session);
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 6a2508589460..b3466018bbd7 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -22,14 +22,13 @@
22#include <linux/list.h> 22#include <linux/list.h>
23 23
24struct perf_inject { 24struct perf_inject {
25 struct perf_tool tool; 25 struct perf_tool tool;
26 bool build_ids; 26 bool build_ids;
27 bool sched_stat; 27 bool sched_stat;
28 const char *input_name; 28 const char *input_name;
29 int pipe_output, 29 struct perf_data_file output;
30 output; 30 u64 bytes_written;
31 u64 bytes_written; 31 struct list_head samples;
32 struct list_head samples;
33}; 32};
34 33
35struct event_entry { 34struct event_entry {
@@ -42,21 +41,14 @@ static int perf_event__repipe_synth(struct perf_tool *tool,
42 union perf_event *event) 41 union perf_event *event)
43{ 42{
44 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 43 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
45 uint32_t size; 44 ssize_t size;
46 void *buf = event;
47 45
48 size = event->header.size; 46 size = perf_data_file__write(&inject->output, event,
49 47 event->header.size);
50 while (size) { 48 if (size < 0)
51 int ret = write(inject->output, buf, size); 49 return -errno;
52 if (ret < 0)
53 return -errno;
54
55 size -= ret;
56 buf += ret;
57 inject->bytes_written += ret;
58 }
59 50
51 inject->bytes_written += size;
60 return 0; 52 return 0;
61} 53}
62 54
@@ -80,7 +72,7 @@ static int perf_event__repipe_attr(struct perf_tool *tool,
80 if (ret) 72 if (ret)
81 return ret; 73 return ret;
82 74
83 if (!inject->pipe_output) 75 if (&inject->output.is_pipe)
84 return 0; 76 return 0;
85 77
86 return perf_event__repipe_synth(tool, event); 78 return perf_event__repipe_synth(tool, event);
@@ -355,6 +347,7 @@ static int __cmd_inject(struct perf_inject *inject)
355 .path = inject->input_name, 347 .path = inject->input_name,
356 .mode = PERF_DATA_MODE_READ, 348 .mode = PERF_DATA_MODE_READ,
357 }; 349 };
350 struct perf_data_file *file_out = &inject->output;
358 351
359 signal(SIGINT, sig_handler); 352 signal(SIGINT, sig_handler);
360 353
@@ -376,7 +369,7 @@ static int __cmd_inject(struct perf_inject *inject)
376 369
377 inject->tool.ordered_samples = true; 370 inject->tool.ordered_samples = true;
378 371
379 list_for_each_entry(evsel, &session->evlist->entries, node) { 372 evlist__for_each(session->evlist, evsel) {
380 const char *name = perf_evsel__name(evsel); 373 const char *name = perf_evsel__name(evsel);
381 374
382 if (!strcmp(name, "sched:sched_switch")) { 375 if (!strcmp(name, "sched:sched_switch")) {
@@ -391,14 +384,14 @@ static int __cmd_inject(struct perf_inject *inject)
391 } 384 }
392 } 385 }
393 386
394 if (!inject->pipe_output) 387 if (!file_out->is_pipe)
395 lseek(inject->output, session->header.data_offset, SEEK_SET); 388 lseek(file_out->fd, session->header.data_offset, SEEK_SET);
396 389
397 ret = perf_session__process_events(session, &inject->tool); 390 ret = perf_session__process_events(session, &inject->tool);
398 391
399 if (!inject->pipe_output) { 392 if (!file_out->is_pipe) {
400 session->header.data_size = inject->bytes_written; 393 session->header.data_size = inject->bytes_written;
401 perf_session__write_header(session, session->evlist, inject->output, true); 394 perf_session__write_header(session, session->evlist, file_out->fd, true);
402 } 395 }
403 396
404 perf_session__delete(session); 397 perf_session__delete(session);
@@ -427,14 +420,17 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
427 }, 420 },
428 .input_name = "-", 421 .input_name = "-",
429 .samples = LIST_HEAD_INIT(inject.samples), 422 .samples = LIST_HEAD_INIT(inject.samples),
423 .output = {
424 .path = "-",
425 .mode = PERF_DATA_MODE_WRITE,
426 },
430 }; 427 };
431 const char *output_name = "-";
432 const struct option options[] = { 428 const struct option options[] = {
433 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 429 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
434 "Inject build-ids into the output stream"), 430 "Inject build-ids into the output stream"),
435 OPT_STRING('i', "input", &inject.input_name, "file", 431 OPT_STRING('i', "input", &inject.input_name, "file",
436 "input file name"), 432 "input file name"),
437 OPT_STRING('o', "output", &output_name, "file", 433 OPT_STRING('o', "output", &inject.output.path, "file",
438 "output file name"), 434 "output file name"),
439 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, 435 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
440 "Merge sched-stat and sched-switch for getting events " 436 "Merge sched-stat and sched-switch for getting events "
@@ -456,16 +452,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
456 if (argc) 452 if (argc)
457 usage_with_options(inject_usage, options); 453 usage_with_options(inject_usage, options);
458 454
459 if (!strcmp(output_name, "-")) { 455 if (perf_data_file__open(&inject.output)) {
460 inject.pipe_output = 1; 456 perror("failed to create output file");
461 inject.output = STDOUT_FILENO; 457 return -1;
462 } else {
463 inject.output = open(output_name, O_CREAT | O_WRONLY | O_TRUNC,
464 S_IRUSR | S_IWUSR);
465 if (inject.output < 0) {
466 perror("failed to create output file");
467 return -1;
468 }
469 } 458 }
470 459
471 if (symbol__init() < 0) 460 if (symbol__init() < 0)
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index f8bf5f244d77..a7350519c63f 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -13,7 +13,7 @@
13#include "util/parse-options.h" 13#include "util/parse-options.h"
14#include "util/trace-event.h" 14#include "util/trace-event.h"
15#include "util/debug.h" 15#include "util/debug.h"
16#include <lk/debugfs.h> 16#include <api/fs/debugfs.h>
17#include "util/tool.h" 17#include "util/tool.h"
18#include "util/stat.h" 18#include "util/stat.h"
19#include "util/top.h" 19#include "util/top.h"
@@ -89,7 +89,7 @@ struct exit_reasons_table {
89 89
90struct perf_kvm_stat { 90struct perf_kvm_stat {
91 struct perf_tool tool; 91 struct perf_tool tool;
92 struct perf_record_opts opts; 92 struct record_opts opts;
93 struct perf_evlist *evlist; 93 struct perf_evlist *evlist;
94 struct perf_session *session; 94 struct perf_session *session;
95 95
@@ -1158,9 +1158,7 @@ out:
1158 if (kvm->timerfd >= 0) 1158 if (kvm->timerfd >= 0)
1159 close(kvm->timerfd); 1159 close(kvm->timerfd);
1160 1160
1161 if (pollfds) 1161 free(pollfds);
1162 free(pollfds);
1163
1164 return err; 1162 return err;
1165} 1163}
1166 1164
@@ -1176,7 +1174,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
1176 * Note: exclude_{guest,host} do not apply here. 1174 * Note: exclude_{guest,host} do not apply here.
1177 * This command processes KVM tracepoints from host only 1175 * This command processes KVM tracepoints from host only
1178 */ 1176 */
1179 list_for_each_entry(pos, &evlist->entries, node) { 1177 evlist__for_each(evlist, pos) {
1180 struct perf_event_attr *attr = &pos->attr; 1178 struct perf_event_attr *attr = &pos->attr;
1181 1179
1182 /* make sure these *are* set */ 1180 /* make sure these *are* set */
@@ -1232,7 +1230,7 @@ static int read_events(struct perf_kvm_stat *kvm)
1232 .ordered_samples = true, 1230 .ordered_samples = true,
1233 }; 1231 };
1234 struct perf_data_file file = { 1232 struct perf_data_file file = {
1235 .path = input_name, 1233 .path = kvm->file_name,
1236 .mode = PERF_DATA_MODE_READ, 1234 .mode = PERF_DATA_MODE_READ,
1237 }; 1235 };
1238 1236
@@ -1558,10 +1556,8 @@ out:
1558 if (kvm->session) 1556 if (kvm->session)
1559 perf_session__delete(kvm->session); 1557 perf_session__delete(kvm->session);
1560 kvm->session = NULL; 1558 kvm->session = NULL;
1561 if (kvm->evlist) { 1559 if (kvm->evlist)
1562 perf_evlist__delete_maps(kvm->evlist);
1563 perf_evlist__delete(kvm->evlist); 1560 perf_evlist__delete(kvm->evlist);
1564 }
1565 1561
1566 return err; 1562 return err;
1567} 1563}
@@ -1690,6 +1686,8 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
1690 "file", "file saving guest os /proc/kallsyms"), 1686 "file", "file saving guest os /proc/kallsyms"),
1691 OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, 1687 OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules,
1692 "file", "file saving guest os /proc/modules"), 1688 "file", "file saving guest os /proc/modules"),
1689 OPT_INCR('v', "verbose", &verbose,
1690 "be more verbose (show counter open errors, etc)"),
1693 OPT_END() 1691 OPT_END()
1694 }; 1692 };
1695 1693
@@ -1711,12 +1709,7 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
1711 perf_guest = 1; 1709 perf_guest = 1;
1712 1710
1713 if (!file_name) { 1711 if (!file_name) {
1714 if (perf_host && !perf_guest) 1712 file_name = get_filename_for_perf_kvm();
1715 file_name = strdup("perf.data.host");
1716 else if (!perf_host && perf_guest)
1717 file_name = strdup("perf.data.guest");
1718 else
1719 file_name = strdup("perf.data.kvm");
1720 1713
1721 if (!file_name) { 1714 if (!file_name) {
1722 pr_err("Failed to allocate memory for filename\n"); 1715 pr_err("Failed to allocate memory for filename\n");
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 31c00f186da1..2e3ade69a58e 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -62,7 +62,6 @@ static int
62dump_raw_samples(struct perf_tool *tool, 62dump_raw_samples(struct perf_tool *tool,
63 union perf_event *event, 63 union perf_event *event,
64 struct perf_sample *sample, 64 struct perf_sample *sample,
65 struct perf_evsel *evsel __maybe_unused,
66 struct machine *machine) 65 struct machine *machine)
67{ 66{
68 struct perf_mem *mem = container_of(tool, struct perf_mem, tool); 67 struct perf_mem *mem = container_of(tool, struct perf_mem, tool);
@@ -112,10 +111,10 @@ dump_raw_samples(struct perf_tool *tool,
112static int process_sample_event(struct perf_tool *tool, 111static int process_sample_event(struct perf_tool *tool,
113 union perf_event *event, 112 union perf_event *event,
114 struct perf_sample *sample, 113 struct perf_sample *sample,
115 struct perf_evsel *evsel, 114 struct perf_evsel *evsel __maybe_unused,
116 struct machine *machine) 115 struct machine *machine)
117{ 116{
118 return dump_raw_samples(tool, event, sample, evsel, machine); 117 return dump_raw_samples(tool, event, sample, machine);
119} 118}
120 119
121static int report_raw_events(struct perf_mem *mem) 120static int report_raw_events(struct perf_mem *mem)
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 6ea9e85bdc00..78948882e3de 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -37,7 +37,7 @@
37#include "util/strfilter.h" 37#include "util/strfilter.h"
38#include "util/symbol.h" 38#include "util/symbol.h"
39#include "util/debug.h" 39#include "util/debug.h"
40#include <lk/debugfs.h> 40#include <api/fs/debugfs.h>
41#include "util/parse-options.h" 41#include "util/parse-options.h"
42#include "util/probe-finder.h" 42#include "util/probe-finder.h"
43#include "util/probe-event.h" 43#include "util/probe-event.h"
@@ -59,7 +59,7 @@ static struct {
59 struct perf_probe_event events[MAX_PROBES]; 59 struct perf_probe_event events[MAX_PROBES];
60 struct strlist *dellist; 60 struct strlist *dellist;
61 struct line_range line_range; 61 struct line_range line_range;
62 const char *target; 62 char *target;
63 int max_probe_points; 63 int max_probe_points;
64 struct strfilter *filter; 64 struct strfilter *filter;
65} params; 65} params;
@@ -98,7 +98,10 @@ static int set_target(const char *ptr)
98 * short module name. 98 * short module name.
99 */ 99 */
100 if (!params.target && ptr && *ptr == '/') { 100 if (!params.target && ptr && *ptr == '/') {
101 params.target = ptr; 101 params.target = strdup(ptr);
102 if (!params.target)
103 return -ENOMEM;
104
102 found = 1; 105 found = 1;
103 buf = ptr + (strlen(ptr) - 3); 106 buf = ptr + (strlen(ptr) - 3);
104 107
@@ -116,6 +119,9 @@ static int parse_probe_event_argv(int argc, const char **argv)
116 char *buf; 119 char *buf;
117 120
118 found_target = set_target(argv[0]); 121 found_target = set_target(argv[0]);
122 if (found_target < 0)
123 return found_target;
124
119 if (found_target && argc == 1) 125 if (found_target && argc == 1)
120 return 0; 126 return 0;
121 127
@@ -169,6 +175,7 @@ static int opt_set_target(const struct option *opt, const char *str,
169 int unset __maybe_unused) 175 int unset __maybe_unused)
170{ 176{
171 int ret = -ENOENT; 177 int ret = -ENOENT;
178 char *tmp;
172 179
173 if (str && !params.target) { 180 if (str && !params.target) {
174 if (!strcmp(opt->long_name, "exec")) 181 if (!strcmp(opt->long_name, "exec"))
@@ -180,7 +187,19 @@ static int opt_set_target(const struct option *opt, const char *str,
180 else 187 else
181 return ret; 188 return ret;
182 189
183 params.target = str; 190 /* Expand given path to absolute path, except for modulename */
191 if (params.uprobes || strchr(str, '/')) {
192 tmp = realpath(str, NULL);
193 if (!tmp) {
194 pr_warning("Failed to get the absolute path of %s: %m\n", str);
195 return ret;
196 }
197 } else {
198 tmp = strdup(str);
199 if (!tmp)
200 return -ENOMEM;
201 }
202 params.target = tmp;
184 ret = 0; 203 ret = 0;
185 } 204 }
186 205
@@ -204,7 +223,6 @@ static int opt_show_lines(const struct option *opt __maybe_unused,
204 223
205 params.show_lines = true; 224 params.show_lines = true;
206 ret = parse_line_range_desc(str, &params.line_range); 225 ret = parse_line_range_desc(str, &params.line_range);
207 INIT_LIST_HEAD(&params.line_range.line_list);
208 226
209 return ret; 227 return ret;
210} 228}
@@ -250,7 +268,28 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
250 return 0; 268 return 0;
251} 269}
252 270
253int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) 271static void init_params(void)
272{
273 line_range__init(&params.line_range);
274}
275
276static void cleanup_params(void)
277{
278 int i;
279
280 for (i = 0; i < params.nevents; i++)
281 clear_perf_probe_event(params.events + i);
282 if (params.dellist)
283 strlist__delete(params.dellist);
284 line_range__clear(&params.line_range);
285 free(params.target);
286 if (params.filter)
287 strfilter__delete(params.filter);
288 memset(&params, 0, sizeof(params));
289}
290
291static int
292__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
254{ 293{
255 const char * const probe_usage[] = { 294 const char * const probe_usage[] = {
256 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 295 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
@@ -404,6 +443,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
404 ret = show_available_funcs(params.target, params.filter, 443 ret = show_available_funcs(params.target, params.filter,
405 params.uprobes); 444 params.uprobes);
406 strfilter__delete(params.filter); 445 strfilter__delete(params.filter);
446 params.filter = NULL;
407 if (ret < 0) 447 if (ret < 0)
408 pr_err(" Error: Failed to show functions." 448 pr_err(" Error: Failed to show functions."
409 " (%d)\n", ret); 449 " (%d)\n", ret);
@@ -411,7 +451,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
411 } 451 }
412 452
413#ifdef HAVE_DWARF_SUPPORT 453#ifdef HAVE_DWARF_SUPPORT
414 if (params.show_lines && !params.uprobes) { 454 if (params.show_lines) {
415 if (params.mod_events) { 455 if (params.mod_events) {
416 pr_err(" Error: Don't use --line with" 456 pr_err(" Error: Don't use --line with"
417 " --add/--del.\n"); 457 " --add/--del.\n");
@@ -443,6 +483,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
443 params.filter, 483 params.filter,
444 params.show_ext_vars); 484 params.show_ext_vars);
445 strfilter__delete(params.filter); 485 strfilter__delete(params.filter);
486 params.filter = NULL;
446 if (ret < 0) 487 if (ret < 0)
447 pr_err(" Error: Failed to show vars. (%d)\n", ret); 488 pr_err(" Error: Failed to show vars. (%d)\n", ret);
448 return ret; 489 return ret;
@@ -451,7 +492,6 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
451 492
452 if (params.dellist) { 493 if (params.dellist) {
453 ret = del_perf_probe_events(params.dellist); 494 ret = del_perf_probe_events(params.dellist);
454 strlist__delete(params.dellist);
455 if (ret < 0) { 495 if (ret < 0) {
456 pr_err(" Error: Failed to delete events. (%d)\n", ret); 496 pr_err(" Error: Failed to delete events. (%d)\n", ret);
457 return ret; 497 return ret;
@@ -470,3 +510,14 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
470 } 510 }
471 return 0; 511 return 0;
472} 512}
513
514int cmd_probe(int argc, const char **argv, const char *prefix)
515{
516 int ret;
517
518 init_params();
519 ret = __cmd_probe(argc, argv, prefix);
520 cleanup_params();
521
522 return ret;
523}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 7c8020a32784..3c394bf16fa8 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -62,9 +62,9 @@ static void __handle_on_exit_funcs(void)
62} 62}
63#endif 63#endif
64 64
65struct perf_record { 65struct record {
66 struct perf_tool tool; 66 struct perf_tool tool;
67 struct perf_record_opts opts; 67 struct record_opts opts;
68 u64 bytes_written; 68 u64 bytes_written;
69 struct perf_data_file file; 69 struct perf_data_file file;
70 struct perf_evlist *evlist; 70 struct perf_evlist *evlist;
@@ -76,46 +76,27 @@ struct perf_record {
76 long samples; 76 long samples;
77}; 77};
78 78
79static int do_write_output(struct perf_record *rec, void *buf, size_t size) 79static int record__write(struct record *rec, void *bf, size_t size)
80{ 80{
81 struct perf_data_file *file = &rec->file; 81 if (perf_data_file__write(rec->session->file, bf, size) < 0) {
82 82 pr_err("failed to write perf data, error: %m\n");
83 while (size) { 83 return -1;
84 ssize_t ret = write(file->fd, buf, size);
85
86 if (ret < 0) {
87 pr_err("failed to write perf data, error: %m\n");
88 return -1;
89 }
90
91 size -= ret;
92 buf += ret;
93
94 rec->bytes_written += ret;
95 } 84 }
96 85
86 rec->bytes_written += size;
97 return 0; 87 return 0;
98} 88}
99 89
100static int write_output(struct perf_record *rec, void *buf, size_t size)
101{
102 return do_write_output(rec, buf, size);
103}
104
105static int process_synthesized_event(struct perf_tool *tool, 90static int process_synthesized_event(struct perf_tool *tool,
106 union perf_event *event, 91 union perf_event *event,
107 struct perf_sample *sample __maybe_unused, 92 struct perf_sample *sample __maybe_unused,
108 struct machine *machine __maybe_unused) 93 struct machine *machine __maybe_unused)
109{ 94{
110 struct perf_record *rec = container_of(tool, struct perf_record, tool); 95 struct record *rec = container_of(tool, struct record, tool);
111 if (write_output(rec, event, event->header.size) < 0) 96 return record__write(rec, event, event->header.size);
112 return -1;
113
114 return 0;
115} 97}
116 98
117static int perf_record__mmap_read(struct perf_record *rec, 99static int record__mmap_read(struct record *rec, struct perf_mmap *md)
118 struct perf_mmap *md)
119{ 100{
120 unsigned int head = perf_mmap__read_head(md); 101 unsigned int head = perf_mmap__read_head(md);
121 unsigned int old = md->prev; 102 unsigned int old = md->prev;
@@ -136,7 +117,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
136 size = md->mask + 1 - (old & md->mask); 117 size = md->mask + 1 - (old & md->mask);
137 old += size; 118 old += size;
138 119
139 if (write_output(rec, buf, size) < 0) { 120 if (record__write(rec, buf, size) < 0) {
140 rc = -1; 121 rc = -1;
141 goto out; 122 goto out;
142 } 123 }
@@ -146,7 +127,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
146 size = head - old; 127 size = head - old;
147 old += size; 128 old += size;
148 129
149 if (write_output(rec, buf, size) < 0) { 130 if (record__write(rec, buf, size) < 0) {
150 rc = -1; 131 rc = -1;
151 goto out; 132 goto out;
152 } 133 }
@@ -171,9 +152,9 @@ static void sig_handler(int sig)
171 signr = sig; 152 signr = sig;
172} 153}
173 154
174static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg) 155static void record__sig_exit(int exit_status __maybe_unused, void *arg)
175{ 156{
176 struct perf_record *rec = arg; 157 struct record *rec = arg;
177 int status; 158 int status;
178 159
179 if (rec->evlist->workload.pid > 0) { 160 if (rec->evlist->workload.pid > 0) {
@@ -191,18 +172,18 @@ static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg)
191 signal(signr, SIG_DFL); 172 signal(signr, SIG_DFL);
192} 173}
193 174
194static int perf_record__open(struct perf_record *rec) 175static int record__open(struct record *rec)
195{ 176{
196 char msg[512]; 177 char msg[512];
197 struct perf_evsel *pos; 178 struct perf_evsel *pos;
198 struct perf_evlist *evlist = rec->evlist; 179 struct perf_evlist *evlist = rec->evlist;
199 struct perf_session *session = rec->session; 180 struct perf_session *session = rec->session;
200 struct perf_record_opts *opts = &rec->opts; 181 struct record_opts *opts = &rec->opts;
201 int rc = 0; 182 int rc = 0;
202 183
203 perf_evlist__config(evlist, opts); 184 perf_evlist__config(evlist, opts);
204 185
205 list_for_each_entry(pos, &evlist->entries, node) { 186 evlist__for_each(evlist, pos) {
206try_again: 187try_again:
207 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { 188 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
208 if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { 189 if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
@@ -232,7 +213,7 @@ try_again:
232 "Consider increasing " 213 "Consider increasing "
233 "/proc/sys/kernel/perf_event_mlock_kb,\n" 214 "/proc/sys/kernel/perf_event_mlock_kb,\n"
234 "or try again with a smaller value of -m/--mmap_pages.\n" 215 "or try again with a smaller value of -m/--mmap_pages.\n"
235 "(current value: %d)\n", opts->mmap_pages); 216 "(current value: %u)\n", opts->mmap_pages);
236 rc = -errno; 217 rc = -errno;
237 } else { 218 } else {
238 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); 219 pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno));
@@ -247,7 +228,7 @@ out:
247 return rc; 228 return rc;
248} 229}
249 230
250static int process_buildids(struct perf_record *rec) 231static int process_buildids(struct record *rec)
251{ 232{
252 struct perf_data_file *file = &rec->file; 233 struct perf_data_file *file = &rec->file;
253 struct perf_session *session = rec->session; 234 struct perf_session *session = rec->session;
@@ -262,9 +243,9 @@ static int process_buildids(struct perf_record *rec)
262 size, &build_id__mark_dso_hit_ops); 243 size, &build_id__mark_dso_hit_ops);
263} 244}
264 245
265static void perf_record__exit(int status, void *arg) 246static void record__exit(int status, void *arg)
266{ 247{
267 struct perf_record *rec = arg; 248 struct record *rec = arg;
268 struct perf_data_file *file = &rec->file; 249 struct perf_data_file *file = &rec->file;
269 250
270 if (status != 0) 251 if (status != 0)
@@ -320,14 +301,14 @@ static struct perf_event_header finished_round_event = {
320 .type = PERF_RECORD_FINISHED_ROUND, 301 .type = PERF_RECORD_FINISHED_ROUND,
321}; 302};
322 303
323static int perf_record__mmap_read_all(struct perf_record *rec) 304static int record__mmap_read_all(struct record *rec)
324{ 305{
325 int i; 306 int i;
326 int rc = 0; 307 int rc = 0;
327 308
328 for (i = 0; i < rec->evlist->nr_mmaps; i++) { 309 for (i = 0; i < rec->evlist->nr_mmaps; i++) {
329 if (rec->evlist->mmap[i].base) { 310 if (rec->evlist->mmap[i].base) {
330 if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { 311 if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) {
331 rc = -1; 312 rc = -1;
332 goto out; 313 goto out;
333 } 314 }
@@ -335,16 +316,14 @@ static int perf_record__mmap_read_all(struct perf_record *rec)
335 } 316 }
336 317
337 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) 318 if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
338 rc = write_output(rec, &finished_round_event, 319 rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
339 sizeof(finished_round_event));
340 320
341out: 321out:
342 return rc; 322 return rc;
343} 323}
344 324
345static void perf_record__init_features(struct perf_record *rec) 325static void record__init_features(struct record *rec)
346{ 326{
347 struct perf_evlist *evsel_list = rec->evlist;
348 struct perf_session *session = rec->session; 327 struct perf_session *session = rec->session;
349 int feat; 328 int feat;
350 329
@@ -354,32 +333,46 @@ static void perf_record__init_features(struct perf_record *rec)
354 if (rec->no_buildid) 333 if (rec->no_buildid)
355 perf_header__clear_feat(&session->header, HEADER_BUILD_ID); 334 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
356 335
357 if (!have_tracepoints(&evsel_list->entries)) 336 if (!have_tracepoints(&rec->evlist->entries))
358 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); 337 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
359 338
360 if (!rec->opts.branch_stack) 339 if (!rec->opts.branch_stack)
361 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); 340 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
362} 341}
363 342
364static int __cmd_record(struct perf_record *rec, int argc, const char **argv) 343static volatile int workload_exec_errno;
344
345/*
346 * perf_evlist__prepare_workload will send a SIGUSR1
347 * if the fork fails, since we asked by setting its
348 * want_signal to true.
349 */
350static void workload_exec_failed_signal(int signo, siginfo_t *info,
351 void *ucontext __maybe_unused)
352{
353 workload_exec_errno = info->si_value.sival_int;
354 done = 1;
355 signr = signo;
356 child_finished = 1;
357}
358
359static int __cmd_record(struct record *rec, int argc, const char **argv)
365{ 360{
366 int err; 361 int err;
367 unsigned long waking = 0; 362 unsigned long waking = 0;
368 const bool forks = argc > 0; 363 const bool forks = argc > 0;
369 struct machine *machine; 364 struct machine *machine;
370 struct perf_tool *tool = &rec->tool; 365 struct perf_tool *tool = &rec->tool;
371 struct perf_record_opts *opts = &rec->opts; 366 struct record_opts *opts = &rec->opts;
372 struct perf_evlist *evsel_list = rec->evlist;
373 struct perf_data_file *file = &rec->file; 367 struct perf_data_file *file = &rec->file;
374 struct perf_session *session; 368 struct perf_session *session;
375 bool disabled = false; 369 bool disabled = false;
376 370
377 rec->progname = argv[0]; 371 rec->progname = argv[0];
378 372
379 on_exit(perf_record__sig_exit, rec); 373 on_exit(record__sig_exit, rec);
380 signal(SIGCHLD, sig_handler); 374 signal(SIGCHLD, sig_handler);
381 signal(SIGINT, sig_handler); 375 signal(SIGINT, sig_handler);
382 signal(SIGUSR1, sig_handler);
383 signal(SIGTERM, sig_handler); 376 signal(SIGTERM, sig_handler);
384 377
385 session = perf_session__new(file, false, NULL); 378 session = perf_session__new(file, false, NULL);
@@ -390,37 +383,37 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
390 383
391 rec->session = session; 384 rec->session = session;
392 385
393 perf_record__init_features(rec); 386 record__init_features(rec);
394 387
395 if (forks) { 388 if (forks) {
396 err = perf_evlist__prepare_workload(evsel_list, &opts->target, 389 err = perf_evlist__prepare_workload(rec->evlist, &opts->target,
397 argv, file->is_pipe, 390 argv, file->is_pipe,
398 true); 391 workload_exec_failed_signal);
399 if (err < 0) { 392 if (err < 0) {
400 pr_err("Couldn't run the workload!\n"); 393 pr_err("Couldn't run the workload!\n");
401 goto out_delete_session; 394 goto out_delete_session;
402 } 395 }
403 } 396 }
404 397
405 if (perf_record__open(rec) != 0) { 398 if (record__open(rec) != 0) {
406 err = -1; 399 err = -1;
407 goto out_delete_session; 400 goto out_delete_session;
408 } 401 }
409 402
410 if (!evsel_list->nr_groups) 403 if (!rec->evlist->nr_groups)
411 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); 404 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
412 405
413 /* 406 /*
414 * perf_session__delete(session) will be called at perf_record__exit() 407 * perf_session__delete(session) will be called at record__exit()
415 */ 408 */
416 on_exit(perf_record__exit, rec); 409 on_exit(record__exit, rec);
417 410
418 if (file->is_pipe) { 411 if (file->is_pipe) {
419 err = perf_header__write_pipe(file->fd); 412 err = perf_header__write_pipe(file->fd);
420 if (err < 0) 413 if (err < 0)
421 goto out_delete_session; 414 goto out_delete_session;
422 } else { 415 } else {
423 err = perf_session__write_header(session, evsel_list, 416 err = perf_session__write_header(session, rec->evlist,
424 file->fd, false); 417 file->fd, false);
425 if (err < 0) 418 if (err < 0)
426 goto out_delete_session; 419 goto out_delete_session;
@@ -444,7 +437,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
444 goto out_delete_session; 437 goto out_delete_session;
445 } 438 }
446 439
447 if (have_tracepoints(&evsel_list->entries)) { 440 if (have_tracepoints(&rec->evlist->entries)) {
448 /* 441 /*
449 * FIXME err <= 0 here actually means that 442 * FIXME err <= 0 here actually means that
450 * there were no tracepoints so its not really 443 * there were no tracepoints so its not really
@@ -453,7 +446,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
453 * return this more properly and also 446 * return this more properly and also
454 * propagate errors that now are calling die() 447 * propagate errors that now are calling die()
455 */ 448 */
456 err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list, 449 err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist,
457 process_synthesized_event); 450 process_synthesized_event);
458 if (err <= 0) { 451 if (err <= 0) {
459 pr_err("Couldn't record tracing data.\n"); 452 pr_err("Couldn't record tracing data.\n");
@@ -485,7 +478,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
485 perf_event__synthesize_guest_os, tool); 478 perf_event__synthesize_guest_os, tool);
486 } 479 }
487 480
488 err = __machine__synthesize_threads(machine, tool, &opts->target, evsel_list->threads, 481 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
489 process_synthesized_event, opts->sample_address); 482 process_synthesized_event, opts->sample_address);
490 if (err != 0) 483 if (err != 0)
491 goto out_delete_session; 484 goto out_delete_session;
@@ -506,19 +499,24 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
506 * (apart from group members) have enable_on_exec=1 set, 499 * (apart from group members) have enable_on_exec=1 set,
507 * so don't spoil it by prematurely enabling them. 500 * so don't spoil it by prematurely enabling them.
508 */ 501 */
509 if (!target__none(&opts->target)) 502 if (!target__none(&opts->target) && !opts->initial_delay)
510 perf_evlist__enable(evsel_list); 503 perf_evlist__enable(rec->evlist);
511 504
512 /* 505 /*
513 * Let the child rip 506 * Let the child rip
514 */ 507 */
515 if (forks) 508 if (forks)
516 perf_evlist__start_workload(evsel_list); 509 perf_evlist__start_workload(rec->evlist);
510
511 if (opts->initial_delay) {
512 usleep(opts->initial_delay * 1000);
513 perf_evlist__enable(rec->evlist);
514 }
517 515
518 for (;;) { 516 for (;;) {
519 int hits = rec->samples; 517 int hits = rec->samples;
520 518
521 if (perf_record__mmap_read_all(rec) < 0) { 519 if (record__mmap_read_all(rec) < 0) {
522 err = -1; 520 err = -1;
523 goto out_delete_session; 521 goto out_delete_session;
524 } 522 }
@@ -526,7 +524,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
526 if (hits == rec->samples) { 524 if (hits == rec->samples) {
527 if (done) 525 if (done)
528 break; 526 break;
529 err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); 527 err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1);
530 waking++; 528 waking++;
531 } 529 }
532 530
@@ -536,11 +534,19 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
536 * disable events in this case. 534 * disable events in this case.
537 */ 535 */
538 if (done && !disabled && !target__none(&opts->target)) { 536 if (done && !disabled && !target__none(&opts->target)) {
539 perf_evlist__disable(evsel_list); 537 perf_evlist__disable(rec->evlist);
540 disabled = true; 538 disabled = true;
541 } 539 }
542 } 540 }
543 541
542 if (forks && workload_exec_errno) {
543 char msg[512];
544 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
545 pr_err("Workload failed: %s\n", emsg);
546 err = -1;
547 goto out_delete_session;
548 }
549
544 if (quiet || signr == SIGUSR1) 550 if (quiet || signr == SIGUSR1)
545 return 0; 551 return 0;
546 552
@@ -677,7 +683,7 @@ static int get_stack_size(char *str, unsigned long *_size)
677} 683}
678#endif /* HAVE_LIBUNWIND_SUPPORT */ 684#endif /* HAVE_LIBUNWIND_SUPPORT */
679 685
680int record_parse_callchain(const char *arg, struct perf_record_opts *opts) 686int record_parse_callchain(const char *arg, struct record_opts *opts)
681{ 687{
682 char *tok, *name, *saveptr = NULL; 688 char *tok, *name, *saveptr = NULL;
683 char *buf; 689 char *buf;
@@ -733,7 +739,7 @@ int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
733 return ret; 739 return ret;
734} 740}
735 741
736static void callchain_debug(struct perf_record_opts *opts) 742static void callchain_debug(struct record_opts *opts)
737{ 743{
738 pr_debug("callchain: type %d\n", opts->call_graph); 744 pr_debug("callchain: type %d\n", opts->call_graph);
739 745
@@ -746,7 +752,7 @@ int record_parse_callchain_opt(const struct option *opt,
746 const char *arg, 752 const char *arg,
747 int unset) 753 int unset)
748{ 754{
749 struct perf_record_opts *opts = opt->value; 755 struct record_opts *opts = opt->value;
750 int ret; 756 int ret;
751 757
752 /* --no-call-graph */ 758 /* --no-call-graph */
@@ -767,7 +773,7 @@ int record_callchain_opt(const struct option *opt,
767 const char *arg __maybe_unused, 773 const char *arg __maybe_unused,
768 int unset __maybe_unused) 774 int unset __maybe_unused)
769{ 775{
770 struct perf_record_opts *opts = opt->value; 776 struct record_opts *opts = opt->value;
771 777
772 if (opts->call_graph == CALLCHAIN_NONE) 778 if (opts->call_graph == CALLCHAIN_NONE)
773 opts->call_graph = CALLCHAIN_FP; 779 opts->call_graph = CALLCHAIN_FP;
@@ -783,8 +789,8 @@ static const char * const record_usage[] = {
783}; 789};
784 790
785/* 791/*
786 * XXX Ideally would be local to cmd_record() and passed to a perf_record__new 792 * XXX Ideally would be local to cmd_record() and passed to a record__new
787 * because we need to have access to it in perf_record__exit, that is called 793 * because we need to have access to it in record__exit, that is called
788 * after cmd_record() exits, but since record_options need to be accessible to 794 * after cmd_record() exits, but since record_options need to be accessible to
789 * builtin-script, leave it here. 795 * builtin-script, leave it here.
790 * 796 *
@@ -792,7 +798,7 @@ static const char * const record_usage[] = {
792 * 798 *
793 * Just say no to tons of global variables, sigh. 799 * Just say no to tons of global variables, sigh.
794 */ 800 */
795static struct perf_record record = { 801static struct record record = {
796 .opts = { 802 .opts = {
797 .mmap_pages = UINT_MAX, 803 .mmap_pages = UINT_MAX,
798 .user_freq = UINT_MAX, 804 .user_freq = UINT_MAX,
@@ -800,6 +806,7 @@ static struct perf_record record = {
800 .freq = 4000, 806 .freq = 4000,
801 .target = { 807 .target = {
802 .uses_mmap = true, 808 .uses_mmap = true,
809 .default_per_cpu = true,
803 }, 810 },
804 }, 811 },
805}; 812};
@@ -815,7 +822,7 @@ const char record_callchain_help[] = CALLCHAIN_HELP "fp";
815/* 822/*
816 * XXX Will stay a global variable till we fix builtin-script.c to stop messing 823 * XXX Will stay a global variable till we fix builtin-script.c to stop messing
817 * with it and switch to use the library functions in perf_evlist that came 824 * with it and switch to use the library functions in perf_evlist that came
818 * from builtin-record.c, i.e. use perf_record_opts, 825 * from builtin-record.c, i.e. use record_opts,
819 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', 826 * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
820 * using pipes, etc. 827 * using pipes, etc.
821 */ 828 */
@@ -831,7 +838,7 @@ const struct option record_options[] = {
831 "record events on existing thread id"), 838 "record events on existing thread id"),
832 OPT_INTEGER('r', "realtime", &record.realtime_prio, 839 OPT_INTEGER('r', "realtime", &record.realtime_prio,
833 "collect data with this RT SCHED_FIFO priority"), 840 "collect data with this RT SCHED_FIFO priority"),
834 OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay, 841 OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering,
835 "collect data without buffering"), 842 "collect data without buffering"),
836 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, 843 OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
837 "collect raw sample records from all opened counters"), 844 "collect raw sample records from all opened counters"),
@@ -842,8 +849,9 @@ const struct option record_options[] = {
842 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), 849 OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"),
843 OPT_STRING('o', "output", &record.file.path, "file", 850 OPT_STRING('o', "output", &record.file.path, "file",
844 "output file name"), 851 "output file name"),
845 OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, 852 OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit,
846 "child tasks do not inherit counters"), 853 &record.opts.no_inherit_set,
854 "child tasks do not inherit counters"),
847 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), 855 OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
848 OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages", 856 OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
849 "number of mmap data pages", 857 "number of mmap data pages",
@@ -874,6 +882,8 @@ const struct option record_options[] = {
874 OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 882 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
875 "monitor event in cgroup name only", 883 "monitor event in cgroup name only",
876 parse_cgroups), 884 parse_cgroups),
885 OPT_UINTEGER('D', "delay", &record.opts.initial_delay,
886 "ms to wait before starting measurement after program start"),
877 OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", 887 OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
878 "user to profile"), 888 "user to profile"),
879 889
@@ -888,24 +898,21 @@ const struct option record_options[] = {
888 "sample by weight (on special events only)"), 898 "sample by weight (on special events only)"),
889 OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction, 899 OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction,
890 "sample transaction flags (special events only)"), 900 "sample transaction flags (special events only)"),
891 OPT_BOOLEAN(0, "force-per-cpu", &record.opts.target.force_per_cpu, 901 OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
892 "force the use of per-cpu mmaps"), 902 "use per-thread mmaps"),
893 OPT_END() 903 OPT_END()
894}; 904};
895 905
896int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 906int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
897{ 907{
898 int err = -ENOMEM; 908 int err = -ENOMEM;
899 struct perf_evlist *evsel_list; 909 struct record *rec = &record;
900 struct perf_record *rec = &record;
901 char errbuf[BUFSIZ]; 910 char errbuf[BUFSIZ];
902 911
903 evsel_list = perf_evlist__new(); 912 rec->evlist = perf_evlist__new();
904 if (evsel_list == NULL) 913 if (rec->evlist == NULL)
905 return -ENOMEM; 914 return -ENOMEM;
906 915
907 rec->evlist = evsel_list;
908
909 argc = parse_options(argc, argv, record_options, record_usage, 916 argc = parse_options(argc, argv, record_options, record_usage,
910 PARSE_OPT_STOP_AT_NON_OPTION); 917 PARSE_OPT_STOP_AT_NON_OPTION);
911 if (!argc && target__none(&rec->opts.target)) 918 if (!argc && target__none(&rec->opts.target))
@@ -932,12 +939,15 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
932 if (rec->no_buildid_cache || rec->no_buildid) 939 if (rec->no_buildid_cache || rec->no_buildid)
933 disable_buildid_cache(); 940 disable_buildid_cache();
934 941
935 if (evsel_list->nr_entries == 0 && 942 if (rec->evlist->nr_entries == 0 &&
936 perf_evlist__add_default(evsel_list) < 0) { 943 perf_evlist__add_default(rec->evlist) < 0) {
937 pr_err("Not enough memory for event selector list\n"); 944 pr_err("Not enough memory for event selector list\n");
938 goto out_symbol_exit; 945 goto out_symbol_exit;
939 } 946 }
940 947
948 if (rec->opts.target.tid && !rec->opts.no_inherit_set)
949 rec->opts.no_inherit = true;
950
941 err = target__validate(&rec->opts.target); 951 err = target__validate(&rec->opts.target);
942 if (err) { 952 if (err) {
943 target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); 953 target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
@@ -956,20 +966,15 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
956 } 966 }
957 967
958 err = -ENOMEM; 968 err = -ENOMEM;
959 if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) 969 if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
960 usage_with_options(record_usage, record_options); 970 usage_with_options(record_usage, record_options);
961 971
962 if (perf_record_opts__config(&rec->opts)) { 972 if (record_opts__config(&rec->opts)) {
963 err = -EINVAL; 973 err = -EINVAL;
964 goto out_free_fd; 974 goto out_symbol_exit;
965 } 975 }
966 976
967 err = __cmd_record(&record, argc, argv); 977 err = __cmd_record(&record, argc, argv);
968
969 perf_evlist__munmap(evsel_list);
970 perf_evlist__close(evsel_list);
971out_free_fd:
972 perf_evlist__delete_maps(evsel_list);
973out_symbol_exit: 978out_symbol_exit:
974 symbol__exit(); 979 symbol__exit();
975 return err; 980 return err;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 8cf8e66ba594..3c53ec268fbc 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -39,7 +39,7 @@
39#include <dlfcn.h> 39#include <dlfcn.h>
40#include <linux/bitmap.h> 40#include <linux/bitmap.h>
41 41
42struct perf_report { 42struct report {
43 struct perf_tool tool; 43 struct perf_tool tool;
44 struct perf_session *session; 44 struct perf_session *session;
45 bool force, use_tui, use_gtk, use_stdio; 45 bool force, use_tui, use_gtk, use_stdio;
@@ -49,6 +49,8 @@ struct perf_report {
49 bool show_threads; 49 bool show_threads;
50 bool inverted_callchain; 50 bool inverted_callchain;
51 bool mem_mode; 51 bool mem_mode;
52 bool header;
53 bool header_only;
52 int max_stack; 54 int max_stack;
53 struct perf_read_values show_threads_values; 55 struct perf_read_values show_threads_values;
54 const char *pretty_printing_style; 56 const char *pretty_printing_style;
@@ -58,14 +60,14 @@ struct perf_report {
58 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 60 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
59}; 61};
60 62
61static int perf_report_config(const char *var, const char *value, void *cb) 63static int report__config(const char *var, const char *value, void *cb)
62{ 64{
63 if (!strcmp(var, "report.group")) { 65 if (!strcmp(var, "report.group")) {
64 symbol_conf.event_group = perf_config_bool(var, value); 66 symbol_conf.event_group = perf_config_bool(var, value);
65 return 0; 67 return 0;
66 } 68 }
67 if (!strcmp(var, "report.percent-limit")) { 69 if (!strcmp(var, "report.percent-limit")) {
68 struct perf_report *rep = cb; 70 struct report *rep = cb;
69 rep->min_percent = strtof(value, NULL); 71 rep->min_percent = strtof(value, NULL);
70 return 0; 72 return 0;
71 } 73 }
@@ -73,31 +75,22 @@ static int perf_report_config(const char *var, const char *value, void *cb)
73 return perf_default_config(var, value, cb); 75 return perf_default_config(var, value, cb);
74} 76}
75 77
76static int perf_report__add_mem_hist_entry(struct perf_tool *tool, 78static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al,
77 struct addr_location *al, 79 struct perf_sample *sample, struct perf_evsel *evsel,
78 struct perf_sample *sample, 80 union perf_event *event)
79 struct perf_evsel *evsel,
80 struct machine *machine,
81 union perf_event *event)
82{ 81{
83 struct perf_report *rep = container_of(tool, struct perf_report, tool); 82 struct report *rep = container_of(tool, struct report, tool);
84 struct symbol *parent = NULL; 83 struct symbol *parent = NULL;
85 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 84 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
86 int err = 0;
87 struct hist_entry *he; 85 struct hist_entry *he;
88 struct mem_info *mi, *mx; 86 struct mem_info *mi, *mx;
89 uint64_t cost; 87 uint64_t cost;
88 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
90 89
91 if ((sort__has_parent || symbol_conf.use_callchain) && 90 if (err)
92 sample->callchain) { 91 return err;
93 err = machine__resolve_callchain(machine, evsel, al->thread,
94 sample, &parent, al,
95 rep->max_stack);
96 if (err)
97 return err;
98 }
99 92
100 mi = machine__resolve_mem(machine, al->thread, sample, cpumode); 93 mi = machine__resolve_mem(al->machine, al->thread, sample, cpumode);
101 if (!mi) 94 if (!mi)
102 return -ENOMEM; 95 return -ENOMEM;
103 96
@@ -120,77 +113,36 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
120 if (!he) 113 if (!he)
121 return -ENOMEM; 114 return -ENOMEM;
122 115
123 /* 116 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
124 * In the TUI browser, we are doing integrated annotation, 117 if (err)
125 * so we don't allocate the extra space needed because the stdio 118 goto out;
126 * code will not use it.
127 */
128 if (sort__has_sym && he->ms.sym && use_browser > 0) {
129 struct annotation *notes = symbol__annotation(he->ms.sym);
130
131 assert(evsel != NULL);
132
133 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
134 goto out;
135
136 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
137 if (err)
138 goto out;
139 }
140 119
141 if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) { 120 mx = he->mem_info;
142 struct annotation *notes; 121 err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
143 122 if (err)
144 mx = he->mem_info; 123 goto out;
145
146 notes = symbol__annotation(mx->daddr.sym);
147 if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0)
148 goto out;
149
150 err = symbol__inc_addr_samples(mx->daddr.sym,
151 mx->daddr.map,
152 evsel->idx,
153 mx->daddr.al_addr);
154 if (err)
155 goto out;
156 }
157 124
158 evsel->hists.stats.total_period += cost; 125 evsel->hists.stats.total_period += cost;
159 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 126 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
160 err = 0; 127 err = hist_entry__append_callchain(he, sample);
161
162 if (symbol_conf.use_callchain) {
163 err = callchain_append(he->callchain,
164 &callchain_cursor,
165 sample->period);
166 }
167out: 128out:
168 return err; 129 return err;
169} 130}
170 131
171static int perf_report__add_branch_hist_entry(struct perf_tool *tool, 132static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_location *al,
172 struct addr_location *al, 133 struct perf_sample *sample, struct perf_evsel *evsel)
173 struct perf_sample *sample,
174 struct perf_evsel *evsel,
175 struct machine *machine)
176{ 134{
177 struct perf_report *rep = container_of(tool, struct perf_report, tool); 135 struct report *rep = container_of(tool, struct report, tool);
178 struct symbol *parent = NULL; 136 struct symbol *parent = NULL;
179 int err = 0;
180 unsigned i; 137 unsigned i;
181 struct hist_entry *he; 138 struct hist_entry *he;
182 struct branch_info *bi, *bx; 139 struct branch_info *bi, *bx;
140 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
183 141
184 if ((sort__has_parent || symbol_conf.use_callchain) 142 if (err)
185 && sample->callchain) { 143 return err;
186 err = machine__resolve_callchain(machine, evsel, al->thread,
187 sample, &parent, al,
188 rep->max_stack);
189 if (err)
190 return err;
191 }
192 144
193 bi = machine__resolve_bstack(machine, al->thread, 145 bi = machine__resolve_bstack(al->machine, al->thread,
194 sample->branch_stack); 146 sample->branch_stack);
195 if (!bi) 147 if (!bi)
196 return -ENOMEM; 148 return -ENOMEM;
@@ -212,35 +164,15 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
212 he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL, 164 he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
213 1, 1, 0); 165 1, 1, 0);
214 if (he) { 166 if (he) {
215 struct annotation *notes;
216 bx = he->branch_info; 167 bx = he->branch_info;
217 if (bx->from.sym && use_browser == 1 && sort__has_sym) { 168 err = addr_map_symbol__inc_samples(&bx->from, evsel->idx);
218 notes = symbol__annotation(bx->from.sym); 169 if (err)
219 if (!notes->src 170 goto out;
220 && symbol__alloc_hist(bx->from.sym) < 0) 171
221 goto out; 172 err = addr_map_symbol__inc_samples(&bx->to, evsel->idx);
222 173 if (err)
223 err = symbol__inc_addr_samples(bx->from.sym, 174 goto out;
224 bx->from.map,
225 evsel->idx,
226 bx->from.al_addr);
227 if (err)
228 goto out;
229 }
230 175
231 if (bx->to.sym && use_browser == 1 && sort__has_sym) {
232 notes = symbol__annotation(bx->to.sym);
233 if (!notes->src
234 && symbol__alloc_hist(bx->to.sym) < 0)
235 goto out;
236
237 err = symbol__inc_addr_samples(bx->to.sym,
238 bx->to.map,
239 evsel->idx,
240 bx->to.al_addr);
241 if (err)
242 goto out;
243 }
244 evsel->hists.stats.total_period += 1; 176 evsel->hists.stats.total_period += 1;
245 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 177 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
246 } else 178 } else
@@ -252,24 +184,16 @@ out:
252 return err; 184 return err;
253} 185}
254 186
255static int perf_evsel__add_hist_entry(struct perf_tool *tool, 187static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evsel,
256 struct perf_evsel *evsel, 188 struct addr_location *al, struct perf_sample *sample)
257 struct addr_location *al,
258 struct perf_sample *sample,
259 struct machine *machine)
260{ 189{
261 struct perf_report *rep = container_of(tool, struct perf_report, tool); 190 struct report *rep = container_of(tool, struct report, tool);
262 struct symbol *parent = NULL; 191 struct symbol *parent = NULL;
263 int err = 0;
264 struct hist_entry *he; 192 struct hist_entry *he;
193 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
265 194
266 if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { 195 if (err)
267 err = machine__resolve_callchain(machine, evsel, al->thread, 196 return err;
268 sample, &parent, al,
269 rep->max_stack);
270 if (err)
271 return err;
272 }
273 197
274 he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL, 198 he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL,
275 sample->period, sample->weight, 199 sample->period, sample->weight,
@@ -277,30 +201,11 @@ static int perf_evsel__add_hist_entry(struct perf_tool *tool,
277 if (he == NULL) 201 if (he == NULL)
278 return -ENOMEM; 202 return -ENOMEM;
279 203
280 if (symbol_conf.use_callchain) { 204 err = hist_entry__append_callchain(he, sample);
281 err = callchain_append(he->callchain, 205 if (err)
282 &callchain_cursor, 206 goto out;
283 sample->period);
284 if (err)
285 return err;
286 }
287 /*
288 * Only in the TUI browser we are doing integrated annotation,
289 * so we don't allocated the extra space needed because the stdio
290 * code will not use it.
291 */
292 if (he->ms.sym != NULL && use_browser == 1 && sort__has_sym) {
293 struct annotation *notes = symbol__annotation(he->ms.sym);
294
295 assert(evsel != NULL);
296
297 err = -ENOMEM;
298 if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
299 goto out;
300
301 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
302 }
303 207
208 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
304 evsel->hists.stats.total_period += sample->period; 209 evsel->hists.stats.total_period += sample->period;
305 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 210 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
306out: 211out:
@@ -314,13 +219,13 @@ static int process_sample_event(struct perf_tool *tool,
314 struct perf_evsel *evsel, 219 struct perf_evsel *evsel,
315 struct machine *machine) 220 struct machine *machine)
316{ 221{
317 struct perf_report *rep = container_of(tool, struct perf_report, tool); 222 struct report *rep = container_of(tool, struct report, tool);
318 struct addr_location al; 223 struct addr_location al;
319 int ret; 224 int ret;
320 225
321 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 226 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
322 fprintf(stderr, "problem processing %d event, skipping it.\n", 227 pr_debug("problem processing %d event, skipping it.\n",
323 event->header.type); 228 event->header.type);
324 return -1; 229 return -1;
325 } 230 }
326 231
@@ -331,21 +236,18 @@ static int process_sample_event(struct perf_tool *tool,
331 return 0; 236 return 0;
332 237
333 if (sort__mode == SORT_MODE__BRANCH) { 238 if (sort__mode == SORT_MODE__BRANCH) {
334 ret = perf_report__add_branch_hist_entry(tool, &al, sample, 239 ret = report__add_branch_hist_entry(tool, &al, sample, evsel);
335 evsel, machine);
336 if (ret < 0) 240 if (ret < 0)
337 pr_debug("problem adding lbr entry, skipping event\n"); 241 pr_debug("problem adding lbr entry, skipping event\n");
338 } else if (rep->mem_mode == 1) { 242 } else if (rep->mem_mode == 1) {
339 ret = perf_report__add_mem_hist_entry(tool, &al, sample, 243 ret = report__add_mem_hist_entry(tool, &al, sample, evsel, event);
340 evsel, machine, event);
341 if (ret < 0) 244 if (ret < 0)
342 pr_debug("problem adding mem entry, skipping event\n"); 245 pr_debug("problem adding mem entry, skipping event\n");
343 } else { 246 } else {
344 if (al.map != NULL) 247 if (al.map != NULL)
345 al.map->dso->hit = 1; 248 al.map->dso->hit = 1;
346 249
347 ret = perf_evsel__add_hist_entry(tool, evsel, &al, sample, 250 ret = report__add_hist_entry(tool, evsel, &al, sample);
348 machine);
349 if (ret < 0) 251 if (ret < 0)
350 pr_debug("problem incrementing symbol period, skipping event\n"); 252 pr_debug("problem incrementing symbol period, skipping event\n");
351 } 253 }
@@ -358,7 +260,7 @@ static int process_read_event(struct perf_tool *tool,
358 struct perf_evsel *evsel, 260 struct perf_evsel *evsel,
359 struct machine *machine __maybe_unused) 261 struct machine *machine __maybe_unused)
360{ 262{
361 struct perf_report *rep = container_of(tool, struct perf_report, tool); 263 struct report *rep = container_of(tool, struct report, tool);
362 264
363 if (rep->show_threads) { 265 if (rep->show_threads) {
364 const char *name = evsel ? perf_evsel__name(evsel) : "unknown"; 266 const char *name = evsel ? perf_evsel__name(evsel) : "unknown";
@@ -377,7 +279,7 @@ static int process_read_event(struct perf_tool *tool,
377} 279}
378 280
379/* For pipe mode, sample_type is not currently set */ 281/* For pipe mode, sample_type is not currently set */
380static int perf_report__setup_sample_type(struct perf_report *rep) 282static int report__setup_sample_type(struct report *rep)
381{ 283{
382 struct perf_session *session = rep->session; 284 struct perf_session *session = rep->session;
383 u64 sample_type = perf_evlist__combined_sample_type(session->evlist); 285 u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
@@ -422,8 +324,7 @@ static void sig_handler(int sig __maybe_unused)
422 session_done = 1; 324 session_done = 1;
423} 325}
424 326
425static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, 327static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep,
426 struct hists *hists,
427 const char *evname, FILE *fp) 328 const char *evname, FILE *fp)
428{ 329{
429 size_t ret; 330 size_t ret;
@@ -460,12 +361,12 @@ static size_t hists__fprintf_nr_sample_events(struct perf_report *rep,
460} 361}
461 362
462static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, 363static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
463 struct perf_report *rep, 364 struct report *rep,
464 const char *help) 365 const char *help)
465{ 366{
466 struct perf_evsel *pos; 367 struct perf_evsel *pos;
467 368
468 list_for_each_entry(pos, &evlist->entries, node) { 369 evlist__for_each(evlist, pos) {
469 struct hists *hists = &pos->hists; 370 struct hists *hists = &pos->hists;
470 const char *evname = perf_evsel__name(pos); 371 const char *evname = perf_evsel__name(pos);
471 372
@@ -473,7 +374,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
473 !perf_evsel__is_group_leader(pos)) 374 !perf_evsel__is_group_leader(pos))
474 continue; 375 continue;
475 376
476 hists__fprintf_nr_sample_events(rep, hists, evname, stdout); 377 hists__fprintf_nr_sample_events(hists, rep, evname, stdout);
477 hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout); 378 hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
478 fprintf(stdout, "\n\n"); 379 fprintf(stdout, "\n\n");
479 } 380 }
@@ -493,43 +394,11 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
493 return 0; 394 return 0;
494} 395}
495 396
496static int __cmd_report(struct perf_report *rep) 397static void report__warn_kptr_restrict(const struct report *rep)
497{ 398{
498 int ret = -EINVAL; 399 struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION];
499 u64 nr_samples; 400 struct kmap *kernel_kmap = map__kmap(kernel_map);
500 struct perf_session *session = rep->session;
501 struct perf_evsel *pos;
502 struct map *kernel_map;
503 struct kmap *kernel_kmap;
504 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
505 struct ui_progress prog;
506 struct perf_data_file *file = session->file;
507
508 signal(SIGINT, sig_handler);
509 401
510 if (rep->cpu_list) {
511 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
512 rep->cpu_bitmap);
513 if (ret)
514 return ret;
515 }
516
517 if (use_browser <= 0)
518 perf_session__fprintf_info(session, stdout, rep->show_full_info);
519
520 if (rep->show_threads)
521 perf_read_values_init(&rep->show_threads_values);
522
523 ret = perf_report__setup_sample_type(rep);
524 if (ret)
525 return ret;
526
527 ret = perf_session__process_events(session, &rep->tool);
528 if (ret)
529 return ret;
530
531 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
532 kernel_kmap = map__kmap(kernel_map);
533 if (kernel_map == NULL || 402 if (kernel_map == NULL ||
534 (kernel_map->dso->hit && 403 (kernel_map->dso->hit &&
535 (kernel_kmap->ref_reloc_sym == NULL || 404 (kernel_kmap->ref_reloc_sym == NULL ||
@@ -552,26 +421,73 @@ static int __cmd_report(struct perf_report *rep)
552"Samples in kernel modules can't be resolved as well.\n\n", 421"Samples in kernel modules can't be resolved as well.\n\n",
553 desc); 422 desc);
554 } 423 }
424}
555 425
556 if (verbose > 3) 426static int report__gtk_browse_hists(struct report *rep, const char *help)
557 perf_session__fprintf(session, stdout); 427{
428 int (*hist_browser)(struct perf_evlist *evlist, const char *help,
429 struct hist_browser_timer *timer, float min_pcnt);
558 430
559 if (verbose > 2) 431 hist_browser = dlsym(perf_gtk_handle, "perf_evlist__gtk_browse_hists");
560 perf_session__fprintf_dsos(session, stdout);
561 432
562 if (dump_trace) { 433 if (hist_browser == NULL) {
563 perf_session__fprintf_nr_events(session, stdout); 434 ui__error("GTK browser not found!\n");
564 return 0; 435 return -1;
565 } 436 }
566 437
567 nr_samples = 0; 438 return hist_browser(rep->session->evlist, help, NULL, rep->min_percent);
568 list_for_each_entry(pos, &session->evlist->entries, node) 439}
440
441static int report__browse_hists(struct report *rep)
442{
443 int ret;
444 struct perf_session *session = rep->session;
445 struct perf_evlist *evlist = session->evlist;
446 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
447
448 switch (use_browser) {
449 case 1:
450 ret = perf_evlist__tui_browse_hists(evlist, help, NULL,
451 rep->min_percent,
452 &session->header.env);
453 /*
454 * Usually "ret" is the last pressed key, and we only
455 * care if the key notifies us to switch data file.
456 */
457 if (ret != K_SWITCH_INPUT_DATA)
458 ret = 0;
459 break;
460 case 2:
461 ret = report__gtk_browse_hists(rep, help);
462 break;
463 default:
464 ret = perf_evlist__tty_browse_hists(evlist, rep, help);
465 break;
466 }
467
468 return ret;
469}
470
471static u64 report__collapse_hists(struct report *rep)
472{
473 struct ui_progress prog;
474 struct perf_evsel *pos;
475 u64 nr_samples = 0;
476 /*
477 * Count number of histogram entries to use when showing progress,
478 * reusing nr_samples variable.
479 */
480 evlist__for_each(rep->session->evlist, pos)
569 nr_samples += pos->hists.nr_entries; 481 nr_samples += pos->hists.nr_entries;
570 482
571 ui_progress__init(&prog, nr_samples, "Merging related events..."); 483 ui_progress__init(&prog, nr_samples, "Merging related events...");
572 484 /*
485 * Count total number of samples, will be used to check if this
486 * session had any.
487 */
573 nr_samples = 0; 488 nr_samples = 0;
574 list_for_each_entry(pos, &session->evlist->entries, node) { 489
490 evlist__for_each(rep->session->evlist, pos) {
575 struct hists *hists = &pos->hists; 491 struct hists *hists = &pos->hists;
576 492
577 if (pos->idx == 0) 493 if (pos->idx == 0)
@@ -589,8 +505,57 @@ static int __cmd_report(struct perf_report *rep)
589 hists__link(leader_hists, hists); 505 hists__link(leader_hists, hists);
590 } 506 }
591 } 507 }
508
592 ui_progress__finish(); 509 ui_progress__finish();
593 510
511 return nr_samples;
512}
513
514static int __cmd_report(struct report *rep)
515{
516 int ret;
517 u64 nr_samples;
518 struct perf_session *session = rep->session;
519 struct perf_evsel *pos;
520 struct perf_data_file *file = session->file;
521
522 signal(SIGINT, sig_handler);
523
524 if (rep->cpu_list) {
525 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
526 rep->cpu_bitmap);
527 if (ret)
528 return ret;
529 }
530
531 if (rep->show_threads)
532 perf_read_values_init(&rep->show_threads_values);
533
534 ret = report__setup_sample_type(rep);
535 if (ret)
536 return ret;
537
538 ret = perf_session__process_events(session, &rep->tool);
539 if (ret)
540 return ret;
541
542 report__warn_kptr_restrict(rep);
543
544 if (use_browser == 0) {
545 if (verbose > 3)
546 perf_session__fprintf(session, stdout);
547
548 if (verbose > 2)
549 perf_session__fprintf_dsos(session, stdout);
550
551 if (dump_trace) {
552 perf_session__fprintf_nr_events(session, stdout);
553 return 0;
554 }
555 }
556
557 nr_samples = report__collapse_hists(rep);
558
594 if (session_done()) 559 if (session_done())
595 return 0; 560 return 0;
596 561
@@ -599,47 +564,16 @@ static int __cmd_report(struct perf_report *rep)
599 return 0; 564 return 0;
600 } 565 }
601 566
602 list_for_each_entry(pos, &session->evlist->entries, node) 567 evlist__for_each(session->evlist, pos)
603 hists__output_resort(&pos->hists); 568 hists__output_resort(&pos->hists);
604 569
605 if (use_browser > 0) { 570 return report__browse_hists(rep);
606 if (use_browser == 1) {
607 ret = perf_evlist__tui_browse_hists(session->evlist,
608 help, NULL,
609 rep->min_percent,
610 &session->header.env);
611 /*
612 * Usually "ret" is the last pressed key, and we only
613 * care if the key notifies us to switch data file.
614 */
615 if (ret != K_SWITCH_INPUT_DATA)
616 ret = 0;
617
618 } else if (use_browser == 2) {
619 int (*hist_browser)(struct perf_evlist *,
620 const char *,
621 struct hist_browser_timer *,
622 float min_pcnt);
623
624 hist_browser = dlsym(perf_gtk_handle,
625 "perf_evlist__gtk_browse_hists");
626 if (hist_browser == NULL) {
627 ui__error("GTK browser not found!\n");
628 return ret;
629 }
630 hist_browser(session->evlist, help, NULL,
631 rep->min_percent);
632 }
633 } else
634 perf_evlist__tty_browse_hists(session->evlist, rep, help);
635
636 return ret;
637} 571}
638 572
639static int 573static int
640parse_callchain_opt(const struct option *opt, const char *arg, int unset) 574parse_callchain_opt(const struct option *opt, const char *arg, int unset)
641{ 575{
642 struct perf_report *rep = (struct perf_report *)opt->value; 576 struct report *rep = (struct report *)opt->value;
643 char *tok, *tok2; 577 char *tok, *tok2;
644 char *endptr; 578 char *endptr;
645 579
@@ -721,7 +655,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
721 return -1; 655 return -1;
722setup: 656setup:
723 if (callchain_register_param(&callchain_param) < 0) { 657 if (callchain_register_param(&callchain_param) < 0) {
724 fprintf(stderr, "Can't register callchain params\n"); 658 pr_err("Can't register callchain params\n");
725 return -1; 659 return -1;
726 } 660 }
727 return 0; 661 return 0;
@@ -759,7 +693,7 @@ static int
759parse_percent_limit(const struct option *opt, const char *str, 693parse_percent_limit(const struct option *opt, const char *str,
760 int unset __maybe_unused) 694 int unset __maybe_unused)
761{ 695{
762 struct perf_report *rep = opt->value; 696 struct report *rep = opt->value;
763 697
764 rep->min_percent = strtof(str, NULL); 698 rep->min_percent = strtof(str, NULL);
765 return 0; 699 return 0;
@@ -777,7 +711,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
777 "perf report [<options>]", 711 "perf report [<options>]",
778 NULL 712 NULL
779 }; 713 };
780 struct perf_report report = { 714 struct report report = {
781 .tool = { 715 .tool = {
782 .sample = process_sample_event, 716 .sample = process_sample_event,
783 .mmap = perf_event__process_mmap, 717 .mmap = perf_event__process_mmap,
@@ -820,6 +754,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
820 OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"), 754 OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"),
821 OPT_BOOLEAN(0, "stdio", &report.use_stdio, 755 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
822 "Use the stdio interface"), 756 "Use the stdio interface"),
757 OPT_BOOLEAN(0, "header", &report.header, "Show data header."),
758 OPT_BOOLEAN(0, "header-only", &report.header_only,
759 "Show only data header."),
823 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 760 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
824 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," 761 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
825 " dso_to, dso_from, symbol_to, symbol_from, mispredict," 762 " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
@@ -890,7 +827,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
890 .mode = PERF_DATA_MODE_READ, 827 .mode = PERF_DATA_MODE_READ,
891 }; 828 };
892 829
893 perf_config(perf_report_config, &report); 830 perf_config(report__config, &report);
894 831
895 argc = parse_options(argc, argv, options, report_usage, 0); 832 argc = parse_options(argc, argv, options, report_usage, 0);
896 833
@@ -940,7 +877,7 @@ repeat:
940 } 877 }
941 if (report.mem_mode) { 878 if (report.mem_mode) {
942 if (sort__mode == SORT_MODE__BRANCH) { 879 if (sort__mode == SORT_MODE__BRANCH) {
943 fprintf(stderr, "branch and mem mode incompatible\n"); 880 pr_err("branch and mem mode incompatible\n");
944 goto error; 881 goto error;
945 } 882 }
946 sort__mode = SORT_MODE__MEMORY; 883 sort__mode = SORT_MODE__MEMORY;
@@ -963,6 +900,10 @@ repeat:
963 goto error; 900 goto error;
964 } 901 }
965 902
903 /* Force tty output for header output. */
904 if (report.header || report.header_only)
905 use_browser = 0;
906
966 if (strcmp(input_name, "-") != 0) 907 if (strcmp(input_name, "-") != 0)
967 setup_browser(true); 908 setup_browser(true);
968 else { 909 else {
@@ -970,6 +911,16 @@ repeat:
970 perf_hpp__init(); 911 perf_hpp__init();
971 } 912 }
972 913
914 if (report.header || report.header_only) {
915 perf_session__fprintf_info(session, stdout,
916 report.show_full_info);
917 if (report.header_only)
918 return 0;
919 } else if (use_browser == 0) {
920 fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
921 stdout);
922 }
923
973 /* 924 /*
974 * Only in the TUI browser we are doing integrated annotation, 925 * Only in the TUI browser we are doing integrated annotation,
975 * so don't allocate extra space that won't be used in the stdio 926 * so don't allocate extra space that won't be used in the stdio
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 0f3c65518a2c..6a76a07b6789 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -469,7 +469,7 @@ static void *thread_func(void *ctx)
469 char comm2[22]; 469 char comm2[22];
470 int fd; 470 int fd;
471 471
472 free(parms); 472 zfree(&parms);
473 473
474 sprintf(comm2, ":%s", this_task->comm); 474 sprintf(comm2, ":%s", this_task->comm);
475 prctl(PR_SET_NAME, comm2); 475 prctl(PR_SET_NAME, comm2);
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index baf17989a216..9e9c91f5b7fa 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -43,6 +43,7 @@ enum perf_output_field {
43 PERF_OUTPUT_DSO = 1U << 9, 43 PERF_OUTPUT_DSO = 1U << 9,
44 PERF_OUTPUT_ADDR = 1U << 10, 44 PERF_OUTPUT_ADDR = 1U << 10,
45 PERF_OUTPUT_SYMOFFSET = 1U << 11, 45 PERF_OUTPUT_SYMOFFSET = 1U << 11,
46 PERF_OUTPUT_SRCLINE = 1U << 12,
46}; 47};
47 48
48struct output_option { 49struct output_option {
@@ -61,6 +62,7 @@ struct output_option {
61 {.str = "dso", .field = PERF_OUTPUT_DSO}, 62 {.str = "dso", .field = PERF_OUTPUT_DSO},
62 {.str = "addr", .field = PERF_OUTPUT_ADDR}, 63 {.str = "addr", .field = PERF_OUTPUT_ADDR},
63 {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, 64 {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},
65 {.str = "srcline", .field = PERF_OUTPUT_SRCLINE},
64}; 66};
65 67
66/* default set to maintain compatibility with current format */ 68/* default set to maintain compatibility with current format */
@@ -210,6 +212,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
210 "to DSO.\n"); 212 "to DSO.\n");
211 return -EINVAL; 213 return -EINVAL;
212 } 214 }
215 if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) {
216 pr_err("Display of source line number requested but sample IP is not\n"
217 "selected. Hence, no address to lookup the source line number.\n");
218 return -EINVAL;
219 }
213 220
214 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && 221 if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
215 perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", 222 perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID",
@@ -245,6 +252,9 @@ static void set_print_ip_opts(struct perf_event_attr *attr)
245 252
246 if (PRINT_FIELD(SYMOFFSET)) 253 if (PRINT_FIELD(SYMOFFSET))
247 output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET; 254 output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
255
256 if (PRINT_FIELD(SRCLINE))
257 output[type].print_ip_opts |= PRINT_IP_OPT_SRCLINE;
248} 258}
249 259
250/* 260/*
@@ -280,6 +290,30 @@ static int perf_session__check_output_opt(struct perf_session *session)
280 set_print_ip_opts(&evsel->attr); 290 set_print_ip_opts(&evsel->attr);
281 } 291 }
282 292
293 /*
294 * set default for tracepoints to print symbols only
295 * if callchains are present
296 */
297 if (symbol_conf.use_callchain &&
298 !output[PERF_TYPE_TRACEPOINT].user_set) {
299 struct perf_event_attr *attr;
300
301 j = PERF_TYPE_TRACEPOINT;
302 evsel = perf_session__find_first_evtype(session, j);
303 if (evsel == NULL)
304 goto out;
305
306 attr = &evsel->attr;
307
308 if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) {
309 output[j].fields |= PERF_OUTPUT_IP;
310 output[j].fields |= PERF_OUTPUT_SYM;
311 output[j].fields |= PERF_OUTPUT_DSO;
312 set_print_ip_opts(attr);
313 }
314 }
315
316out:
283 return 0; 317 return 0;
284} 318}
285 319
@@ -288,7 +322,6 @@ static void print_sample_start(struct perf_sample *sample,
288 struct perf_evsel *evsel) 322 struct perf_evsel *evsel)
289{ 323{
290 struct perf_event_attr *attr = &evsel->attr; 324 struct perf_event_attr *attr = &evsel->attr;
291 const char *evname = NULL;
292 unsigned long secs; 325 unsigned long secs;
293 unsigned long usecs; 326 unsigned long usecs;
294 unsigned long long nsecs; 327 unsigned long long nsecs;
@@ -323,11 +356,6 @@ static void print_sample_start(struct perf_sample *sample,
323 usecs = nsecs / NSECS_PER_USEC; 356 usecs = nsecs / NSECS_PER_USEC;
324 printf("%5lu.%06lu: ", secs, usecs); 357 printf("%5lu.%06lu: ", secs, usecs);
325 } 358 }
326
327 if (PRINT_FIELD(EVNAME)) {
328 evname = perf_evsel__name(evsel);
329 printf("%s: ", evname ? evname : "[unknown]");
330 }
331} 359}
332 360
333static bool is_bts_event(struct perf_event_attr *attr) 361static bool is_bts_event(struct perf_event_attr *attr)
@@ -395,8 +423,8 @@ static void print_sample_addr(union perf_event *event,
395static void print_sample_bts(union perf_event *event, 423static void print_sample_bts(union perf_event *event,
396 struct perf_sample *sample, 424 struct perf_sample *sample,
397 struct perf_evsel *evsel, 425 struct perf_evsel *evsel,
398 struct machine *machine, 426 struct thread *thread,
399 struct thread *thread) 427 struct addr_location *al)
400{ 428{
401 struct perf_event_attr *attr = &evsel->attr; 429 struct perf_event_attr *attr = &evsel->attr;
402 430
@@ -406,7 +434,7 @@ static void print_sample_bts(union perf_event *event,
406 printf(" "); 434 printf(" ");
407 else 435 else
408 printf("\n"); 436 printf("\n");
409 perf_evsel__print_ip(evsel, event, sample, machine, 437 perf_evsel__print_ip(evsel, sample, al,
410 output[attr->type].print_ip_opts, 438 output[attr->type].print_ip_opts,
411 PERF_MAX_STACK_DEPTH); 439 PERF_MAX_STACK_DEPTH);
412 } 440 }
@@ -417,15 +445,14 @@ static void print_sample_bts(union perf_event *event,
417 if (PRINT_FIELD(ADDR) || 445 if (PRINT_FIELD(ADDR) ||
418 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 446 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
419 !output[attr->type].user_set)) 447 !output[attr->type].user_set))
420 print_sample_addr(event, sample, machine, thread, attr); 448 print_sample_addr(event, sample, al->machine, thread, attr);
421 449
422 printf("\n"); 450 printf("\n");
423} 451}
424 452
425static void process_event(union perf_event *event, struct perf_sample *sample, 453static void process_event(union perf_event *event, struct perf_sample *sample,
426 struct perf_evsel *evsel, struct machine *machine, 454 struct perf_evsel *evsel, struct thread *thread,
427 struct thread *thread, 455 struct addr_location *al)
428 struct addr_location *al __maybe_unused)
429{ 456{
430 struct perf_event_attr *attr = &evsel->attr; 457 struct perf_event_attr *attr = &evsel->attr;
431 458
@@ -434,8 +461,13 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
434 461
435 print_sample_start(sample, thread, evsel); 462 print_sample_start(sample, thread, evsel);
436 463
464 if (PRINT_FIELD(EVNAME)) {
465 const char *evname = perf_evsel__name(evsel);
466 printf("%s: ", evname ? evname : "[unknown]");
467 }
468
437 if (is_bts_event(attr)) { 469 if (is_bts_event(attr)) {
438 print_sample_bts(event, sample, evsel, machine, thread); 470 print_sample_bts(event, sample, evsel, thread, al);
439 return; 471 return;
440 } 472 }
441 473
@@ -443,7 +475,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
443 event_format__print(evsel->tp_format, sample->cpu, 475 event_format__print(evsel->tp_format, sample->cpu,
444 sample->raw_data, sample->raw_size); 476 sample->raw_data, sample->raw_size);
445 if (PRINT_FIELD(ADDR)) 477 if (PRINT_FIELD(ADDR))
446 print_sample_addr(event, sample, machine, thread, attr); 478 print_sample_addr(event, sample, al->machine, thread, attr);
447 479
448 if (PRINT_FIELD(IP)) { 480 if (PRINT_FIELD(IP)) {
449 if (!symbol_conf.use_callchain) 481 if (!symbol_conf.use_callchain)
@@ -451,7 +483,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
451 else 483 else
452 printf("\n"); 484 printf("\n");
453 485
454 perf_evsel__print_ip(evsel, event, sample, machine, 486 perf_evsel__print_ip(evsel, sample, al,
455 output[attr->type].print_ip_opts, 487 output[attr->type].print_ip_opts,
456 PERF_MAX_STACK_DEPTH); 488 PERF_MAX_STACK_DEPTH);
457 } 489 }
@@ -540,7 +572,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
540 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 572 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
541 return 0; 573 return 0;
542 574
543 scripting_ops->process_event(event, sample, evsel, machine, thread, &al); 575 scripting_ops->process_event(event, sample, evsel, thread, &al);
544 576
545 evsel->hists.stats.total_period += sample->period; 577 evsel->hists.stats.total_period += sample->period;
546 return 0; 578 return 0;
@@ -549,6 +581,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
549struct perf_script { 581struct perf_script {
550 struct perf_tool tool; 582 struct perf_tool tool;
551 struct perf_session *session; 583 struct perf_session *session;
584 bool show_task_events;
585 bool show_mmap_events;
552}; 586};
553 587
554static int process_attr(struct perf_tool *tool, union perf_event *event, 588static int process_attr(struct perf_tool *tool, union perf_event *event,
@@ -569,7 +603,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
569 if (evsel->attr.type >= PERF_TYPE_MAX) 603 if (evsel->attr.type >= PERF_TYPE_MAX)
570 return 0; 604 return 0;
571 605
572 list_for_each_entry(pos, &evlist->entries, node) { 606 evlist__for_each(evlist, pos) {
573 if (pos->attr.type == evsel->attr.type && pos != evsel) 607 if (pos->attr.type == evsel->attr.type && pos != evsel)
574 return 0; 608 return 0;
575 } 609 }
@@ -579,6 +613,163 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
579 return perf_evsel__check_attr(evsel, scr->session); 613 return perf_evsel__check_attr(evsel, scr->session);
580} 614}
581 615
616static int process_comm_event(struct perf_tool *tool,
617 union perf_event *event,
618 struct perf_sample *sample,
619 struct machine *machine)
620{
621 struct thread *thread;
622 struct perf_script *script = container_of(tool, struct perf_script, tool);
623 struct perf_session *session = script->session;
624 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
625 int ret = -1;
626
627 thread = machine__findnew_thread(machine, event->comm.pid, event->comm.tid);
628 if (thread == NULL) {
629 pr_debug("problem processing COMM event, skipping it.\n");
630 return -1;
631 }
632
633 if (perf_event__process_comm(tool, event, sample, machine) < 0)
634 goto out;
635
636 if (!evsel->attr.sample_id_all) {
637 sample->cpu = 0;
638 sample->time = 0;
639 sample->tid = event->comm.tid;
640 sample->pid = event->comm.pid;
641 }
642 print_sample_start(sample, thread, evsel);
643 perf_event__fprintf(event, stdout);
644 ret = 0;
645
646out:
647 return ret;
648}
649
650static int process_fork_event(struct perf_tool *tool,
651 union perf_event *event,
652 struct perf_sample *sample,
653 struct machine *machine)
654{
655 struct thread *thread;
656 struct perf_script *script = container_of(tool, struct perf_script, tool);
657 struct perf_session *session = script->session;
658 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
659
660 if (perf_event__process_fork(tool, event, sample, machine) < 0)
661 return -1;
662
663 thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid);
664 if (thread == NULL) {
665 pr_debug("problem processing FORK event, skipping it.\n");
666 return -1;
667 }
668
669 if (!evsel->attr.sample_id_all) {
670 sample->cpu = 0;
671 sample->time = event->fork.time;
672 sample->tid = event->fork.tid;
673 sample->pid = event->fork.pid;
674 }
675 print_sample_start(sample, thread, evsel);
676 perf_event__fprintf(event, stdout);
677
678 return 0;
679}
680static int process_exit_event(struct perf_tool *tool,
681 union perf_event *event,
682 struct perf_sample *sample,
683 struct machine *machine)
684{
685 struct thread *thread;
686 struct perf_script *script = container_of(tool, struct perf_script, tool);
687 struct perf_session *session = script->session;
688 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
689
690 thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid);
691 if (thread == NULL) {
692 pr_debug("problem processing EXIT event, skipping it.\n");
693 return -1;
694 }
695
696 if (!evsel->attr.sample_id_all) {
697 sample->cpu = 0;
698 sample->time = 0;
699 sample->tid = event->comm.tid;
700 sample->pid = event->comm.pid;
701 }
702 print_sample_start(sample, thread, evsel);
703 perf_event__fprintf(event, stdout);
704
705 if (perf_event__process_exit(tool, event, sample, machine) < 0)
706 return -1;
707
708 return 0;
709}
710
711static int process_mmap_event(struct perf_tool *tool,
712 union perf_event *event,
713 struct perf_sample *sample,
714 struct machine *machine)
715{
716 struct thread *thread;
717 struct perf_script *script = container_of(tool, struct perf_script, tool);
718 struct perf_session *session = script->session;
719 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
720
721 if (perf_event__process_mmap(tool, event, sample, machine) < 0)
722 return -1;
723
724 thread = machine__findnew_thread(machine, event->mmap.pid, event->mmap.tid);
725 if (thread == NULL) {
726 pr_debug("problem processing MMAP event, skipping it.\n");
727 return -1;
728 }
729
730 if (!evsel->attr.sample_id_all) {
731 sample->cpu = 0;
732 sample->time = 0;
733 sample->tid = event->mmap.tid;
734 sample->pid = event->mmap.pid;
735 }
736 print_sample_start(sample, thread, evsel);
737 perf_event__fprintf(event, stdout);
738
739 return 0;
740}
741
742static int process_mmap2_event(struct perf_tool *tool,
743 union perf_event *event,
744 struct perf_sample *sample,
745 struct machine *machine)
746{
747 struct thread *thread;
748 struct perf_script *script = container_of(tool, struct perf_script, tool);
749 struct perf_session *session = script->session;
750 struct perf_evsel *evsel = perf_evlist__first(session->evlist);
751
752 if (perf_event__process_mmap2(tool, event, sample, machine) < 0)
753 return -1;
754
755 thread = machine__findnew_thread(machine, event->mmap2.pid, event->mmap2.tid);
756 if (thread == NULL) {
757 pr_debug("problem processing MMAP2 event, skipping it.\n");
758 return -1;
759 }
760
761 if (!evsel->attr.sample_id_all) {
762 sample->cpu = 0;
763 sample->time = 0;
764 sample->tid = event->mmap2.tid;
765 sample->pid = event->mmap2.pid;
766 }
767 print_sample_start(sample, thread, evsel);
768 perf_event__fprintf(event, stdout);
769
770 return 0;
771}
772
582static void sig_handler(int sig __maybe_unused) 773static void sig_handler(int sig __maybe_unused)
583{ 774{
584 session_done = 1; 775 session_done = 1;
@@ -590,6 +781,17 @@ static int __cmd_script(struct perf_script *script)
590 781
591 signal(SIGINT, sig_handler); 782 signal(SIGINT, sig_handler);
592 783
784 /* override event processing functions */
785 if (script->show_task_events) {
786 script->tool.comm = process_comm_event;
787 script->tool.fork = process_fork_event;
788 script->tool.exit = process_exit_event;
789 }
790 if (script->show_mmap_events) {
791 script->tool.mmap = process_mmap_event;
792 script->tool.mmap2 = process_mmap2_event;
793 }
794
593 ret = perf_session__process_events(script->session, &script->tool); 795 ret = perf_session__process_events(script->session, &script->tool);
594 796
595 if (debug_mode) 797 if (debug_mode)
@@ -900,9 +1102,9 @@ static struct script_desc *script_desc__new(const char *name)
900 1102
901static void script_desc__delete(struct script_desc *s) 1103static void script_desc__delete(struct script_desc *s)
902{ 1104{
903 free(s->name); 1105 zfree(&s->name);
904 free(s->half_liner); 1106 zfree(&s->half_liner);
905 free(s->args); 1107 zfree(&s->args);
906 free(s); 1108 free(s);
907} 1109}
908 1110
@@ -1107,8 +1309,7 @@ static int check_ev_match(char *dir_name, char *scriptname,
1107 snprintf(evname, len + 1, "%s", p); 1309 snprintf(evname, len + 1, "%s", p);
1108 1310
1109 match = 0; 1311 match = 0;
1110 list_for_each_entry(pos, 1312 evlist__for_each(session->evlist, pos) {
1111 &session->evlist->entries, node) {
1112 if (!strcmp(perf_evsel__name(pos), evname)) { 1313 if (!strcmp(perf_evsel__name(pos), evname)) {
1113 match = 1; 1314 match = 1;
1114 break; 1315 break;
@@ -1290,6 +1491,8 @@ static int have_cmd(int argc, const char **argv)
1290int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) 1491int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1291{ 1492{
1292 bool show_full_info = false; 1493 bool show_full_info = false;
1494 bool header = false;
1495 bool header_only = false;
1293 char *rec_script_path = NULL; 1496 char *rec_script_path = NULL;
1294 char *rep_script_path = NULL; 1497 char *rep_script_path = NULL;
1295 struct perf_session *session; 1498 struct perf_session *session;
@@ -1328,6 +1531,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1328 OPT_STRING('i', "input", &input_name, "file", "input file name"), 1531 OPT_STRING('i', "input", &input_name, "file", "input file name"),
1329 OPT_BOOLEAN('d', "debug-mode", &debug_mode, 1532 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
1330 "do various checks like samples ordering and lost events"), 1533 "do various checks like samples ordering and lost events"),
1534 OPT_BOOLEAN(0, "header", &header, "Show data header."),
1535 OPT_BOOLEAN(0, "header-only", &header_only, "Show only data header."),
1331 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1536 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1332 "file", "vmlinux pathname"), 1537 "file", "vmlinux pathname"),
1333 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, 1538 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
@@ -1352,6 +1557,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1352 "display extended information from perf.data file"), 1557 "display extended information from perf.data file"),
1353 OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, 1558 OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
1354 "Show the path of [kernel.kallsyms]"), 1559 "Show the path of [kernel.kallsyms]"),
1560 OPT_BOOLEAN('\0', "show-task-events", &script.show_task_events,
1561 "Show the fork/comm/exit events"),
1562 OPT_BOOLEAN('\0', "show-mmap-events", &script.show_mmap_events,
1563 "Show the mmap events"),
1355 OPT_END() 1564 OPT_END()
1356 }; 1565 };
1357 const char * const script_usage[] = { 1566 const char * const script_usage[] = {
@@ -1540,6 +1749,12 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1540 if (session == NULL) 1749 if (session == NULL)
1541 return -ENOMEM; 1750 return -ENOMEM;
1542 1751
1752 if (header || header_only) {
1753 perf_session__fprintf_info(session, stdout, show_full_info);
1754 if (header_only)
1755 return 0;
1756 }
1757
1543 script.session = session; 1758 script.session = session;
1544 1759
1545 if (cpu_list) { 1760 if (cpu_list) {
@@ -1547,9 +1762,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1547 return -1; 1762 return -1;
1548 } 1763 }
1549 1764
1550 if (!script_name && !generate_script_lang)
1551 perf_session__fprintf_info(session, stdout, show_full_info);
1552
1553 if (!no_callchain) 1765 if (!no_callchain)
1554 symbol_conf.use_callchain = true; 1766 symbol_conf.use_callchain = true;
1555 else 1767 else
@@ -1588,7 +1800,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1588 return -1; 1800 return -1;
1589 } 1801 }
1590 1802
1591 err = scripting_ops->generate_script(session->pevent, 1803 err = scripting_ops->generate_script(session->tevent.pevent,
1592 "perf-script"); 1804 "perf-script");
1593 goto out; 1805 goto out;
1594 } 1806 }
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index ee0d565f83e3..8b0e1c9234d9 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -138,6 +138,7 @@ static const char *post_cmd = NULL;
138static bool sync_run = false; 138static bool sync_run = false;
139static unsigned int interval = 0; 139static unsigned int interval = 0;
140static unsigned int initial_delay = 0; 140static unsigned int initial_delay = 0;
141static unsigned int unit_width = 4; /* strlen("unit") */
141static bool forever = false; 142static bool forever = false;
142static struct timespec ref_time; 143static struct timespec ref_time;
143static struct cpu_map *aggr_map; 144static struct cpu_map *aggr_map;
@@ -184,8 +185,7 @@ static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
184 185
185static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) 186static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
186{ 187{
187 free(evsel->priv); 188 zfree(&evsel->priv);
188 evsel->priv = NULL;
189} 189}
190 190
191static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) 191static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
@@ -207,15 +207,14 @@ static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
207 207
208static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) 208static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
209{ 209{
210 free(evsel->prev_raw_counts); 210 zfree(&evsel->prev_raw_counts);
211 evsel->prev_raw_counts = NULL;
212} 211}
213 212
214static void perf_evlist__free_stats(struct perf_evlist *evlist) 213static void perf_evlist__free_stats(struct perf_evlist *evlist)
215{ 214{
216 struct perf_evsel *evsel; 215 struct perf_evsel *evsel;
217 216
218 list_for_each_entry(evsel, &evlist->entries, node) { 217 evlist__for_each(evlist, evsel) {
219 perf_evsel__free_stat_priv(evsel); 218 perf_evsel__free_stat_priv(evsel);
220 perf_evsel__free_counts(evsel); 219 perf_evsel__free_counts(evsel);
221 perf_evsel__free_prev_raw_counts(evsel); 220 perf_evsel__free_prev_raw_counts(evsel);
@@ -226,7 +225,7 @@ static int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
226{ 225{
227 struct perf_evsel *evsel; 226 struct perf_evsel *evsel;
228 227
229 list_for_each_entry(evsel, &evlist->entries, node) { 228 evlist__for_each(evlist, evsel) {
230 if (perf_evsel__alloc_stat_priv(evsel) < 0 || 229 if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
231 perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 || 230 perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 ||
232 (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0)) 231 (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0))
@@ -260,7 +259,7 @@ static void perf_stat__reset_stats(struct perf_evlist *evlist)
260{ 259{
261 struct perf_evsel *evsel; 260 struct perf_evsel *evsel;
262 261
263 list_for_each_entry(evsel, &evlist->entries, node) { 262 evlist__for_each(evlist, evsel) {
264 perf_evsel__reset_stat_priv(evsel); 263 perf_evsel__reset_stat_priv(evsel);
265 perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel)); 264 perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel));
266 } 265 }
@@ -327,13 +326,13 @@ static struct perf_evsel *nth_evsel(int n)
327 326
328 /* Assumes this only called when evsel_list does not change anymore. */ 327 /* Assumes this only called when evsel_list does not change anymore. */
329 if (!array) { 328 if (!array) {
330 list_for_each_entry(ev, &evsel_list->entries, node) 329 evlist__for_each(evsel_list, ev)
331 array_len++; 330 array_len++;
332 array = malloc(array_len * sizeof(void *)); 331 array = malloc(array_len * sizeof(void *));
333 if (!array) 332 if (!array)
334 exit(ENOMEM); 333 exit(ENOMEM);
335 j = 0; 334 j = 0;
336 list_for_each_entry(ev, &evsel_list->entries, node) 335 evlist__for_each(evsel_list, ev)
337 array[j++] = ev; 336 array[j++] = ev;
338 } 337 }
339 if (n < array_len) 338 if (n < array_len)
@@ -441,13 +440,13 @@ static void print_interval(void)
441 char prefix[64]; 440 char prefix[64];
442 441
443 if (aggr_mode == AGGR_GLOBAL) { 442 if (aggr_mode == AGGR_GLOBAL) {
444 list_for_each_entry(counter, &evsel_list->entries, node) { 443 evlist__for_each(evsel_list, counter) {
445 ps = counter->priv; 444 ps = counter->priv;
446 memset(ps->res_stats, 0, sizeof(ps->res_stats)); 445 memset(ps->res_stats, 0, sizeof(ps->res_stats));
447 read_counter_aggr(counter); 446 read_counter_aggr(counter);
448 } 447 }
449 } else { 448 } else {
450 list_for_each_entry(counter, &evsel_list->entries, node) { 449 evlist__for_each(evsel_list, counter) {
451 ps = counter->priv; 450 ps = counter->priv;
452 memset(ps->res_stats, 0, sizeof(ps->res_stats)); 451 memset(ps->res_stats, 0, sizeof(ps->res_stats));
453 read_counter(counter); 452 read_counter(counter);
@@ -461,17 +460,17 @@ static void print_interval(void)
461 if (num_print_interval == 0 && !csv_output) { 460 if (num_print_interval == 0 && !csv_output) {
462 switch (aggr_mode) { 461 switch (aggr_mode) {
463 case AGGR_SOCKET: 462 case AGGR_SOCKET:
464 fprintf(output, "# time socket cpus counts events\n"); 463 fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit");
465 break; 464 break;
466 case AGGR_CORE: 465 case AGGR_CORE:
467 fprintf(output, "# time core cpus counts events\n"); 466 fprintf(output, "# time core cpus counts %*s events\n", unit_width, "unit");
468 break; 467 break;
469 case AGGR_NONE: 468 case AGGR_NONE:
470 fprintf(output, "# time CPU counts events\n"); 469 fprintf(output, "# time CPU counts %*s events\n", unit_width, "unit");
471 break; 470 break;
472 case AGGR_GLOBAL: 471 case AGGR_GLOBAL:
473 default: 472 default:
474 fprintf(output, "# time counts events\n"); 473 fprintf(output, "# time counts %*s events\n", unit_width, "unit");
475 } 474 }
476 } 475 }
477 476
@@ -484,12 +483,12 @@ static void print_interval(void)
484 print_aggr(prefix); 483 print_aggr(prefix);
485 break; 484 break;
486 case AGGR_NONE: 485 case AGGR_NONE:
487 list_for_each_entry(counter, &evsel_list->entries, node) 486 evlist__for_each(evsel_list, counter)
488 print_counter(counter, prefix); 487 print_counter(counter, prefix);
489 break; 488 break;
490 case AGGR_GLOBAL: 489 case AGGR_GLOBAL:
491 default: 490 default:
492 list_for_each_entry(counter, &evsel_list->entries, node) 491 evlist__for_each(evsel_list, counter)
493 print_counter_aggr(counter, prefix); 492 print_counter_aggr(counter, prefix);
494 } 493 }
495 494
@@ -505,17 +504,31 @@ static void handle_initial_delay(void)
505 nthreads = thread_map__nr(evsel_list->threads); 504 nthreads = thread_map__nr(evsel_list->threads);
506 505
507 usleep(initial_delay * 1000); 506 usleep(initial_delay * 1000);
508 list_for_each_entry(counter, &evsel_list->entries, node) 507 evlist__for_each(evsel_list, counter)
509 perf_evsel__enable(counter, ncpus, nthreads); 508 perf_evsel__enable(counter, ncpus, nthreads);
510 } 509 }
511} 510}
512 511
512static volatile int workload_exec_errno;
513
514/*
515 * perf_evlist__prepare_workload will send a SIGUSR1
516 * if the fork fails, since we asked by setting its
517 * want_signal to true.
518 */
519static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *info,
520 void *ucontext __maybe_unused)
521{
522 workload_exec_errno = info->si_value.sival_int;
523}
524
513static int __run_perf_stat(int argc, const char **argv) 525static int __run_perf_stat(int argc, const char **argv)
514{ 526{
515 char msg[512]; 527 char msg[512];
516 unsigned long long t0, t1; 528 unsigned long long t0, t1;
517 struct perf_evsel *counter; 529 struct perf_evsel *counter;
518 struct timespec ts; 530 struct timespec ts;
531 size_t l;
519 int status = 0; 532 int status = 0;
520 const bool forks = (argc > 0); 533 const bool forks = (argc > 0);
521 534
@@ -528,8 +541,8 @@ static int __run_perf_stat(int argc, const char **argv)
528 } 541 }
529 542
530 if (forks) { 543 if (forks) {
531 if (perf_evlist__prepare_workload(evsel_list, &target, argv, 544 if (perf_evlist__prepare_workload(evsel_list, &target, argv, false,
532 false, false) < 0) { 545 workload_exec_failed_signal) < 0) {
533 perror("failed to prepare workload"); 546 perror("failed to prepare workload");
534 return -1; 547 return -1;
535 } 548 }
@@ -539,7 +552,7 @@ static int __run_perf_stat(int argc, const char **argv)
539 if (group) 552 if (group)
540 perf_evlist__set_leader(evsel_list); 553 perf_evlist__set_leader(evsel_list);
541 554
542 list_for_each_entry(counter, &evsel_list->entries, node) { 555 evlist__for_each(evsel_list, counter) {
543 if (create_perf_stat_counter(counter) < 0) { 556 if (create_perf_stat_counter(counter) < 0) {
544 /* 557 /*
545 * PPC returns ENXIO for HW counters until 2.6.37 558 * PPC returns ENXIO for HW counters until 2.6.37
@@ -565,6 +578,10 @@ static int __run_perf_stat(int argc, const char **argv)
565 return -1; 578 return -1;
566 } 579 }
567 counter->supported = true; 580 counter->supported = true;
581
582 l = strlen(counter->unit);
583 if (l > unit_width)
584 unit_width = l;
568 } 585 }
569 586
570 if (perf_evlist__apply_filters(evsel_list)) { 587 if (perf_evlist__apply_filters(evsel_list)) {
@@ -590,6 +607,13 @@ static int __run_perf_stat(int argc, const char **argv)
590 } 607 }
591 } 608 }
592 wait(&status); 609 wait(&status);
610
611 if (workload_exec_errno) {
612 const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg));
613 pr_err("Workload failed: %s\n", emsg);
614 return -1;
615 }
616
593 if (WIFSIGNALED(status)) 617 if (WIFSIGNALED(status))
594 psignal(WTERMSIG(status), argv[0]); 618 psignal(WTERMSIG(status), argv[0]);
595 } else { 619 } else {
@@ -606,13 +630,13 @@ static int __run_perf_stat(int argc, const char **argv)
606 update_stats(&walltime_nsecs_stats, t1 - t0); 630 update_stats(&walltime_nsecs_stats, t1 - t0);
607 631
608 if (aggr_mode == AGGR_GLOBAL) { 632 if (aggr_mode == AGGR_GLOBAL) {
609 list_for_each_entry(counter, &evsel_list->entries, node) { 633 evlist__for_each(evsel_list, counter) {
610 read_counter_aggr(counter); 634 read_counter_aggr(counter);
611 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 635 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
612 thread_map__nr(evsel_list->threads)); 636 thread_map__nr(evsel_list->threads));
613 } 637 }
614 } else { 638 } else {
615 list_for_each_entry(counter, &evsel_list->entries, node) { 639 evlist__for_each(evsel_list, counter) {
616 read_counter(counter); 640 read_counter(counter);
617 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1); 641 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
618 } 642 }
@@ -621,7 +645,7 @@ static int __run_perf_stat(int argc, const char **argv)
621 return WEXITSTATUS(status); 645 return WEXITSTATUS(status);
622} 646}
623 647
624static int run_perf_stat(int argc __maybe_unused, const char **argv) 648static int run_perf_stat(int argc, const char **argv)
625{ 649{
626 int ret; 650 int ret;
627 651
@@ -704,14 +728,25 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
704static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 728static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
705{ 729{
706 double msecs = avg / 1e6; 730 double msecs = avg / 1e6;
707 const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s"; 731 const char *fmt_v, *fmt_n;
708 char name[25]; 732 char name[25];
709 733
734 fmt_v = csv_output ? "%.6f%s" : "%18.6f%s";
735 fmt_n = csv_output ? "%s" : "%-25s";
736
710 aggr_printout(evsel, cpu, nr); 737 aggr_printout(evsel, cpu, nr);
711 738
712 scnprintf(name, sizeof(name), "%s%s", 739 scnprintf(name, sizeof(name), "%s%s",
713 perf_evsel__name(evsel), csv_output ? "" : " (msec)"); 740 perf_evsel__name(evsel), csv_output ? "" : " (msec)");
714 fprintf(output, fmt, msecs, csv_sep, name); 741
742 fprintf(output, fmt_v, msecs, csv_sep);
743
744 if (csv_output)
745 fprintf(output, "%s%s", evsel->unit, csv_sep);
746 else
747 fprintf(output, "%-*s%s", unit_width, evsel->unit, csv_sep);
748
749 fprintf(output, fmt_n, name);
715 750
716 if (evsel->cgrp) 751 if (evsel->cgrp)
717 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 752 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -908,21 +943,31 @@ static void print_ll_cache_misses(int cpu,
908static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 943static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
909{ 944{
910 double total, ratio = 0.0, total2; 945 double total, ratio = 0.0, total2;
946 double sc = evsel->scale;
911 const char *fmt; 947 const char *fmt;
912 948
913 if (csv_output) 949 if (csv_output) {
914 fmt = "%.0f%s%s"; 950 fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s";
915 else if (big_num) 951 } else {
916 fmt = "%'18.0f%s%-25s"; 952 if (big_num)
917 else 953 fmt = sc != 1.0 ? "%'18.2f%s" : "%'18.0f%s";
918 fmt = "%18.0f%s%-25s"; 954 else
955 fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s";
956 }
919 957
920 aggr_printout(evsel, cpu, nr); 958 aggr_printout(evsel, cpu, nr);
921 959
922 if (aggr_mode == AGGR_GLOBAL) 960 if (aggr_mode == AGGR_GLOBAL)
923 cpu = 0; 961 cpu = 0;
924 962
925 fprintf(output, fmt, avg, csv_sep, perf_evsel__name(evsel)); 963 fprintf(output, fmt, avg, csv_sep);
964
965 if (evsel->unit)
966 fprintf(output, "%-*s%s",
967 csv_output ? 0 : unit_width,
968 evsel->unit, csv_sep);
969
970 fprintf(output, "%-*s", csv_output ? 0 : 25, perf_evsel__name(evsel));
926 971
927 if (evsel->cgrp) 972 if (evsel->cgrp)
928 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 973 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -941,7 +986,10 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
941 986
942 if (total && avg) { 987 if (total && avg) {
943 ratio = total / avg; 988 ratio = total / avg;
944 fprintf(output, "\n # %5.2f stalled cycles per insn", ratio); 989 fprintf(output, "\n");
990 if (aggr_mode == AGGR_NONE)
991 fprintf(output, " ");
992 fprintf(output, " # %5.2f stalled cycles per insn", ratio);
945 } 993 }
946 994
947 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && 995 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
@@ -1061,6 +1109,7 @@ static void print_aggr(char *prefix)
1061{ 1109{
1062 struct perf_evsel *counter; 1110 struct perf_evsel *counter;
1063 int cpu, cpu2, s, s2, id, nr; 1111 int cpu, cpu2, s, s2, id, nr;
1112 double uval;
1064 u64 ena, run, val; 1113 u64 ena, run, val;
1065 1114
1066 if (!(aggr_map || aggr_get_id)) 1115 if (!(aggr_map || aggr_get_id))
@@ -1068,7 +1117,7 @@ static void print_aggr(char *prefix)
1068 1117
1069 for (s = 0; s < aggr_map->nr; s++) { 1118 for (s = 0; s < aggr_map->nr; s++) {
1070 id = aggr_map->map[s]; 1119 id = aggr_map->map[s];
1071 list_for_each_entry(counter, &evsel_list->entries, node) { 1120 evlist__for_each(evsel_list, counter) {
1072 val = ena = run = 0; 1121 val = ena = run = 0;
1073 nr = 0; 1122 nr = 0;
1074 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1123 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
@@ -1087,11 +1136,17 @@ static void print_aggr(char *prefix)
1087 if (run == 0 || ena == 0) { 1136 if (run == 0 || ena == 0) {
1088 aggr_printout(counter, id, nr); 1137 aggr_printout(counter, id, nr);
1089 1138
1090 fprintf(output, "%*s%s%*s", 1139 fprintf(output, "%*s%s",
1091 csv_output ? 0 : 18, 1140 csv_output ? 0 : 18,
1092 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 1141 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1093 csv_sep, 1142 csv_sep);
1094 csv_output ? 0 : -24, 1143
1144 fprintf(output, "%-*s%s",
1145 csv_output ? 0 : unit_width,
1146 counter->unit, csv_sep);
1147
1148 fprintf(output, "%*s",
1149 csv_output ? 0 : -25,
1095 perf_evsel__name(counter)); 1150 perf_evsel__name(counter));
1096 1151
1097 if (counter->cgrp) 1152 if (counter->cgrp)
@@ -1101,11 +1156,12 @@ static void print_aggr(char *prefix)
1101 fputc('\n', output); 1156 fputc('\n', output);
1102 continue; 1157 continue;
1103 } 1158 }
1159 uval = val * counter->scale;
1104 1160
1105 if (nsec_counter(counter)) 1161 if (nsec_counter(counter))
1106 nsec_printout(id, nr, counter, val); 1162 nsec_printout(id, nr, counter, uval);
1107 else 1163 else
1108 abs_printout(id, nr, counter, val); 1164 abs_printout(id, nr, counter, uval);
1109 1165
1110 if (!csv_output) { 1166 if (!csv_output) {
1111 print_noise(counter, 1.0); 1167 print_noise(counter, 1.0);
@@ -1128,16 +1184,21 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1128 struct perf_stat *ps = counter->priv; 1184 struct perf_stat *ps = counter->priv;
1129 double avg = avg_stats(&ps->res_stats[0]); 1185 double avg = avg_stats(&ps->res_stats[0]);
1130 int scaled = counter->counts->scaled; 1186 int scaled = counter->counts->scaled;
1187 double uval;
1131 1188
1132 if (prefix) 1189 if (prefix)
1133 fprintf(output, "%s", prefix); 1190 fprintf(output, "%s", prefix);
1134 1191
1135 if (scaled == -1) { 1192 if (scaled == -1) {
1136 fprintf(output, "%*s%s%*s", 1193 fprintf(output, "%*s%s",
1137 csv_output ? 0 : 18, 1194 csv_output ? 0 : 18,
1138 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 1195 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1139 csv_sep, 1196 csv_sep);
1140 csv_output ? 0 : -24, 1197 fprintf(output, "%-*s%s",
1198 csv_output ? 0 : unit_width,
1199 counter->unit, csv_sep);
1200 fprintf(output, "%*s",
1201 csv_output ? 0 : -25,
1141 perf_evsel__name(counter)); 1202 perf_evsel__name(counter));
1142 1203
1143 if (counter->cgrp) 1204 if (counter->cgrp)
@@ -1147,10 +1208,12 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1147 return; 1208 return;
1148 } 1209 }
1149 1210
1211 uval = avg * counter->scale;
1212
1150 if (nsec_counter(counter)) 1213 if (nsec_counter(counter))
1151 nsec_printout(-1, 0, counter, avg); 1214 nsec_printout(-1, 0, counter, uval);
1152 else 1215 else
1153 abs_printout(-1, 0, counter, avg); 1216 abs_printout(-1, 0, counter, uval);
1154 1217
1155 print_noise(counter, avg); 1218 print_noise(counter, avg);
1156 1219
@@ -1177,6 +1240,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1177static void print_counter(struct perf_evsel *counter, char *prefix) 1240static void print_counter(struct perf_evsel *counter, char *prefix)
1178{ 1241{
1179 u64 ena, run, val; 1242 u64 ena, run, val;
1243 double uval;
1180 int cpu; 1244 int cpu;
1181 1245
1182 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1246 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
@@ -1188,14 +1252,20 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
1188 fprintf(output, "%s", prefix); 1252 fprintf(output, "%s", prefix);
1189 1253
1190 if (run == 0 || ena == 0) { 1254 if (run == 0 || ena == 0) {
1191 fprintf(output, "CPU%*d%s%*s%s%*s", 1255 fprintf(output, "CPU%*d%s%*s%s",
1192 csv_output ? 0 : -4, 1256 csv_output ? 0 : -4,
1193 perf_evsel__cpus(counter)->map[cpu], csv_sep, 1257 perf_evsel__cpus(counter)->map[cpu], csv_sep,
1194 csv_output ? 0 : 18, 1258 csv_output ? 0 : 18,
1195 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 1259 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1196 csv_sep, 1260 csv_sep);
1197 csv_output ? 0 : -24, 1261
1198 perf_evsel__name(counter)); 1262 fprintf(output, "%-*s%s",
1263 csv_output ? 0 : unit_width,
1264 counter->unit, csv_sep);
1265
1266 fprintf(output, "%*s",
1267 csv_output ? 0 : -25,
1268 perf_evsel__name(counter));
1199 1269
1200 if (counter->cgrp) 1270 if (counter->cgrp)
1201 fprintf(output, "%s%s", 1271 fprintf(output, "%s%s",
@@ -1205,10 +1275,12 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
1205 continue; 1275 continue;
1206 } 1276 }
1207 1277
1278 uval = val * counter->scale;
1279
1208 if (nsec_counter(counter)) 1280 if (nsec_counter(counter))
1209 nsec_printout(cpu, 0, counter, val); 1281 nsec_printout(cpu, 0, counter, uval);
1210 else 1282 else
1211 abs_printout(cpu, 0, counter, val); 1283 abs_printout(cpu, 0, counter, uval);
1212 1284
1213 if (!csv_output) { 1285 if (!csv_output) {
1214 print_noise(counter, 1.0); 1286 print_noise(counter, 1.0);
@@ -1256,11 +1328,11 @@ static void print_stat(int argc, const char **argv)
1256 print_aggr(NULL); 1328 print_aggr(NULL);
1257 break; 1329 break;
1258 case AGGR_GLOBAL: 1330 case AGGR_GLOBAL:
1259 list_for_each_entry(counter, &evsel_list->entries, node) 1331 evlist__for_each(evsel_list, counter)
1260 print_counter_aggr(counter, NULL); 1332 print_counter_aggr(counter, NULL);
1261 break; 1333 break;
1262 case AGGR_NONE: 1334 case AGGR_NONE:
1263 list_for_each_entry(counter, &evsel_list->entries, node) 1335 evlist__for_each(evsel_list, counter)
1264 print_counter(counter, NULL); 1336 print_counter(counter, NULL);
1265 break; 1337 break;
1266 default: 1338 default:
@@ -1710,14 +1782,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1710 if (interval && interval < 100) { 1782 if (interval && interval < 100) {
1711 pr_err("print interval must be >= 100ms\n"); 1783 pr_err("print interval must be >= 100ms\n");
1712 parse_options_usage(stat_usage, options, "I", 1); 1784 parse_options_usage(stat_usage, options, "I", 1);
1713 goto out_free_maps; 1785 goto out;
1714 } 1786 }
1715 1787
1716 if (perf_evlist__alloc_stats(evsel_list, interval)) 1788 if (perf_evlist__alloc_stats(evsel_list, interval))
1717 goto out_free_maps; 1789 goto out;
1718 1790
1719 if (perf_stat_init_aggr_mode()) 1791 if (perf_stat_init_aggr_mode())
1720 goto out_free_maps; 1792 goto out;
1721 1793
1722 /* 1794 /*
1723 * We dont want to block the signals - that would cause 1795 * We dont want to block the signals - that would cause
@@ -1749,8 +1821,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1749 print_stat(argc, argv); 1821 print_stat(argc, argv);
1750 1822
1751 perf_evlist__free_stats(evsel_list); 1823 perf_evlist__free_stats(evsel_list);
1752out_free_maps:
1753 perf_evlist__delete_maps(evsel_list);
1754out: 1824out:
1755 perf_evlist__delete(evsel_list); 1825 perf_evlist__delete(evsel_list);
1756 return status; 1826 return status;
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 41c9bde2fb67..652af0b66a62 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -41,25 +41,29 @@
41#define SUPPORT_OLD_POWER_EVENTS 1 41#define SUPPORT_OLD_POWER_EVENTS 1
42#define PWR_EVENT_EXIT -1 42#define PWR_EVENT_EXIT -1
43 43
44
45static unsigned int numcpus;
46static u64 min_freq; /* Lowest CPU frequency seen */
47static u64 max_freq; /* Highest CPU frequency seen */
48static u64 turbo_frequency;
49
50static u64 first_time, last_time;
51
52static bool power_only;
53
54
55struct per_pid; 44struct per_pid;
56struct per_pidcomm;
57
58struct cpu_sample;
59struct power_event; 45struct power_event;
60struct wake_event; 46struct wake_event;
61 47
62struct sample_wrapper; 48struct timechart {
49 struct perf_tool tool;
50 struct per_pid *all_data;
51 struct power_event *power_events;
52 struct wake_event *wake_events;
53 int proc_num;
54 unsigned int numcpus;
55 u64 min_freq, /* Lowest CPU frequency seen */
56 max_freq, /* Highest CPU frequency seen */
57 turbo_frequency,
58 first_time, last_time;
59 bool power_only,
60 tasks_only,
61 with_backtrace,
62 topology;
63};
64
65struct per_pidcomm;
66struct cpu_sample;
63 67
64/* 68/*
65 * Datastructure layout: 69 * Datastructure layout:
@@ -124,10 +128,9 @@ struct cpu_sample {
124 u64 end_time; 128 u64 end_time;
125 int type; 129 int type;
126 int cpu; 130 int cpu;
131 const char *backtrace;
127}; 132};
128 133
129static struct per_pid *all_data;
130
131#define CSTATE 1 134#define CSTATE 1
132#define PSTATE 2 135#define PSTATE 2
133 136
@@ -145,12 +148,9 @@ struct wake_event {
145 int waker; 148 int waker;
146 int wakee; 149 int wakee;
147 u64 time; 150 u64 time;
151 const char *backtrace;
148}; 152};
149 153
150static struct power_event *power_events;
151static struct wake_event *wake_events;
152
153struct process_filter;
154struct process_filter { 154struct process_filter {
155 char *name; 155 char *name;
156 int pid; 156 int pid;
@@ -160,9 +160,9 @@ struct process_filter {
160static struct process_filter *process_filter; 160static struct process_filter *process_filter;
161 161
162 162
163static struct per_pid *find_create_pid(int pid) 163static struct per_pid *find_create_pid(struct timechart *tchart, int pid)
164{ 164{
165 struct per_pid *cursor = all_data; 165 struct per_pid *cursor = tchart->all_data;
166 166
167 while (cursor) { 167 while (cursor) {
168 if (cursor->pid == pid) 168 if (cursor->pid == pid)
@@ -172,16 +172,16 @@ static struct per_pid *find_create_pid(int pid)
172 cursor = zalloc(sizeof(*cursor)); 172 cursor = zalloc(sizeof(*cursor));
173 assert(cursor != NULL); 173 assert(cursor != NULL);
174 cursor->pid = pid; 174 cursor->pid = pid;
175 cursor->next = all_data; 175 cursor->next = tchart->all_data;
176 all_data = cursor; 176 tchart->all_data = cursor;
177 return cursor; 177 return cursor;
178} 178}
179 179
180static void pid_set_comm(int pid, char *comm) 180static void pid_set_comm(struct timechart *tchart, int pid, char *comm)
181{ 181{
182 struct per_pid *p; 182 struct per_pid *p;
183 struct per_pidcomm *c; 183 struct per_pidcomm *c;
184 p = find_create_pid(pid); 184 p = find_create_pid(tchart, pid);
185 c = p->all; 185 c = p->all;
186 while (c) { 186 while (c) {
187 if (c->comm && strcmp(c->comm, comm) == 0) { 187 if (c->comm && strcmp(c->comm, comm) == 0) {
@@ -203,14 +203,14 @@ static void pid_set_comm(int pid, char *comm)
203 p->all = c; 203 p->all = c;
204} 204}
205 205
206static void pid_fork(int pid, int ppid, u64 timestamp) 206static void pid_fork(struct timechart *tchart, int pid, int ppid, u64 timestamp)
207{ 207{
208 struct per_pid *p, *pp; 208 struct per_pid *p, *pp;
209 p = find_create_pid(pid); 209 p = find_create_pid(tchart, pid);
210 pp = find_create_pid(ppid); 210 pp = find_create_pid(tchart, ppid);
211 p->ppid = ppid; 211 p->ppid = ppid;
212 if (pp->current && pp->current->comm && !p->current) 212 if (pp->current && pp->current->comm && !p->current)
213 pid_set_comm(pid, pp->current->comm); 213 pid_set_comm(tchart, pid, pp->current->comm);
214 214
215 p->start_time = timestamp; 215 p->start_time = timestamp;
216 if (p->current) { 216 if (p->current) {
@@ -219,23 +219,24 @@ static void pid_fork(int pid, int ppid, u64 timestamp)
219 } 219 }
220} 220}
221 221
222static void pid_exit(int pid, u64 timestamp) 222static void pid_exit(struct timechart *tchart, int pid, u64 timestamp)
223{ 223{
224 struct per_pid *p; 224 struct per_pid *p;
225 p = find_create_pid(pid); 225 p = find_create_pid(tchart, pid);
226 p->end_time = timestamp; 226 p->end_time = timestamp;
227 if (p->current) 227 if (p->current)
228 p->current->end_time = timestamp; 228 p->current->end_time = timestamp;
229} 229}
230 230
231static void 231static void pid_put_sample(struct timechart *tchart, int pid, int type,
232pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end) 232 unsigned int cpu, u64 start, u64 end,
233 const char *backtrace)
233{ 234{
234 struct per_pid *p; 235 struct per_pid *p;
235 struct per_pidcomm *c; 236 struct per_pidcomm *c;
236 struct cpu_sample *sample; 237 struct cpu_sample *sample;
237 238
238 p = find_create_pid(pid); 239 p = find_create_pid(tchart, pid);
239 c = p->current; 240 c = p->current;
240 if (!c) { 241 if (!c) {
241 c = zalloc(sizeof(*c)); 242 c = zalloc(sizeof(*c));
@@ -252,6 +253,7 @@ pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end)
252 sample->type = type; 253 sample->type = type;
253 sample->next = c->samples; 254 sample->next = c->samples;
254 sample->cpu = cpu; 255 sample->cpu = cpu;
256 sample->backtrace = backtrace;
255 c->samples = sample; 257 c->samples = sample;
256 258
257 if (sample->type == TYPE_RUNNING && end > start && start > 0) { 259 if (sample->type == TYPE_RUNNING && end > start && start > 0) {
@@ -272,84 +274,47 @@ static int cpus_cstate_state[MAX_CPUS];
272static u64 cpus_pstate_start_times[MAX_CPUS]; 274static u64 cpus_pstate_start_times[MAX_CPUS];
273static u64 cpus_pstate_state[MAX_CPUS]; 275static u64 cpus_pstate_state[MAX_CPUS];
274 276
275static int process_comm_event(struct perf_tool *tool __maybe_unused, 277static int process_comm_event(struct perf_tool *tool,
276 union perf_event *event, 278 union perf_event *event,
277 struct perf_sample *sample __maybe_unused, 279 struct perf_sample *sample __maybe_unused,
278 struct machine *machine __maybe_unused) 280 struct machine *machine __maybe_unused)
279{ 281{
280 pid_set_comm(event->comm.tid, event->comm.comm); 282 struct timechart *tchart = container_of(tool, struct timechart, tool);
283 pid_set_comm(tchart, event->comm.tid, event->comm.comm);
281 return 0; 284 return 0;
282} 285}
283 286
284static int process_fork_event(struct perf_tool *tool __maybe_unused, 287static int process_fork_event(struct perf_tool *tool,
285 union perf_event *event, 288 union perf_event *event,
286 struct perf_sample *sample __maybe_unused, 289 struct perf_sample *sample __maybe_unused,
287 struct machine *machine __maybe_unused) 290 struct machine *machine __maybe_unused)
288{ 291{
289 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 292 struct timechart *tchart = container_of(tool, struct timechart, tool);
293 pid_fork(tchart, event->fork.pid, event->fork.ppid, event->fork.time);
290 return 0; 294 return 0;
291} 295}
292 296
293static int process_exit_event(struct perf_tool *tool __maybe_unused, 297static int process_exit_event(struct perf_tool *tool,
294 union perf_event *event, 298 union perf_event *event,
295 struct perf_sample *sample __maybe_unused, 299 struct perf_sample *sample __maybe_unused,
296 struct machine *machine __maybe_unused) 300 struct machine *machine __maybe_unused)
297{ 301{
298 pid_exit(event->fork.pid, event->fork.time); 302 struct timechart *tchart = container_of(tool, struct timechart, tool);
303 pid_exit(tchart, event->fork.pid, event->fork.time);
299 return 0; 304 return 0;
300} 305}
301 306
302struct trace_entry {
303 unsigned short type;
304 unsigned char flags;
305 unsigned char preempt_count;
306 int pid;
307 int lock_depth;
308};
309
310#ifdef SUPPORT_OLD_POWER_EVENTS 307#ifdef SUPPORT_OLD_POWER_EVENTS
311static int use_old_power_events; 308static int use_old_power_events;
312struct power_entry_old {
313 struct trace_entry te;
314 u64 type;
315 u64 value;
316 u64 cpu_id;
317};
318#endif 309#endif
319 310
320struct power_processor_entry {
321 struct trace_entry te;
322 u32 state;
323 u32 cpu_id;
324};
325
326#define TASK_COMM_LEN 16
327struct wakeup_entry {
328 struct trace_entry te;
329 char comm[TASK_COMM_LEN];
330 int pid;
331 int prio;
332 int success;
333};
334
335struct sched_switch {
336 struct trace_entry te;
337 char prev_comm[TASK_COMM_LEN];
338 int prev_pid;
339 int prev_prio;
340 long prev_state; /* Arjan weeps. */
341 char next_comm[TASK_COMM_LEN];
342 int next_pid;
343 int next_prio;
344};
345
346static void c_state_start(int cpu, u64 timestamp, int state) 311static void c_state_start(int cpu, u64 timestamp, int state)
347{ 312{
348 cpus_cstate_start_times[cpu] = timestamp; 313 cpus_cstate_start_times[cpu] = timestamp;
349 cpus_cstate_state[cpu] = state; 314 cpus_cstate_state[cpu] = state;
350} 315}
351 316
352static void c_state_end(int cpu, u64 timestamp) 317static void c_state_end(struct timechart *tchart, int cpu, u64 timestamp)
353{ 318{
354 struct power_event *pwr = zalloc(sizeof(*pwr)); 319 struct power_event *pwr = zalloc(sizeof(*pwr));
355 320
@@ -361,12 +326,12 @@ static void c_state_end(int cpu, u64 timestamp)
361 pwr->end_time = timestamp; 326 pwr->end_time = timestamp;
362 pwr->cpu = cpu; 327 pwr->cpu = cpu;
363 pwr->type = CSTATE; 328 pwr->type = CSTATE;
364 pwr->next = power_events; 329 pwr->next = tchart->power_events;
365 330
366 power_events = pwr; 331 tchart->power_events = pwr;
367} 332}
368 333
369static void p_state_change(int cpu, u64 timestamp, u64 new_freq) 334static void p_state_change(struct timechart *tchart, int cpu, u64 timestamp, u64 new_freq)
370{ 335{
371 struct power_event *pwr; 336 struct power_event *pwr;
372 337
@@ -382,73 +347,78 @@ static void p_state_change(int cpu, u64 timestamp, u64 new_freq)
382 pwr->end_time = timestamp; 347 pwr->end_time = timestamp;
383 pwr->cpu = cpu; 348 pwr->cpu = cpu;
384 pwr->type = PSTATE; 349 pwr->type = PSTATE;
385 pwr->next = power_events; 350 pwr->next = tchart->power_events;
386 351
387 if (!pwr->start_time) 352 if (!pwr->start_time)
388 pwr->start_time = first_time; 353 pwr->start_time = tchart->first_time;
389 354
390 power_events = pwr; 355 tchart->power_events = pwr;
391 356
392 cpus_pstate_state[cpu] = new_freq; 357 cpus_pstate_state[cpu] = new_freq;
393 cpus_pstate_start_times[cpu] = timestamp; 358 cpus_pstate_start_times[cpu] = timestamp;
394 359
395 if ((u64)new_freq > max_freq) 360 if ((u64)new_freq > tchart->max_freq)
396 max_freq = new_freq; 361 tchart->max_freq = new_freq;
397 362
398 if (new_freq < min_freq || min_freq == 0) 363 if (new_freq < tchart->min_freq || tchart->min_freq == 0)
399 min_freq = new_freq; 364 tchart->min_freq = new_freq;
400 365
401 if (new_freq == max_freq - 1000) 366 if (new_freq == tchart->max_freq - 1000)
402 turbo_frequency = max_freq; 367 tchart->turbo_frequency = tchart->max_freq;
403} 368}
404 369
405static void 370static void sched_wakeup(struct timechart *tchart, int cpu, u64 timestamp,
406sched_wakeup(int cpu, u64 timestamp, int pid, struct trace_entry *te) 371 int waker, int wakee, u8 flags, const char *backtrace)
407{ 372{
408 struct per_pid *p; 373 struct per_pid *p;
409 struct wakeup_entry *wake = (void *)te;
410 struct wake_event *we = zalloc(sizeof(*we)); 374 struct wake_event *we = zalloc(sizeof(*we));
411 375
412 if (!we) 376 if (!we)
413 return; 377 return;
414 378
415 we->time = timestamp; 379 we->time = timestamp;
416 we->waker = pid; 380 we->waker = waker;
381 we->backtrace = backtrace;
417 382
418 if ((te->flags & TRACE_FLAG_HARDIRQ) || (te->flags & TRACE_FLAG_SOFTIRQ)) 383 if ((flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ))
419 we->waker = -1; 384 we->waker = -1;
420 385
421 we->wakee = wake->pid; 386 we->wakee = wakee;
422 we->next = wake_events; 387 we->next = tchart->wake_events;
423 wake_events = we; 388 tchart->wake_events = we;
424 p = find_create_pid(we->wakee); 389 p = find_create_pid(tchart, we->wakee);
425 390
426 if (p && p->current && p->current->state == TYPE_NONE) { 391 if (p && p->current && p->current->state == TYPE_NONE) {
427 p->current->state_since = timestamp; 392 p->current->state_since = timestamp;
428 p->current->state = TYPE_WAITING; 393 p->current->state = TYPE_WAITING;
429 } 394 }
430 if (p && p->current && p->current->state == TYPE_BLOCKED) { 395 if (p && p->current && p->current->state == TYPE_BLOCKED) {
431 pid_put_sample(p->pid, p->current->state, cpu, p->current->state_since, timestamp); 396 pid_put_sample(tchart, p->pid, p->current->state, cpu,
397 p->current->state_since, timestamp, NULL);
432 p->current->state_since = timestamp; 398 p->current->state_since = timestamp;
433 p->current->state = TYPE_WAITING; 399 p->current->state = TYPE_WAITING;
434 } 400 }
435} 401}
436 402
437static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) 403static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp,
404 int prev_pid, int next_pid, u64 prev_state,
405 const char *backtrace)
438{ 406{
439 struct per_pid *p = NULL, *prev_p; 407 struct per_pid *p = NULL, *prev_p;
440 struct sched_switch *sw = (void *)te;
441
442 408
443 prev_p = find_create_pid(sw->prev_pid); 409 prev_p = find_create_pid(tchart, prev_pid);
444 410
445 p = find_create_pid(sw->next_pid); 411 p = find_create_pid(tchart, next_pid);
446 412
447 if (prev_p->current && prev_p->current->state != TYPE_NONE) 413 if (prev_p->current && prev_p->current->state != TYPE_NONE)
448 pid_put_sample(sw->prev_pid, TYPE_RUNNING, cpu, prev_p->current->state_since, timestamp); 414 pid_put_sample(tchart, prev_pid, TYPE_RUNNING, cpu,
415 prev_p->current->state_since, timestamp,
416 backtrace);
449 if (p && p->current) { 417 if (p && p->current) {
450 if (p->current->state != TYPE_NONE) 418 if (p->current->state != TYPE_NONE)
451 pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp); 419 pid_put_sample(tchart, next_pid, p->current->state, cpu,
420 p->current->state_since, timestamp,
421 backtrace);
452 422
453 p->current->state_since = timestamp; 423 p->current->state_since = timestamp;
454 p->current->state = TYPE_RUNNING; 424 p->current->state = TYPE_RUNNING;
@@ -457,109 +427,211 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
457 if (prev_p->current) { 427 if (prev_p->current) {
458 prev_p->current->state = TYPE_NONE; 428 prev_p->current->state = TYPE_NONE;
459 prev_p->current->state_since = timestamp; 429 prev_p->current->state_since = timestamp;
460 if (sw->prev_state & 2) 430 if (prev_state & 2)
461 prev_p->current->state = TYPE_BLOCKED; 431 prev_p->current->state = TYPE_BLOCKED;
462 if (sw->prev_state == 0) 432 if (prev_state == 0)
463 prev_p->current->state = TYPE_WAITING; 433 prev_p->current->state = TYPE_WAITING;
464 } 434 }
465} 435}
466 436
467typedef int (*tracepoint_handler)(struct perf_evsel *evsel, 437static const char *cat_backtrace(union perf_event *event,
468 struct perf_sample *sample); 438 struct perf_sample *sample,
439 struct machine *machine)
440{
441 struct addr_location al;
442 unsigned int i;
443 char *p = NULL;
444 size_t p_len;
445 u8 cpumode = PERF_RECORD_MISC_USER;
446 struct addr_location tal;
447 struct ip_callchain *chain = sample->callchain;
448 FILE *f = open_memstream(&p, &p_len);
449
450 if (!f) {
451 perror("open_memstream error");
452 return NULL;
453 }
454
455 if (!chain)
456 goto exit;
469 457
470static int process_sample_event(struct perf_tool *tool __maybe_unused, 458 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
471 union perf_event *event __maybe_unused, 459 fprintf(stderr, "problem processing %d event, skipping it.\n",
460 event->header.type);
461 goto exit;
462 }
463
464 for (i = 0; i < chain->nr; i++) {
465 u64 ip;
466
467 if (callchain_param.order == ORDER_CALLEE)
468 ip = chain->ips[i];
469 else
470 ip = chain->ips[chain->nr - i - 1];
471
472 if (ip >= PERF_CONTEXT_MAX) {
473 switch (ip) {
474 case PERF_CONTEXT_HV:
475 cpumode = PERF_RECORD_MISC_HYPERVISOR;
476 break;
477 case PERF_CONTEXT_KERNEL:
478 cpumode = PERF_RECORD_MISC_KERNEL;
479 break;
480 case PERF_CONTEXT_USER:
481 cpumode = PERF_RECORD_MISC_USER;
482 break;
483 default:
484 pr_debug("invalid callchain context: "
485 "%"PRId64"\n", (s64) ip);
486
487 /*
488 * It seems the callchain is corrupted.
489 * Discard all.
490 */
491 zfree(&p);
492 goto exit;
493 }
494 continue;
495 }
496
497 tal.filtered = false;
498 thread__find_addr_location(al.thread, machine, cpumode,
499 MAP__FUNCTION, ip, &tal);
500
501 if (tal.sym)
502 fprintf(f, "..... %016" PRIx64 " %s\n", ip,
503 tal.sym->name);
504 else
505 fprintf(f, "..... %016" PRIx64 "\n", ip);
506 }
507
508exit:
509 fclose(f);
510
511 return p;
512}
513
514typedef int (*tracepoint_handler)(struct timechart *tchart,
515 struct perf_evsel *evsel,
516 struct perf_sample *sample,
517 const char *backtrace);
518
519static int process_sample_event(struct perf_tool *tool,
520 union perf_event *event,
472 struct perf_sample *sample, 521 struct perf_sample *sample,
473 struct perf_evsel *evsel, 522 struct perf_evsel *evsel,
474 struct machine *machine __maybe_unused) 523 struct machine *machine)
475{ 524{
525 struct timechart *tchart = container_of(tool, struct timechart, tool);
526
476 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { 527 if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
477 if (!first_time || first_time > sample->time) 528 if (!tchart->first_time || tchart->first_time > sample->time)
478 first_time = sample->time; 529 tchart->first_time = sample->time;
479 if (last_time < sample->time) 530 if (tchart->last_time < sample->time)
480 last_time = sample->time; 531 tchart->last_time = sample->time;
481 } 532 }
482 533
483 if (sample->cpu > numcpus)
484 numcpus = sample->cpu;
485
486 if (evsel->handler != NULL) { 534 if (evsel->handler != NULL) {
487 tracepoint_handler f = evsel->handler; 535 tracepoint_handler f = evsel->handler;
488 return f(evsel, sample); 536 return f(tchart, evsel, sample,
537 cat_backtrace(event, sample, machine));
489 } 538 }
490 539
491 return 0; 540 return 0;
492} 541}
493 542
494static int 543static int
495process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused, 544process_sample_cpu_idle(struct timechart *tchart __maybe_unused,
496 struct perf_sample *sample) 545 struct perf_evsel *evsel,
546 struct perf_sample *sample,
547 const char *backtrace __maybe_unused)
497{ 548{
498 struct power_processor_entry *ppe = sample->raw_data; 549 u32 state = perf_evsel__intval(evsel, sample, "state");
550 u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
499 551
500 if (ppe->state == (u32) PWR_EVENT_EXIT) 552 if (state == (u32)PWR_EVENT_EXIT)
501 c_state_end(ppe->cpu_id, sample->time); 553 c_state_end(tchart, cpu_id, sample->time);
502 else 554 else
503 c_state_start(ppe->cpu_id, sample->time, ppe->state); 555 c_state_start(cpu_id, sample->time, state);
504 return 0; 556 return 0;
505} 557}
506 558
507static int 559static int
508process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused, 560process_sample_cpu_frequency(struct timechart *tchart,
509 struct perf_sample *sample) 561 struct perf_evsel *evsel,
562 struct perf_sample *sample,
563 const char *backtrace __maybe_unused)
510{ 564{
511 struct power_processor_entry *ppe = sample->raw_data; 565 u32 state = perf_evsel__intval(evsel, sample, "state");
566 u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
512 567
513 p_state_change(ppe->cpu_id, sample->time, ppe->state); 568 p_state_change(tchart, cpu_id, sample->time, state);
514 return 0; 569 return 0;
515} 570}
516 571
517static int 572static int
518process_sample_sched_wakeup(struct perf_evsel *evsel __maybe_unused, 573process_sample_sched_wakeup(struct timechart *tchart,
519 struct perf_sample *sample) 574 struct perf_evsel *evsel,
575 struct perf_sample *sample,
576 const char *backtrace)
520{ 577{
521 struct trace_entry *te = sample->raw_data; 578 u8 flags = perf_evsel__intval(evsel, sample, "common_flags");
579 int waker = perf_evsel__intval(evsel, sample, "common_pid");
580 int wakee = perf_evsel__intval(evsel, sample, "pid");
522 581
523 sched_wakeup(sample->cpu, sample->time, sample->pid, te); 582 sched_wakeup(tchart, sample->cpu, sample->time, waker, wakee, flags, backtrace);
524 return 0; 583 return 0;
525} 584}
526 585
527static int 586static int
528process_sample_sched_switch(struct perf_evsel *evsel __maybe_unused, 587process_sample_sched_switch(struct timechart *tchart,
529 struct perf_sample *sample) 588 struct perf_evsel *evsel,
589 struct perf_sample *sample,
590 const char *backtrace)
530{ 591{
531 struct trace_entry *te = sample->raw_data; 592 int prev_pid = perf_evsel__intval(evsel, sample, "prev_pid");
593 int next_pid = perf_evsel__intval(evsel, sample, "next_pid");
594 u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state");
532 595
533 sched_switch(sample->cpu, sample->time, te); 596 sched_switch(tchart, sample->cpu, sample->time, prev_pid, next_pid,
597 prev_state, backtrace);
534 return 0; 598 return 0;
535} 599}
536 600
537#ifdef SUPPORT_OLD_POWER_EVENTS 601#ifdef SUPPORT_OLD_POWER_EVENTS
538static int 602static int
539process_sample_power_start(struct perf_evsel *evsel __maybe_unused, 603process_sample_power_start(struct timechart *tchart __maybe_unused,
540 struct perf_sample *sample) 604 struct perf_evsel *evsel,
605 struct perf_sample *sample,
606 const char *backtrace __maybe_unused)
541{ 607{
542 struct power_entry_old *peo = sample->raw_data; 608 u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
609 u64 value = perf_evsel__intval(evsel, sample, "value");
543 610
544 c_state_start(peo->cpu_id, sample->time, peo->value); 611 c_state_start(cpu_id, sample->time, value);
545 return 0; 612 return 0;
546} 613}
547 614
548static int 615static int
549process_sample_power_end(struct perf_evsel *evsel __maybe_unused, 616process_sample_power_end(struct timechart *tchart,
550 struct perf_sample *sample) 617 struct perf_evsel *evsel __maybe_unused,
618 struct perf_sample *sample,
619 const char *backtrace __maybe_unused)
551{ 620{
552 c_state_end(sample->cpu, sample->time); 621 c_state_end(tchart, sample->cpu, sample->time);
553 return 0; 622 return 0;
554} 623}
555 624
556static int 625static int
557process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused, 626process_sample_power_frequency(struct timechart *tchart,
558 struct perf_sample *sample) 627 struct perf_evsel *evsel,
628 struct perf_sample *sample,
629 const char *backtrace __maybe_unused)
559{ 630{
560 struct power_entry_old *peo = sample->raw_data; 631 u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
632 u64 value = perf_evsel__intval(evsel, sample, "value");
561 633
562 p_state_change(peo->cpu_id, sample->time, peo->value); 634 p_state_change(tchart, cpu_id, sample->time, value);
563 return 0; 635 return 0;
564} 636}
565#endif /* SUPPORT_OLD_POWER_EVENTS */ 637#endif /* SUPPORT_OLD_POWER_EVENTS */
@@ -568,12 +640,12 @@ process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused,
568 * After the last sample we need to wrap up the current C/P state 640 * After the last sample we need to wrap up the current C/P state
569 * and close out each CPU for these. 641 * and close out each CPU for these.
570 */ 642 */
571static void end_sample_processing(void) 643static void end_sample_processing(struct timechart *tchart)
572{ 644{
573 u64 cpu; 645 u64 cpu;
574 struct power_event *pwr; 646 struct power_event *pwr;
575 647
576 for (cpu = 0; cpu <= numcpus; cpu++) { 648 for (cpu = 0; cpu <= tchart->numcpus; cpu++) {
577 /* C state */ 649 /* C state */
578#if 0 650#if 0
579 pwr = zalloc(sizeof(*pwr)); 651 pwr = zalloc(sizeof(*pwr));
@@ -582,12 +654,12 @@ static void end_sample_processing(void)
582 654
583 pwr->state = cpus_cstate_state[cpu]; 655 pwr->state = cpus_cstate_state[cpu];
584 pwr->start_time = cpus_cstate_start_times[cpu]; 656 pwr->start_time = cpus_cstate_start_times[cpu];
585 pwr->end_time = last_time; 657 pwr->end_time = tchart->last_time;
586 pwr->cpu = cpu; 658 pwr->cpu = cpu;
587 pwr->type = CSTATE; 659 pwr->type = CSTATE;
588 pwr->next = power_events; 660 pwr->next = tchart->power_events;
589 661
590 power_events = pwr; 662 tchart->power_events = pwr;
591#endif 663#endif
592 /* P state */ 664 /* P state */
593 665
@@ -597,32 +669,32 @@ static void end_sample_processing(void)
597 669
598 pwr->state = cpus_pstate_state[cpu]; 670 pwr->state = cpus_pstate_state[cpu];
599 pwr->start_time = cpus_pstate_start_times[cpu]; 671 pwr->start_time = cpus_pstate_start_times[cpu];
600 pwr->end_time = last_time; 672 pwr->end_time = tchart->last_time;
601 pwr->cpu = cpu; 673 pwr->cpu = cpu;
602 pwr->type = PSTATE; 674 pwr->type = PSTATE;
603 pwr->next = power_events; 675 pwr->next = tchart->power_events;
604 676
605 if (!pwr->start_time) 677 if (!pwr->start_time)
606 pwr->start_time = first_time; 678 pwr->start_time = tchart->first_time;
607 if (!pwr->state) 679 if (!pwr->state)
608 pwr->state = min_freq; 680 pwr->state = tchart->min_freq;
609 power_events = pwr; 681 tchart->power_events = pwr;
610 } 682 }
611} 683}
612 684
613/* 685/*
614 * Sort the pid datastructure 686 * Sort the pid datastructure
615 */ 687 */
616static void sort_pids(void) 688static void sort_pids(struct timechart *tchart)
617{ 689{
618 struct per_pid *new_list, *p, *cursor, *prev; 690 struct per_pid *new_list, *p, *cursor, *prev;
619 /* sort by ppid first, then by pid, lowest to highest */ 691 /* sort by ppid first, then by pid, lowest to highest */
620 692
621 new_list = NULL; 693 new_list = NULL;
622 694
623 while (all_data) { 695 while (tchart->all_data) {
624 p = all_data; 696 p = tchart->all_data;
625 all_data = p->next; 697 tchart->all_data = p->next;
626 p->next = NULL; 698 p->next = NULL;
627 699
628 if (new_list == NULL) { 700 if (new_list == NULL) {
@@ -655,14 +727,14 @@ static void sort_pids(void)
655 prev->next = p; 727 prev->next = p;
656 } 728 }
657 } 729 }
658 all_data = new_list; 730 tchart->all_data = new_list;
659} 731}
660 732
661 733
662static void draw_c_p_states(void) 734static void draw_c_p_states(struct timechart *tchart)
663{ 735{
664 struct power_event *pwr; 736 struct power_event *pwr;
665 pwr = power_events; 737 pwr = tchart->power_events;
666 738
667 /* 739 /*
668 * two pass drawing so that the P state bars are on top of the C state blocks 740 * two pass drawing so that the P state bars are on top of the C state blocks
@@ -673,30 +745,30 @@ static void draw_c_p_states(void)
673 pwr = pwr->next; 745 pwr = pwr->next;
674 } 746 }
675 747
676 pwr = power_events; 748 pwr = tchart->power_events;
677 while (pwr) { 749 while (pwr) {
678 if (pwr->type == PSTATE) { 750 if (pwr->type == PSTATE) {
679 if (!pwr->state) 751 if (!pwr->state)
680 pwr->state = min_freq; 752 pwr->state = tchart->min_freq;
681 svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state); 753 svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
682 } 754 }
683 pwr = pwr->next; 755 pwr = pwr->next;
684 } 756 }
685} 757}
686 758
687static void draw_wakeups(void) 759static void draw_wakeups(struct timechart *tchart)
688{ 760{
689 struct wake_event *we; 761 struct wake_event *we;
690 struct per_pid *p; 762 struct per_pid *p;
691 struct per_pidcomm *c; 763 struct per_pidcomm *c;
692 764
693 we = wake_events; 765 we = tchart->wake_events;
694 while (we) { 766 while (we) {
695 int from = 0, to = 0; 767 int from = 0, to = 0;
696 char *task_from = NULL, *task_to = NULL; 768 char *task_from = NULL, *task_to = NULL;
697 769
698 /* locate the column of the waker and wakee */ 770 /* locate the column of the waker and wakee */
699 p = all_data; 771 p = tchart->all_data;
700 while (p) { 772 while (p) {
701 if (p->pid == we->waker || p->pid == we->wakee) { 773 if (p->pid == we->waker || p->pid == we->wakee) {
702 c = p->all; 774 c = p->all;
@@ -739,11 +811,12 @@ static void draw_wakeups(void)
739 } 811 }
740 812
741 if (we->waker == -1) 813 if (we->waker == -1)
742 svg_interrupt(we->time, to); 814 svg_interrupt(we->time, to, we->backtrace);
743 else if (from && to && abs(from - to) == 1) 815 else if (from && to && abs(from - to) == 1)
744 svg_wakeline(we->time, from, to); 816 svg_wakeline(we->time, from, to, we->backtrace);
745 else 817 else
746 svg_partial_wakeline(we->time, from, task_from, to, task_to); 818 svg_partial_wakeline(we->time, from, task_from, to,
819 task_to, we->backtrace);
747 we = we->next; 820 we = we->next;
748 821
749 free(task_from); 822 free(task_from);
@@ -751,19 +824,25 @@ static void draw_wakeups(void)
751 } 824 }
752} 825}
753 826
754static void draw_cpu_usage(void) 827static void draw_cpu_usage(struct timechart *tchart)
755{ 828{
756 struct per_pid *p; 829 struct per_pid *p;
757 struct per_pidcomm *c; 830 struct per_pidcomm *c;
758 struct cpu_sample *sample; 831 struct cpu_sample *sample;
759 p = all_data; 832 p = tchart->all_data;
760 while (p) { 833 while (p) {
761 c = p->all; 834 c = p->all;
762 while (c) { 835 while (c) {
763 sample = c->samples; 836 sample = c->samples;
764 while (sample) { 837 while (sample) {
765 if (sample->type == TYPE_RUNNING) 838 if (sample->type == TYPE_RUNNING) {
766 svg_process(sample->cpu, sample->start_time, sample->end_time, "sample", c->comm); 839 svg_process(sample->cpu,
840 sample->start_time,
841 sample->end_time,
842 p->pid,
843 c->comm,
844 sample->backtrace);
845 }
767 846
768 sample = sample->next; 847 sample = sample->next;
769 } 848 }
@@ -773,16 +852,16 @@ static void draw_cpu_usage(void)
773 } 852 }
774} 853}
775 854
776static void draw_process_bars(void) 855static void draw_process_bars(struct timechart *tchart)
777{ 856{
778 struct per_pid *p; 857 struct per_pid *p;
779 struct per_pidcomm *c; 858 struct per_pidcomm *c;
780 struct cpu_sample *sample; 859 struct cpu_sample *sample;
781 int Y = 0; 860 int Y = 0;
782 861
783 Y = 2 * numcpus + 2; 862 Y = 2 * tchart->numcpus + 2;
784 863
785 p = all_data; 864 p = tchart->all_data;
786 while (p) { 865 while (p) {
787 c = p->all; 866 c = p->all;
788 while (c) { 867 while (c) {
@@ -796,11 +875,20 @@ static void draw_process_bars(void)
796 sample = c->samples; 875 sample = c->samples;
797 while (sample) { 876 while (sample) {
798 if (sample->type == TYPE_RUNNING) 877 if (sample->type == TYPE_RUNNING)
799 svg_sample(Y, sample->cpu, sample->start_time, sample->end_time); 878 svg_running(Y, sample->cpu,
879 sample->start_time,
880 sample->end_time,
881 sample->backtrace);
800 if (sample->type == TYPE_BLOCKED) 882 if (sample->type == TYPE_BLOCKED)
801 svg_box(Y, sample->start_time, sample->end_time, "blocked"); 883 svg_blocked(Y, sample->cpu,
884 sample->start_time,
885 sample->end_time,
886 sample->backtrace);
802 if (sample->type == TYPE_WAITING) 887 if (sample->type == TYPE_WAITING)
803 svg_waiting(Y, sample->start_time, sample->end_time); 888 svg_waiting(Y, sample->cpu,
889 sample->start_time,
890 sample->end_time,
891 sample->backtrace);
804 sample = sample->next; 892 sample = sample->next;
805 } 893 }
806 894
@@ -853,21 +941,21 @@ static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
853 return 0; 941 return 0;
854} 942}
855 943
856static int determine_display_tasks_filtered(void) 944static int determine_display_tasks_filtered(struct timechart *tchart)
857{ 945{
858 struct per_pid *p; 946 struct per_pid *p;
859 struct per_pidcomm *c; 947 struct per_pidcomm *c;
860 int count = 0; 948 int count = 0;
861 949
862 p = all_data; 950 p = tchart->all_data;
863 while (p) { 951 while (p) {
864 p->display = 0; 952 p->display = 0;
865 if (p->start_time == 1) 953 if (p->start_time == 1)
866 p->start_time = first_time; 954 p->start_time = tchart->first_time;
867 955
868 /* no exit marker, task kept running to the end */ 956 /* no exit marker, task kept running to the end */
869 if (p->end_time == 0) 957 if (p->end_time == 0)
870 p->end_time = last_time; 958 p->end_time = tchart->last_time;
871 959
872 c = p->all; 960 c = p->all;
873 961
@@ -875,7 +963,7 @@ static int determine_display_tasks_filtered(void)
875 c->display = 0; 963 c->display = 0;
876 964
877 if (c->start_time == 1) 965 if (c->start_time == 1)
878 c->start_time = first_time; 966 c->start_time = tchart->first_time;
879 967
880 if (passes_filter(p, c)) { 968 if (passes_filter(p, c)) {
881 c->display = 1; 969 c->display = 1;
@@ -884,7 +972,7 @@ static int determine_display_tasks_filtered(void)
884 } 972 }
885 973
886 if (c->end_time == 0) 974 if (c->end_time == 0)
887 c->end_time = last_time; 975 c->end_time = tchart->last_time;
888 976
889 c = c->next; 977 c = c->next;
890 } 978 }
@@ -893,25 +981,25 @@ static int determine_display_tasks_filtered(void)
893 return count; 981 return count;
894} 982}
895 983
896static int determine_display_tasks(u64 threshold) 984static int determine_display_tasks(struct timechart *tchart, u64 threshold)
897{ 985{
898 struct per_pid *p; 986 struct per_pid *p;
899 struct per_pidcomm *c; 987 struct per_pidcomm *c;
900 int count = 0; 988 int count = 0;
901 989
902 if (process_filter) 990 if (process_filter)
903 return determine_display_tasks_filtered(); 991 return determine_display_tasks_filtered(tchart);
904 992
905 p = all_data; 993 p = tchart->all_data;
906 while (p) { 994 while (p) {
907 p->display = 0; 995 p->display = 0;
908 if (p->start_time == 1) 996 if (p->start_time == 1)
909 p->start_time = first_time; 997 p->start_time = tchart->first_time;
910 998
911 /* no exit marker, task kept running to the end */ 999 /* no exit marker, task kept running to the end */
912 if (p->end_time == 0) 1000 if (p->end_time == 0)
913 p->end_time = last_time; 1001 p->end_time = tchart->last_time;
914 if (p->total_time >= threshold && !power_only) 1002 if (p->total_time >= threshold)
915 p->display = 1; 1003 p->display = 1;
916 1004
917 c = p->all; 1005 c = p->all;
@@ -920,15 +1008,15 @@ static int determine_display_tasks(u64 threshold)
920 c->display = 0; 1008 c->display = 0;
921 1009
922 if (c->start_time == 1) 1010 if (c->start_time == 1)
923 c->start_time = first_time; 1011 c->start_time = tchart->first_time;
924 1012
925 if (c->total_time >= threshold && !power_only) { 1013 if (c->total_time >= threshold) {
926 c->display = 1; 1014 c->display = 1;
927 count++; 1015 count++;
928 } 1016 }
929 1017
930 if (c->end_time == 0) 1018 if (c->end_time == 0)
931 c->end_time = last_time; 1019 c->end_time = tchart->last_time;
932 1020
933 c = c->next; 1021 c = c->next;
934 } 1022 }
@@ -941,45 +1029,74 @@ static int determine_display_tasks(u64 threshold)
941 1029
942#define TIME_THRESH 10000000 1030#define TIME_THRESH 10000000
943 1031
944static void write_svg_file(const char *filename) 1032static void write_svg_file(struct timechart *tchart, const char *filename)
945{ 1033{
946 u64 i; 1034 u64 i;
947 int count; 1035 int count;
1036 int thresh = TIME_THRESH;
948 1037
949 numcpus++; 1038 if (tchart->power_only)
950 1039 tchart->proc_num = 0;
951 1040
952 count = determine_display_tasks(TIME_THRESH); 1041 /* We'd like to show at least proc_num tasks;
1042 * be less picky if we have fewer */
1043 do {
1044 count = determine_display_tasks(tchart, thresh);
1045 thresh /= 10;
1046 } while (!process_filter && thresh && count < tchart->proc_num);
953 1047
954 /* We'd like to show at least 15 tasks; be less picky if we have fewer */ 1048 open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time);
955 if (count < 15)
956 count = determine_display_tasks(TIME_THRESH / 10);
957
958 open_svg(filename, numcpus, count, first_time, last_time);
959 1049
960 svg_time_grid(); 1050 svg_time_grid();
961 svg_legenda(); 1051 svg_legenda();
962 1052
963 for (i = 0; i < numcpus; i++) 1053 for (i = 0; i < tchart->numcpus; i++)
964 svg_cpu_box(i, max_freq, turbo_frequency); 1054 svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);
965 1055
966 draw_cpu_usage(); 1056 draw_cpu_usage(tchart);
967 draw_process_bars(); 1057 if (tchart->proc_num)
968 draw_c_p_states(); 1058 draw_process_bars(tchart);
969 draw_wakeups(); 1059 if (!tchart->tasks_only)
1060 draw_c_p_states(tchart);
1061 if (tchart->proc_num)
1062 draw_wakeups(tchart);
970 1063
971 svg_close(); 1064 svg_close();
972} 1065}
973 1066
974static int __cmd_timechart(const char *output_name) 1067static int process_header(struct perf_file_section *section __maybe_unused,
1068 struct perf_header *ph,
1069 int feat,
1070 int fd __maybe_unused,
1071 void *data)
1072{
1073 struct timechart *tchart = data;
1074
1075 switch (feat) {
1076 case HEADER_NRCPUS:
1077 tchart->numcpus = ph->env.nr_cpus_avail;
1078 break;
1079
1080 case HEADER_CPU_TOPOLOGY:
1081 if (!tchart->topology)
1082 break;
1083
1084 if (svg_build_topology_map(ph->env.sibling_cores,
1085 ph->env.nr_sibling_cores,
1086 ph->env.sibling_threads,
1087 ph->env.nr_sibling_threads))
1088 fprintf(stderr, "problem building topology\n");
1089 break;
1090
1091 default:
1092 break;
1093 }
1094
1095 return 0;
1096}
1097
1098static int __cmd_timechart(struct timechart *tchart, const char *output_name)
975{ 1099{
976 struct perf_tool perf_timechart = {
977 .comm = process_comm_event,
978 .fork = process_fork_event,
979 .exit = process_exit_event,
980 .sample = process_sample_event,
981 .ordered_samples = true,
982 };
983 const struct perf_evsel_str_handler power_tracepoints[] = { 1100 const struct perf_evsel_str_handler power_tracepoints[] = {
984 { "power:cpu_idle", process_sample_cpu_idle }, 1101 { "power:cpu_idle", process_sample_cpu_idle },
985 { "power:cpu_frequency", process_sample_cpu_frequency }, 1102 { "power:cpu_frequency", process_sample_cpu_frequency },
@@ -997,12 +1114,17 @@ static int __cmd_timechart(const char *output_name)
997 }; 1114 };
998 1115
999 struct perf_session *session = perf_session__new(&file, false, 1116 struct perf_session *session = perf_session__new(&file, false,
1000 &perf_timechart); 1117 &tchart->tool);
1001 int ret = -EINVAL; 1118 int ret = -EINVAL;
1002 1119
1003 if (session == NULL) 1120 if (session == NULL)
1004 return -ENOMEM; 1121 return -ENOMEM;
1005 1122
1123 (void)perf_header__process_sections(&session->header,
1124 perf_data_file__fd(session->file),
1125 tchart,
1126 process_header);
1127
1006 if (!perf_session__has_traces(session, "timechart record")) 1128 if (!perf_session__has_traces(session, "timechart record"))
1007 goto out_delete; 1129 goto out_delete;
1008 1130
@@ -1012,69 +1134,111 @@ static int __cmd_timechart(const char *output_name)
1012 goto out_delete; 1134 goto out_delete;
1013 } 1135 }
1014 1136
1015 ret = perf_session__process_events(session, &perf_timechart); 1137 ret = perf_session__process_events(session, &tchart->tool);
1016 if (ret) 1138 if (ret)
1017 goto out_delete; 1139 goto out_delete;
1018 1140
1019 end_sample_processing(); 1141 end_sample_processing(tchart);
1020 1142
1021 sort_pids(); 1143 sort_pids(tchart);
1022 1144
1023 write_svg_file(output_name); 1145 write_svg_file(tchart, output_name);
1024 1146
1025 pr_info("Written %2.1f seconds of trace to %s.\n", 1147 pr_info("Written %2.1f seconds of trace to %s.\n",
1026 (last_time - first_time) / 1000000000.0, output_name); 1148 (tchart->last_time - tchart->first_time) / 1000000000.0, output_name);
1027out_delete: 1149out_delete:
1028 perf_session__delete(session); 1150 perf_session__delete(session);
1029 return ret; 1151 return ret;
1030} 1152}
1031 1153
1032static int __cmd_record(int argc, const char **argv) 1154static int timechart__record(struct timechart *tchart, int argc, const char **argv)
1033{ 1155{
1034#ifdef SUPPORT_OLD_POWER_EVENTS 1156 unsigned int rec_argc, i, j;
1035 const char * const record_old_args[] = { 1157 const char **rec_argv;
1158 const char **p;
1159 unsigned int record_elems;
1160
1161 const char * const common_args[] = {
1036 "record", "-a", "-R", "-c", "1", 1162 "record", "-a", "-R", "-c", "1",
1163 };
1164 unsigned int common_args_nr = ARRAY_SIZE(common_args);
1165
1166 const char * const backtrace_args[] = {
1167 "-g",
1168 };
1169 unsigned int backtrace_args_no = ARRAY_SIZE(backtrace_args);
1170
1171 const char * const power_args[] = {
1172 "-e", "power:cpu_frequency",
1173 "-e", "power:cpu_idle",
1174 };
1175 unsigned int power_args_nr = ARRAY_SIZE(power_args);
1176
1177 const char * const old_power_args[] = {
1178#ifdef SUPPORT_OLD_POWER_EVENTS
1037 "-e", "power:power_start", 1179 "-e", "power:power_start",
1038 "-e", "power:power_end", 1180 "-e", "power:power_end",
1039 "-e", "power:power_frequency", 1181 "-e", "power:power_frequency",
1040 "-e", "sched:sched_wakeup",
1041 "-e", "sched:sched_switch",
1042 };
1043#endif 1182#endif
1044 const char * const record_new_args[] = { 1183 };
1045 "record", "-a", "-R", "-c", "1", 1184 unsigned int old_power_args_nr = ARRAY_SIZE(old_power_args);
1046 "-e", "power:cpu_frequency", 1185
1047 "-e", "power:cpu_idle", 1186 const char * const tasks_args[] = {
1048 "-e", "sched:sched_wakeup", 1187 "-e", "sched:sched_wakeup",
1049 "-e", "sched:sched_switch", 1188 "-e", "sched:sched_switch",
1050 }; 1189 };
1051 unsigned int rec_argc, i, j; 1190 unsigned int tasks_args_nr = ARRAY_SIZE(tasks_args);
1052 const char **rec_argv;
1053 const char * const *record_args = record_new_args;
1054 unsigned int record_elems = ARRAY_SIZE(record_new_args);
1055 1191
1056#ifdef SUPPORT_OLD_POWER_EVENTS 1192#ifdef SUPPORT_OLD_POWER_EVENTS
1057 if (!is_valid_tracepoint("power:cpu_idle") && 1193 if (!is_valid_tracepoint("power:cpu_idle") &&
1058 is_valid_tracepoint("power:power_start")) { 1194 is_valid_tracepoint("power:power_start")) {
1059 use_old_power_events = 1; 1195 use_old_power_events = 1;
1060 record_args = record_old_args; 1196 power_args_nr = 0;
1061 record_elems = ARRAY_SIZE(record_old_args); 1197 } else {
1198 old_power_args_nr = 0;
1062 } 1199 }
1063#endif 1200#endif
1064 1201
1065 rec_argc = record_elems + argc - 1; 1202 if (tchart->power_only)
1203 tasks_args_nr = 0;
1204
1205 if (tchart->tasks_only) {
1206 power_args_nr = 0;
1207 old_power_args_nr = 0;
1208 }
1209
1210 if (!tchart->with_backtrace)
1211 backtrace_args_no = 0;
1212
1213 record_elems = common_args_nr + tasks_args_nr +
1214 power_args_nr + old_power_args_nr + backtrace_args_no;
1215
1216 rec_argc = record_elems + argc;
1066 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1217 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1067 1218
1068 if (rec_argv == NULL) 1219 if (rec_argv == NULL)
1069 return -ENOMEM; 1220 return -ENOMEM;
1070 1221
1071 for (i = 0; i < record_elems; i++) 1222 p = rec_argv;
1072 rec_argv[i] = strdup(record_args[i]); 1223 for (i = 0; i < common_args_nr; i++)
1224 *p++ = strdup(common_args[i]);
1225
1226 for (i = 0; i < backtrace_args_no; i++)
1227 *p++ = strdup(backtrace_args[i]);
1228
1229 for (i = 0; i < tasks_args_nr; i++)
1230 *p++ = strdup(tasks_args[i]);
1231
1232 for (i = 0; i < power_args_nr; i++)
1233 *p++ = strdup(power_args[i]);
1073 1234
1074 for (j = 1; j < (unsigned int)argc; j++, i++) 1235 for (i = 0; i < old_power_args_nr; i++)
1075 rec_argv[i] = argv[j]; 1236 *p++ = strdup(old_power_args[i]);
1076 1237
1077 return cmd_record(i, rec_argv, NULL); 1238 for (j = 1; j < (unsigned int)argc; j++)
1239 *p++ = argv[j];
1240
1241 return cmd_record(rec_argc, rec_argv, NULL);
1078} 1242}
1079 1243
1080static int 1244static int
@@ -1086,20 +1250,56 @@ parse_process(const struct option *opt __maybe_unused, const char *arg,
1086 return 0; 1250 return 0;
1087} 1251}
1088 1252
1253static int
1254parse_highlight(const struct option *opt __maybe_unused, const char *arg,
1255 int __maybe_unused unset)
1256{
1257 unsigned long duration = strtoul(arg, NULL, 0);
1258
1259 if (svg_highlight || svg_highlight_name)
1260 return -1;
1261
1262 if (duration)
1263 svg_highlight = duration;
1264 else
1265 svg_highlight_name = strdup(arg);
1266
1267 return 0;
1268}
1269
1089int cmd_timechart(int argc, const char **argv, 1270int cmd_timechart(int argc, const char **argv,
1090 const char *prefix __maybe_unused) 1271 const char *prefix __maybe_unused)
1091{ 1272{
1273 struct timechart tchart = {
1274 .tool = {
1275 .comm = process_comm_event,
1276 .fork = process_fork_event,
1277 .exit = process_exit_event,
1278 .sample = process_sample_event,
1279 .ordered_samples = true,
1280 },
1281 .proc_num = 15,
1282 };
1092 const char *output_name = "output.svg"; 1283 const char *output_name = "output.svg";
1093 const struct option options[] = { 1284 const struct option timechart_options[] = {
1094 OPT_STRING('i', "input", &input_name, "file", "input file name"), 1285 OPT_STRING('i', "input", &input_name, "file", "input file name"),
1095 OPT_STRING('o', "output", &output_name, "file", "output file name"), 1286 OPT_STRING('o', "output", &output_name, "file", "output file name"),
1096 OPT_INTEGER('w', "width", &svg_page_width, "page width"), 1287 OPT_INTEGER('w', "width", &svg_page_width, "page width"),
1097 OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"), 1288 OPT_CALLBACK(0, "highlight", NULL, "duration or task name",
1289 "highlight tasks. Pass duration in ns or process name.",
1290 parse_highlight),
1291 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1292 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1293 "output processes data only"),
1098 OPT_CALLBACK('p', "process", NULL, "process", 1294 OPT_CALLBACK('p', "process", NULL, "process",
1099 "process selector. Pass a pid or process name.", 1295 "process selector. Pass a pid or process name.",
1100 parse_process), 1296 parse_process),
1101 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 1297 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
1102 "Look for files with symbols relative to this directory"), 1298 "Look for files with symbols relative to this directory"),
1299 OPT_INTEGER('n', "proc-num", &tchart.proc_num,
1300 "min. number of tasks to print"),
1301 OPT_BOOLEAN('t', "topology", &tchart.topology,
1302 "sort CPUs according to topology"),
1103 OPT_END() 1303 OPT_END()
1104 }; 1304 };
1105 const char * const timechart_usage[] = { 1305 const char * const timechart_usage[] = {
@@ -1107,17 +1307,41 @@ int cmd_timechart(int argc, const char **argv,
1107 NULL 1307 NULL
1108 }; 1308 };
1109 1309
1110 argc = parse_options(argc, argv, options, timechart_usage, 1310 const struct option record_options[] = {
1311 OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
1312 OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
1313 "output processes data only"),
1314 OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
1315 OPT_END()
1316 };
1317 const char * const record_usage[] = {
1318 "perf timechart record [<options>]",
1319 NULL
1320 };
1321 argc = parse_options(argc, argv, timechart_options, timechart_usage,
1111 PARSE_OPT_STOP_AT_NON_OPTION); 1322 PARSE_OPT_STOP_AT_NON_OPTION);
1112 1323
1324 if (tchart.power_only && tchart.tasks_only) {
1325 pr_err("-P and -T options cannot be used at the same time.\n");
1326 return -1;
1327 }
1328
1113 symbol__init(); 1329 symbol__init();
1114 1330
1115 if (argc && !strncmp(argv[0], "rec", 3)) 1331 if (argc && !strncmp(argv[0], "rec", 3)) {
1116 return __cmd_record(argc, argv); 1332 argc = parse_options(argc, argv, record_options, record_usage,
1117 else if (argc) 1333 PARSE_OPT_STOP_AT_NON_OPTION);
1118 usage_with_options(timechart_usage, options); 1334
1335 if (tchart.power_only && tchart.tasks_only) {
1336 pr_err("-P and -T options cannot be used at the same time.\n");
1337 return -1;
1338 }
1339
1340 return timechart__record(&tchart, argc, argv);
1341 } else if (argc)
1342 usage_with_options(timechart_usage, timechart_options);
1119 1343
1120 setup_pager(); 1344 setup_pager();
1121 1345
1122 return __cmd_timechart(output_name); 1346 return __cmd_timechart(&tchart, output_name);
1123} 1347}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 71e6402729a8..76cd510d34d0 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -189,21 +189,18 @@ static void perf_top__record_precise_ip(struct perf_top *top,
189 if (pthread_mutex_trylock(&notes->lock)) 189 if (pthread_mutex_trylock(&notes->lock))
190 return; 190 return;
191 191
192 if (notes->src == NULL && symbol__alloc_hist(sym) < 0) {
193 pthread_mutex_unlock(&notes->lock);
194 pr_err("Not enough memory for annotating '%s' symbol!\n",
195 sym->name);
196 sleep(1);
197 return;
198 }
199
200 ip = he->ms.map->map_ip(he->ms.map, ip); 192 ip = he->ms.map->map_ip(he->ms.map, ip);
201 err = symbol__inc_addr_samples(sym, he->ms.map, counter, ip); 193 err = hist_entry__inc_addr_samples(he, counter, ip);
202 194
203 pthread_mutex_unlock(&notes->lock); 195 pthread_mutex_unlock(&notes->lock);
204 196
205 if (err == -ERANGE && !he->ms.map->erange_warned) 197 if (err == -ERANGE && !he->ms.map->erange_warned)
206 ui__warn_map_erange(he->ms.map, sym, ip); 198 ui__warn_map_erange(he->ms.map, sym, ip);
199 else if (err == -ENOMEM) {
200 pr_err("Not enough memory for annotating '%s' symbol!\n",
201 sym->name);
202 sleep(1);
203 }
207} 204}
208 205
209static void perf_top__show_details(struct perf_top *top) 206static void perf_top__show_details(struct perf_top *top)
@@ -485,7 +482,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
485 482
486 fprintf(stderr, "\nAvailable events:"); 483 fprintf(stderr, "\nAvailable events:");
487 484
488 list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) 485 evlist__for_each(top->evlist, top->sym_evsel)
489 fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel)); 486 fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel));
490 487
491 prompt_integer(&counter, "Enter details event counter"); 488 prompt_integer(&counter, "Enter details event counter");
@@ -496,7 +493,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
496 sleep(1); 493 sleep(1);
497 break; 494 break;
498 } 495 }
499 list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) 496 evlist__for_each(top->evlist, top->sym_evsel)
500 if (top->sym_evsel->idx == counter) 497 if (top->sym_evsel->idx == counter)
501 break; 498 break;
502 } else 499 } else
@@ -578,7 +575,7 @@ static void *display_thread_tui(void *arg)
578 * Zooming in/out UIDs. For now juse use whatever the user passed 575 * Zooming in/out UIDs. For now juse use whatever the user passed
579 * via --uid. 576 * via --uid.
580 */ 577 */
581 list_for_each_entry(pos, &top->evlist->entries, node) 578 evlist__for_each(top->evlist, pos)
582 pos->hists.uid_filter_str = top->record_opts.target.uid_str; 579 pos->hists.uid_filter_str = top->record_opts.target.uid_str;
583 580
584 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, 581 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
@@ -634,26 +631,9 @@ repeat:
634 return NULL; 631 return NULL;
635} 632}
636 633
637/* Tag samples to be skipped. */
638static const char *skip_symbols[] = {
639 "intel_idle",
640 "default_idle",
641 "native_safe_halt",
642 "cpu_idle",
643 "enter_idle",
644 "exit_idle",
645 "mwait_idle",
646 "mwait_idle_with_hints",
647 "poll_idle",
648 "ppc64_runlatch_off",
649 "pseries_dedicated_idle_sleep",
650 NULL
651};
652
653static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) 634static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
654{ 635{
655 const char *name = sym->name; 636 const char *name = sym->name;
656 int i;
657 637
658 /* 638 /*
659 * ppc64 uses function descriptors and appends a '.' to the 639 * ppc64 uses function descriptors and appends a '.' to the
@@ -671,12 +651,8 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
671 strstr(name, "_text_end")) 651 strstr(name, "_text_end"))
672 return 1; 652 return 1;
673 653
674 for (i = 0; skip_symbols[i]; i++) { 654 if (symbol__is_idle(sym))
675 if (!strcmp(skip_symbols[i], name)) { 655 sym->ignore = true;
676 sym->ignore = true;
677 break;
678 }
679 }
680 656
681 return 0; 657 return 0;
682} 658}
@@ -767,15 +743,10 @@ static void perf_event__process_sample(struct perf_tool *tool,
767 if (al.sym == NULL || !al.sym->ignore) { 743 if (al.sym == NULL || !al.sym->ignore) {
768 struct hist_entry *he; 744 struct hist_entry *he;
769 745
770 if ((sort__has_parent || symbol_conf.use_callchain) && 746 err = sample__resolve_callchain(sample, &parent, evsel, &al,
771 sample->callchain) { 747 top->max_stack);
772 err = machine__resolve_callchain(machine, evsel, 748 if (err)
773 al.thread, sample, 749 return;
774 &parent, &al,
775 top->max_stack);
776 if (err)
777 return;
778 }
779 750
780 he = perf_evsel__add_hist_entry(evsel, &al, sample); 751 he = perf_evsel__add_hist_entry(evsel, &al, sample);
781 if (he == NULL) { 752 if (he == NULL) {
@@ -783,12 +754,9 @@ static void perf_event__process_sample(struct perf_tool *tool,
783 return; 754 return;
784 } 755 }
785 756
786 if (symbol_conf.use_callchain) { 757 err = hist_entry__append_callchain(he, sample);
787 err = callchain_append(he->callchain, &callchain_cursor, 758 if (err)
788 sample->period); 759 return;
789 if (err)
790 return;
791 }
792 760
793 if (sort__has_sym) 761 if (sort__has_sym)
794 perf_top__record_precise_ip(top, he, evsel->idx, ip); 762 perf_top__record_precise_ip(top, he, evsel->idx, ip);
@@ -878,11 +846,11 @@ static int perf_top__start_counters(struct perf_top *top)
878 char msg[512]; 846 char msg[512];
879 struct perf_evsel *counter; 847 struct perf_evsel *counter;
880 struct perf_evlist *evlist = top->evlist; 848 struct perf_evlist *evlist = top->evlist;
881 struct perf_record_opts *opts = &top->record_opts; 849 struct record_opts *opts = &top->record_opts;
882 850
883 perf_evlist__config(evlist, opts); 851 perf_evlist__config(evlist, opts);
884 852
885 list_for_each_entry(counter, &evlist->entries, node) { 853 evlist__for_each(evlist, counter) {
886try_again: 854try_again:
887 if (perf_evsel__open(counter, top->evlist->cpus, 855 if (perf_evsel__open(counter, top->evlist->cpus,
888 top->evlist->threads) < 0) { 856 top->evlist->threads) < 0) {
@@ -930,7 +898,7 @@ static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused)
930 898
931static int __cmd_top(struct perf_top *top) 899static int __cmd_top(struct perf_top *top)
932{ 900{
933 struct perf_record_opts *opts = &top->record_opts; 901 struct record_opts *opts = &top->record_opts;
934 pthread_t thread; 902 pthread_t thread;
935 int ret; 903 int ret;
936 904
@@ -1052,7 +1020,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1052 .max_stack = PERF_MAX_STACK_DEPTH, 1020 .max_stack = PERF_MAX_STACK_DEPTH,
1053 .sym_pcnt_filter = 5, 1021 .sym_pcnt_filter = 5,
1054 }; 1022 };
1055 struct perf_record_opts *opts = &top.record_opts; 1023 struct record_opts *opts = &top.record_opts;
1056 struct target *target = &opts->target; 1024 struct target *target = &opts->target;
1057 const struct option options[] = { 1025 const struct option options[] = {
1058 OPT_CALLBACK('e', "event", &top.evlist, "event", 1026 OPT_CALLBACK('e', "event", &top.evlist, "event",
@@ -1084,7 +1052,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1084 "dump the symbol table used for profiling"), 1052 "dump the symbol table used for profiling"),
1085 OPT_INTEGER('f', "count-filter", &top.count_filter, 1053 OPT_INTEGER('f', "count-filter", &top.count_filter,
1086 "only display functions with more events than this"), 1054 "only display functions with more events than this"),
1087 OPT_BOOLEAN('g', "group", &opts->group, 1055 OPT_BOOLEAN(0, "group", &opts->group,
1088 "put the counters into a counter group"), 1056 "put the counters into a counter group"),
1089 OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit, 1057 OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit,
1090 "child tasks do not inherit counters"), 1058 "child tasks do not inherit counters"),
@@ -1105,7 +1073,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1105 " abort, in_tx, transaction"), 1073 " abort, in_tx, transaction"),
1106 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1074 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1107 "Show a column with the number of samples"), 1075 "Show a column with the number of samples"),
1108 OPT_CALLBACK_NOOPT('G', NULL, &top.record_opts, 1076 OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts,
1109 NULL, "enables call-graph recording", 1077 NULL, "enables call-graph recording",
1110 &callchain_opt), 1078 &callchain_opt),
1111 OPT_CALLBACK(0, "call-graph", &top.record_opts, 1079 OPT_CALLBACK(0, "call-graph", &top.record_opts,
@@ -1195,7 +1163,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1195 if (!top.evlist->nr_entries && 1163 if (!top.evlist->nr_entries &&
1196 perf_evlist__add_default(top.evlist) < 0) { 1164 perf_evlist__add_default(top.evlist) < 0) {
1197 ui__error("Not enough memory for event selector list\n"); 1165 ui__error("Not enough memory for event selector list\n");
1198 goto out_delete_maps; 1166 goto out_delete_evlist;
1199 } 1167 }
1200 1168
1201 symbol_conf.nr_events = top.evlist->nr_entries; 1169 symbol_conf.nr_events = top.evlist->nr_entries;
@@ -1203,9 +1171,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1203 if (top.delay_secs < 1) 1171 if (top.delay_secs < 1)
1204 top.delay_secs = 1; 1172 top.delay_secs = 1;
1205 1173
1206 if (perf_record_opts__config(opts)) { 1174 if (record_opts__config(opts)) {
1207 status = -EINVAL; 1175 status = -EINVAL;
1208 goto out_delete_maps; 1176 goto out_delete_evlist;
1209 } 1177 }
1210 1178
1211 top.sym_evsel = perf_evlist__first(top.evlist); 1179 top.sym_evsel = perf_evlist__first(top.evlist);
@@ -1230,8 +1198,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1230 1198
1231 status = __cmd_top(&top); 1199 status = __cmd_top(&top);
1232 1200
1233out_delete_maps:
1234 perf_evlist__delete_maps(top.evlist);
1235out_delete_evlist: 1201out_delete_evlist:
1236 perf_evlist__delete(top.evlist); 1202 perf_evlist__delete(top.evlist);
1237 1203
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 8be17fc462ba..896f27047ed6 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -11,6 +11,8 @@
11#include "util/intlist.h" 11#include "util/intlist.h"
12#include "util/thread_map.h" 12#include "util/thread_map.h"
13#include "util/stat.h" 13#include "util/stat.h"
14#include "trace-event.h"
15#include "util/parse-events.h"
14 16
15#include <libaudit.h> 17#include <libaudit.h>
16#include <stdlib.h> 18#include <stdlib.h>
@@ -144,8 +146,7 @@ static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
144 146
145static void perf_evsel__delete_priv(struct perf_evsel *evsel) 147static void perf_evsel__delete_priv(struct perf_evsel *evsel)
146{ 148{
147 free(evsel->priv); 149 zfree(&evsel->priv);
148 evsel->priv = NULL;
149 perf_evsel__delete(evsel); 150 perf_evsel__delete(evsel);
150} 151}
151 152
@@ -163,8 +164,7 @@ static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
163 return -ENOMEM; 164 return -ENOMEM;
164 165
165out_delete: 166out_delete:
166 free(evsel->priv); 167 zfree(&evsel->priv);
167 evsel->priv = NULL;
168 return -ENOENT; 168 return -ENOENT;
169} 169}
170 170
@@ -172,6 +172,10 @@ static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void
172{ 172{
173 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); 173 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
174 174
175 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
176 if (evsel == NULL)
177 evsel = perf_evsel__newtp("syscalls", direction);
178
175 if (evsel) { 179 if (evsel) {
176 if (perf_evsel__init_syscall_tp(evsel, handler)) 180 if (perf_evsel__init_syscall_tp(evsel, handler))
177 goto out_delete; 181 goto out_delete;
@@ -1153,29 +1157,30 @@ struct trace {
1153 int max; 1157 int max;
1154 struct syscall *table; 1158 struct syscall *table;
1155 } syscalls; 1159 } syscalls;
1156 struct perf_record_opts opts; 1160 struct record_opts opts;
1157 struct machine *host; 1161 struct machine *host;
1158 u64 base_time; 1162 u64 base_time;
1159 bool full_time;
1160 FILE *output; 1163 FILE *output;
1161 unsigned long nr_events; 1164 unsigned long nr_events;
1162 struct strlist *ev_qualifier; 1165 struct strlist *ev_qualifier;
1163 bool not_ev_qualifier;
1164 bool live;
1165 const char *last_vfs_getname; 1166 const char *last_vfs_getname;
1166 struct intlist *tid_list; 1167 struct intlist *tid_list;
1167 struct intlist *pid_list; 1168 struct intlist *pid_list;
1169 double duration_filter;
1170 double runtime_ms;
1171 struct {
1172 u64 vfs_getname,
1173 proc_getname;
1174 } stats;
1175 bool not_ev_qualifier;
1176 bool live;
1177 bool full_time;
1168 bool sched; 1178 bool sched;
1169 bool multiple_threads; 1179 bool multiple_threads;
1170 bool summary; 1180 bool summary;
1171 bool summary_only; 1181 bool summary_only;
1172 bool show_comm; 1182 bool show_comm;
1173 bool show_tool_stats; 1183 bool show_tool_stats;
1174 double duration_filter;
1175 double runtime_ms;
1176 struct {
1177 u64 vfs_getname, proc_getname;
1178 } stats;
1179}; 1184};
1180 1185
1181static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) 1186static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
@@ -1272,10 +1277,8 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1272 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg); 1277 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1273 struct thread_trace *ttrace = arg->thread->priv; 1278 struct thread_trace *ttrace = arg->thread->priv;
1274 1279
1275 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) { 1280 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1276 free(ttrace->paths.table[fd]); 1281 zfree(&ttrace->paths.table[fd]);
1277 ttrace->paths.table[fd] = NULL;
1278 }
1279 1282
1280 return printed; 1283 return printed;
1281} 1284}
@@ -1430,11 +1433,11 @@ static int trace__read_syscall_info(struct trace *trace, int id)
1430 sc->fmt = syscall_fmt__find(sc->name); 1433 sc->fmt = syscall_fmt__find(sc->name);
1431 1434
1432 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); 1435 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1433 sc->tp_format = event_format__new("syscalls", tp_name); 1436 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
1434 1437
1435 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { 1438 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1436 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); 1439 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1437 sc->tp_format = event_format__new("syscalls", tp_name); 1440 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
1438 } 1441 }
1439 1442
1440 if (sc->tp_format == NULL) 1443 if (sc->tp_format == NULL)
@@ -1764,8 +1767,10 @@ static int trace__process_sample(struct perf_tool *tool,
1764 if (!trace->full_time && trace->base_time == 0) 1767 if (!trace->full_time && trace->base_time == 0)
1765 trace->base_time = sample->time; 1768 trace->base_time = sample->time;
1766 1769
1767 if (handler) 1770 if (handler) {
1771 ++trace->nr_events;
1768 handler(trace, evsel, sample); 1772 handler(trace, evsel, sample);
1773 }
1769 1774
1770 return err; 1775 return err;
1771} 1776}
@@ -1800,10 +1805,11 @@ static int trace__record(int argc, const char **argv)
1800 "-R", 1805 "-R",
1801 "-m", "1024", 1806 "-m", "1024",
1802 "-c", "1", 1807 "-c", "1",
1803 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit", 1808 "-e",
1804 }; 1809 };
1805 1810
1806 rec_argc = ARRAY_SIZE(record_args) + argc; 1811 /* +1 is for the event string below */
1812 rec_argc = ARRAY_SIZE(record_args) + 1 + argc;
1807 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1813 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1808 1814
1809 if (rec_argv == NULL) 1815 if (rec_argv == NULL)
@@ -1812,6 +1818,17 @@ static int trace__record(int argc, const char **argv)
1812 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1818 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1813 rec_argv[i] = record_args[i]; 1819 rec_argv[i] = record_args[i];
1814 1820
1821 /* event string may be different for older kernels - e.g., RHEL6 */
1822 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1823 rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
1824 else if (is_valid_tracepoint("syscalls:sys_enter"))
1825 rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit";
1826 else {
1827 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
1828 return -1;
1829 }
1830 i++;
1831
1815 for (j = 0; j < (unsigned int)argc; j++, i++) 1832 for (j = 0; j < (unsigned int)argc; j++, i++)
1816 rec_argv[i] = argv[j]; 1833 rec_argv[i] = argv[j];
1817 1834
@@ -1869,7 +1886,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1869 err = trace__symbols_init(trace, evlist); 1886 err = trace__symbols_init(trace, evlist);
1870 if (err < 0) { 1887 if (err < 0) {
1871 fprintf(trace->output, "Problems initializing symbol libraries!\n"); 1888 fprintf(trace->output, "Problems initializing symbol libraries!\n");
1872 goto out_delete_maps; 1889 goto out_delete_evlist;
1873 } 1890 }
1874 1891
1875 perf_evlist__config(evlist, &trace->opts); 1892 perf_evlist__config(evlist, &trace->opts);
@@ -1879,10 +1896,10 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1879 1896
1880 if (forks) { 1897 if (forks) {
1881 err = perf_evlist__prepare_workload(evlist, &trace->opts.target, 1898 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
1882 argv, false, false); 1899 argv, false, NULL);
1883 if (err < 0) { 1900 if (err < 0) {
1884 fprintf(trace->output, "Couldn't run the workload!\n"); 1901 fprintf(trace->output, "Couldn't run the workload!\n");
1885 goto out_delete_maps; 1902 goto out_delete_evlist;
1886 } 1903 }
1887 } 1904 }
1888 1905
@@ -1890,10 +1907,10 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
1890 if (err < 0) 1907 if (err < 0)
1891 goto out_error_open; 1908 goto out_error_open;
1892 1909
1893 err = perf_evlist__mmap(evlist, UINT_MAX, false); 1910 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
1894 if (err < 0) { 1911 if (err < 0) {
1895 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); 1912 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
1896 goto out_close_evlist; 1913 goto out_delete_evlist;
1897 } 1914 }
1898 1915
1899 perf_evlist__enable(evlist); 1916 perf_evlist__enable(evlist);
@@ -1977,11 +1994,6 @@ out_disable:
1977 } 1994 }
1978 } 1995 }
1979 1996
1980 perf_evlist__munmap(evlist);
1981out_close_evlist:
1982 perf_evlist__close(evlist);
1983out_delete_maps:
1984 perf_evlist__delete_maps(evlist);
1985out_delete_evlist: 1997out_delete_evlist:
1986 perf_evlist__delete(evlist); 1998 perf_evlist__delete(evlist);
1987out: 1999out:
@@ -2047,6 +2059,10 @@ static int trace__replay(struct trace *trace)
2047 2059
2048 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2060 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2049 "raw_syscalls:sys_enter"); 2061 "raw_syscalls:sys_enter");
2062 /* older kernels have syscalls tp versus raw_syscalls */
2063 if (evsel == NULL)
2064 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2065 "syscalls:sys_enter");
2050 if (evsel == NULL) { 2066 if (evsel == NULL) {
2051 pr_err("Data file does not have raw_syscalls:sys_enter event\n"); 2067 pr_err("Data file does not have raw_syscalls:sys_enter event\n");
2052 goto out; 2068 goto out;
@@ -2060,6 +2076,9 @@ static int trace__replay(struct trace *trace)
2060 2076
2061 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, 2077 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2062 "raw_syscalls:sys_exit"); 2078 "raw_syscalls:sys_exit");
2079 if (evsel == NULL)
2080 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2081 "syscalls:sys_exit");
2063 if (evsel == NULL) { 2082 if (evsel == NULL) {
2064 pr_err("Data file does not have raw_syscalls:sys_exit event\n"); 2083 pr_err("Data file does not have raw_syscalls:sys_exit event\n");
2065 goto out; 2084 goto out;
@@ -2158,7 +2177,6 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2158 size_t printed = data->printed; 2177 size_t printed = data->printed;
2159 struct trace *trace = data->trace; 2178 struct trace *trace = data->trace;
2160 struct thread_trace *ttrace = thread->priv; 2179 struct thread_trace *ttrace = thread->priv;
2161 const char *color;
2162 double ratio; 2180 double ratio;
2163 2181
2164 if (ttrace == NULL) 2182 if (ttrace == NULL)
@@ -2166,17 +2184,9 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2166 2184
2167 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0; 2185 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2168 2186
2169 color = PERF_COLOR_NORMAL; 2187 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
2170 if (ratio > 50.0)
2171 color = PERF_COLOR_RED;
2172 else if (ratio > 25.0)
2173 color = PERF_COLOR_GREEN;
2174 else if (ratio > 5.0)
2175 color = PERF_COLOR_YELLOW;
2176
2177 printed += color_fprintf(fp, color, " %s (%d), ", thread__comm_str(thread), thread->tid);
2178 printed += fprintf(fp, "%lu events, ", ttrace->nr_events); 2188 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
2179 printed += color_fprintf(fp, color, "%.1f%%", ratio); 2189 printed += fprintf(fp, "%.1f%%", ratio);
2180 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); 2190 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2181 printed += thread__dump_stats(ttrace, trace, fp); 2191 printed += thread__dump_stats(ttrace, trace, fp);
2182 2192
@@ -2248,7 +2258,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2248 }, 2258 },
2249 .user_freq = UINT_MAX, 2259 .user_freq = UINT_MAX,
2250 .user_interval = ULLONG_MAX, 2260 .user_interval = ULLONG_MAX,
2251 .no_delay = true, 2261 .no_buffering = true,
2252 .mmap_pages = 1024, 2262 .mmap_pages = 1024,
2253 }, 2263 },
2254 .output = stdout, 2264 .output = stdout,
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index f7d11a811c74..d604e50fc167 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -1,28 +1,26 @@
1uname_M := $(shell uname -m 2>/dev/null || echo not)
2 1
3ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ 2ifeq ($(src-perf),)
4 -e s/arm.*/arm/ -e s/sa110/arm/ \ 3src-perf := $(srctree)/tools/perf
5 -e s/s390x/s390/ -e s/parisc64/parisc/ \ 4endif
6 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
7 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
8NO_PERF_REGS := 1
9CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
10 5
11# Additional ARCH settings for x86 6ifeq ($(obj-perf),)
12ifeq ($(ARCH),i386) 7obj-perf := $(OUTPUT)
13 override ARCH := x86
14 NO_PERF_REGS := 0
15 LIBUNWIND_LIBS = -lunwind -lunwind-x86
16endif 8endif
17 9
18ifeq ($(ARCH),x86_64) 10ifneq ($(obj-perf),)
19 override ARCH := x86 11obj-perf := $(abspath $(obj-perf))/
20 IS_X86_64 := 0 12endif
21 ifeq (, $(findstring m32,$(CFLAGS))) 13
22 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1) 14LIB_INCLUDE := $(srctree)/tools/lib/
23 endif 15CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
16
17include $(src-perf)/config/Makefile.arch
18
19NO_PERF_REGS := 1
20
21# Additional ARCH settings for x86
22ifeq ($(ARCH),x86)
24 ifeq (${IS_X86_64}, 1) 23 ifeq (${IS_X86_64}, 1)
25 RAW_ARCH := x86_64
26 CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT 24 CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT
27 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S 25 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
28 LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 26 LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
@@ -36,24 +34,31 @@ ifeq ($(ARCH),arm)
36 LIBUNWIND_LIBS = -lunwind -lunwind-arm 34 LIBUNWIND_LIBS = -lunwind -lunwind-arm
37endif 35endif
38 36
39ifeq ($(NO_PERF_REGS),0) 37ifeq ($(LIBUNWIND_LIBS),)
40 CFLAGS += -DHAVE_PERF_REGS_SUPPORT 38 NO_LIBUNWIND := 1
41endif 39else
42 40 #
43ifeq ($(src-perf),) 41 # For linking with debug library, run like:
44src-perf := $(srctree)/tools/perf 42 #
45endif 43 # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
44 #
45 ifdef LIBUNWIND_DIR
46 LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
47 LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
48 endif
49 LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS)
46 50
47ifeq ($(obj-perf),) 51 # Set per-feature check compilation flags
48obj-perf := $(OUTPUT) 52 FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
53 FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS)
54 FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
55 FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS)
49endif 56endif
50 57
51ifneq ($(obj-perf),) 58ifeq ($(NO_PERF_REGS),0)
52obj-perf := $(abspath $(obj-perf))/ 59 CFLAGS += -DHAVE_PERF_REGS_SUPPORT
53endif 60endif
54 61
55LIB_INCLUDE := $(srctree)/tools/lib/
56
57# include ARCH specific config 62# include ARCH specific config
58-include $(src-perf)/arch/$(ARCH)/Makefile 63-include $(src-perf)/arch/$(ARCH)/Makefile
59 64
@@ -102,7 +107,7 @@ endif
102 107
103feature_check = $(eval $(feature_check_code)) 108feature_check = $(eval $(feature_check_code))
104define feature_check_code 109define feature_check_code
105 feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBUNWIND_LIBS="$(LIBUNWIND_LIBS)" -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0) 110 feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C config/feature-checks test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
106endef 111endef
107 112
108feature_set = $(eval $(feature_set_code)) 113feature_set = $(eval $(feature_set_code))
@@ -141,16 +146,26 @@ CORE_FEATURE_TESTS = \
141 libslang \ 146 libslang \
142 libunwind \ 147 libunwind \
143 on-exit \ 148 on-exit \
144 stackprotector \
145 stackprotector-all \ 149 stackprotector-all \
146 timerfd 150 timerfd
147 151
152# Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
153# If in the future we need per-feature checks/flags for features not
154# mentioned in this list we need to refactor this ;-).
155set_test_all_flags = $(eval $(set_test_all_flags_code))
156define set_test_all_flags_code
157 FEATURE_CHECK_CFLAGS-all += $(FEATURE_CHECK_CFLAGS-$(1))
158 FEATURE_CHECK_LDFLAGS-all += $(FEATURE_CHECK_LDFLAGS-$(1))
159endef
160
161$(foreach feat,$(CORE_FEATURE_TESTS),$(call set_test_all_flags,$(feat)))
162
148# 163#
149# So here we detect whether test-all was rebuilt, to be able 164# So here we detect whether test-all was rebuilt, to be able
150# to skip the print-out of the long features list if the file 165# to skip the print-out of the long features list if the file
151# existed before and after it was built: 166# existed before and after it was built:
152# 167#
153ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all),) 168ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all.bin),)
154 test-all-failed := 1 169 test-all-failed := 1
155else 170else
156 test-all-failed := 0 171 test-all-failed := 0
@@ -180,7 +195,7 @@ ifeq ($(feature-all), 1)
180 # 195 #
181 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat))) 196 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat)))
182else 197else
183 $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(CORE_FEATURE_TESTS) >/dev/null 2>&1) 198 $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(addsuffix .bin,$(CORE_FEATURE_TESTS)) >/dev/null 2>&1)
184 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat))) 199 $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat)))
185endif 200endif
186 201
@@ -209,10 +224,6 @@ ifeq ($(feature-stackprotector-all), 1)
209 CFLAGS += -fstack-protector-all 224 CFLAGS += -fstack-protector-all
210endif 225endif
211 226
212ifeq ($(feature-stackprotector), 1)
213 CFLAGS += -Wstack-protector
214endif
215
216ifeq ($(DEBUG),0) 227ifeq ($(DEBUG),0)
217 ifeq ($(feature-fortify-source), 1) 228 ifeq ($(feature-fortify-source), 1)
218 CFLAGS += -D_FORTIFY_SOURCE=2 229 CFLAGS += -D_FORTIFY_SOURCE=2
@@ -221,6 +232,7 @@ endif
221 232
222CFLAGS += -I$(src-perf)/util/include 233CFLAGS += -I$(src-perf)/util/include
223CFLAGS += -I$(src-perf)/arch/$(ARCH)/include 234CFLAGS += -I$(src-perf)/arch/$(ARCH)/include
235CFLAGS += -I$(srctree)/tools/include/
224CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi 236CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi
225CFLAGS += -I$(srctree)/arch/$(ARCH)/include 237CFLAGS += -I$(srctree)/arch/$(ARCH)/include
226CFLAGS += -I$(srctree)/include/uapi 238CFLAGS += -I$(srctree)/include/uapi
@@ -310,21 +322,7 @@ ifndef NO_LIBELF
310 endif # NO_DWARF 322 endif # NO_DWARF
311endif # NO_LIBELF 323endif # NO_LIBELF
312 324
313ifeq ($(LIBUNWIND_LIBS),)
314 NO_LIBUNWIND := 1
315endif
316
317ifndef NO_LIBUNWIND 325ifndef NO_LIBUNWIND
318 #
319 # For linking with debug library, run like:
320 #
321 # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
322 #
323 ifdef LIBUNWIND_DIR
324 LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include
325 LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib
326 endif
327
328 ifneq ($(feature-libunwind), 1) 326 ifneq ($(feature-libunwind), 1)
329 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1); 327 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1);
330 NO_LIBUNWIND := 1 328 NO_LIBUNWIND := 1
@@ -339,14 +337,12 @@ ifndef NO_LIBUNWIND
339 # non-ARM has no dwarf_find_debug_frame() function: 337 # non-ARM has no dwarf_find_debug_frame() function:
340 CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME 338 CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
341 endif 339 endif
342 endif
343endif
344 340
345ifndef NO_LIBUNWIND 341 CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
346 CFLAGS += -DHAVE_LIBUNWIND_SUPPORT 342 EXTLIBS += $(LIBUNWIND_LIBS)
347 EXTLIBS += $(LIBUNWIND_LIBS) 343 CFLAGS += $(LIBUNWIND_CFLAGS)
348 CFLAGS += $(LIBUNWIND_CFLAGS) 344 LDFLAGS += $(LIBUNWIND_LDFLAGS)
349 LDFLAGS += $(LIBUNWIND_LDFLAGS) 345 endif # ifneq ($(feature-libunwind), 1)
350endif 346endif
351 347
352ifndef NO_LIBAUDIT 348ifndef NO_LIBAUDIT
@@ -376,7 +372,7 @@ ifndef NO_SLANG
376endif 372endif
377 373
378ifndef NO_GTK2 374ifndef NO_GTK2
379 FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) 375 FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
380 ifneq ($(feature-gtk2), 1) 376 ifneq ($(feature-gtk2), 1)
381 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); 377 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
382 NO_GTK2 := 1 378 NO_GTK2 := 1
@@ -385,8 +381,8 @@ ifndef NO_GTK2
385 GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT 381 GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT
386 endif 382 endif
387 CFLAGS += -DHAVE_GTK2_SUPPORT 383 CFLAGS += -DHAVE_GTK2_SUPPORT
388 GTK_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) 384 GTK_CFLAGS += $(shell $(PKG_CONFIG) --cflags gtk+-2.0 2>/dev/null)
389 GTK_LIBS := $(shell pkg-config --libs gtk+-2.0 2>/dev/null) 385 GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk+-2.0 2>/dev/null)
390 EXTLIBS += -ldl 386 EXTLIBS += -ldl
391 endif 387 endif
392endif 388endif
@@ -533,7 +529,7 @@ endif
533 529
534ifndef NO_LIBNUMA 530ifndef NO_LIBNUMA
535 ifeq ($(feature-libnuma), 0) 531 ifeq ($(feature-libnuma), 0)
536 msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev); 532 msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numactl-devel/libnuma-devel/libnuma-dev);
537 NO_LIBNUMA := 1 533 NO_LIBNUMA := 1
538 else 534 else
539 CFLAGS += -DHAVE_LIBNUMA_SUPPORT 535 CFLAGS += -DHAVE_LIBNUMA_SUPPORT
@@ -598,3 +594,11 @@ else
598perfexec_instdir = $(prefix)/$(perfexecdir) 594perfexec_instdir = $(prefix)/$(perfexecdir)
599endif 595endif
600perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 596perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
597
598# If we install to $(HOME) we keep the traceevent default:
599# $(HOME)/.traceevent/plugins
600# Otherwise we install plugins into the global $(libdir).
601ifdef DESTDIR
602plugindir=$(libdir)/traceevent/plugins
603plugindir_SQ= $(subst ','\'',$(prefix)/$(plugindir))
604endif
diff --git a/tools/perf/config/Makefile.arch b/tools/perf/config/Makefile.arch
new file mode 100644
index 000000000000..fef8ae922800
--- /dev/null
+++ b/tools/perf/config/Makefile.arch
@@ -0,0 +1,22 @@
1
2uname_M := $(shell uname -m 2>/dev/null || echo not)
3
4ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
5 -e s/arm.*/arm/ -e s/sa110/arm/ \
6 -e s/s390x/s390/ -e s/parisc64/parisc/ \
7 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
8 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
9
10# Additional ARCH settings for x86
11ifeq ($(ARCH),i386)
12 override ARCH := x86
13endif
14
15ifeq ($(ARCH),x86_64)
16 override ARCH := x86
17 IS_X86_64 := 0
18 ifeq (, $(findstring m32,$(CFLAGS)))
19 IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1)
20 RAW_ARCH := x86_64
21 endif
22endif
diff --git a/tools/perf/config/feature-checks/.gitignore b/tools/perf/config/feature-checks/.gitignore
new file mode 100644
index 000000000000..80f3da0c3515
--- /dev/null
+++ b/tools/perf/config/feature-checks/.gitignore
@@ -0,0 +1,2 @@
1*.d
2*.bin
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 87e790017c69..12e551346fa6 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -1,95 +1,92 @@
1 1
2FILES= \ 2FILES= \
3 test-all \ 3 test-all.bin \
4 test-backtrace \ 4 test-backtrace.bin \
5 test-bionic \ 5 test-bionic.bin \
6 test-dwarf \ 6 test-dwarf.bin \
7 test-fortify-source \ 7 test-fortify-source.bin \
8 test-glibc \ 8 test-glibc.bin \
9 test-gtk2 \ 9 test-gtk2.bin \
10 test-gtk2-infobar \ 10 test-gtk2-infobar.bin \
11 test-hello \ 11 test-hello.bin \
12 test-libaudit \ 12 test-libaudit.bin \
13 test-libbfd \ 13 test-libbfd.bin \
14 test-liberty \ 14 test-liberty.bin \
15 test-liberty-z \ 15 test-liberty-z.bin \
16 test-cplus-demangle \ 16 test-cplus-demangle.bin \
17 test-libelf \ 17 test-libelf.bin \
18 test-libelf-getphdrnum \ 18 test-libelf-getphdrnum.bin \
19 test-libelf-mmap \ 19 test-libelf-mmap.bin \
20 test-libnuma \ 20 test-libnuma.bin \
21 test-libperl \ 21 test-libperl.bin \
22 test-libpython \ 22 test-libpython.bin \
23 test-libpython-version \ 23 test-libpython-version.bin \
24 test-libslang \ 24 test-libslang.bin \
25 test-libunwind \ 25 test-libunwind.bin \
26 test-libunwind-debug-frame \ 26 test-libunwind-debug-frame.bin \
27 test-on-exit \ 27 test-on-exit.bin \
28 test-stackprotector-all \ 28 test-stackprotector-all.bin \
29 test-stackprotector \ 29 test-timerfd.bin
30 test-timerfd 30
31 31CC := $(CROSS_COMPILE)gcc -MD
32CC := $(CC) -MD 32PKG_CONFIG := $(CROSS_COMPILE)pkg-config
33 33
34all: $(FILES) 34all: $(FILES)
35 35
36BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c 36BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS)
37 37
38############################### 38###############################
39 39
40test-all: 40test-all.bin:
41 $(BUILD) -Werror -fstack-protector -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl 41 $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
42 42
43test-hello: 43test-hello.bin:
44 $(BUILD) 44 $(BUILD)
45 45
46test-stackprotector-all: 46test-stackprotector-all.bin:
47 $(BUILD) -Werror -fstack-protector-all 47 $(BUILD) -Werror -fstack-protector-all
48 48
49test-stackprotector: 49test-fortify-source.bin:
50 $(BUILD) -Werror -fstack-protector -Wstack-protector
51
52test-fortify-source:
53 $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2 50 $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2
54 51
55test-bionic: 52test-bionic.bin:
56 $(BUILD) 53 $(BUILD)
57 54
58test-libelf: 55test-libelf.bin:
59 $(BUILD) -lelf 56 $(BUILD) -lelf
60 57
61test-glibc: 58test-glibc.bin:
62 $(BUILD) 59 $(BUILD)
63 60
64test-dwarf: 61test-dwarf.bin:
65 $(BUILD) -ldw 62 $(BUILD) -ldw
66 63
67test-libelf-mmap: 64test-libelf-mmap.bin:
68 $(BUILD) -lelf 65 $(BUILD) -lelf
69 66
70test-libelf-getphdrnum: 67test-libelf-getphdrnum.bin:
71 $(BUILD) -lelf 68 $(BUILD) -lelf
72 69
73test-libnuma: 70test-libnuma.bin:
74 $(BUILD) -lnuma 71 $(BUILD) -lnuma
75 72
76test-libunwind: 73test-libunwind.bin:
77 $(BUILD) $(LIBUNWIND_LIBS) -lelf 74 $(BUILD) -lelf
78 75
79test-libunwind-debug-frame: 76test-libunwind-debug-frame.bin:
80 $(BUILD) $(LIBUNWIND_LIBS) -lelf 77 $(BUILD) -lelf
81 78
82test-libaudit: 79test-libaudit.bin:
83 $(BUILD) -laudit 80 $(BUILD) -laudit
84 81
85test-libslang: 82test-libslang.bin:
86 $(BUILD) -I/usr/include/slang -lslang 83 $(BUILD) -I/usr/include/slang -lslang
87 84
88test-gtk2: 85test-gtk2.bin:
89 $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) 86 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
90 87
91test-gtk2-infobar: 88test-gtk2-infobar.bin:
92 $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) 89 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
93 90
94grep-libs = $(filter -l%,$(1)) 91grep-libs = $(filter -l%,$(1))
95strip-libs = $(filter-out -l%,$(1)) 92strip-libs = $(filter-out -l%,$(1))
@@ -100,7 +97,7 @@ PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
100PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 97PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
101FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) 98FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
102 99
103test-libperl: 100test-libperl.bin:
104 $(BUILD) $(FLAGS_PERL_EMBED) 101 $(BUILD) $(FLAGS_PERL_EMBED)
105 102
106override PYTHON := python 103override PYTHON := python
@@ -117,31 +114,31 @@ PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
117PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) 114PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
118FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 115FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
119 116
120test-libpython: 117test-libpython.bin:
121 $(BUILD) $(FLAGS_PYTHON_EMBED) 118 $(BUILD) $(FLAGS_PYTHON_EMBED)
122 119
123test-libpython-version: 120test-libpython-version.bin:
124 $(BUILD) $(FLAGS_PYTHON_EMBED) 121 $(BUILD) $(FLAGS_PYTHON_EMBED)
125 122
126test-libbfd: 123test-libbfd.bin:
127 $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl 124 $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
128 125
129test-liberty: 126test-liberty.bin:
130 $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty 127 $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty
131 128
132test-liberty-z: 129test-liberty-z.bin:
133 $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz 130 $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz
134 131
135test-cplus-demangle: 132test-cplus-demangle.bin:
136 $(BUILD) -liberty 133 $(BUILD) -liberty
137 134
138test-on-exit: 135test-on-exit.bin:
139 $(BUILD) 136 $(BUILD)
140 137
141test-backtrace: 138test-backtrace.bin:
142 $(BUILD) 139 $(BUILD)
143 140
144test-timerfd: 141test-timerfd.bin:
145 $(BUILD) 142 $(BUILD)
146 143
147-include *.d 144-include *.d
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index 59e7a705e146..9b8a544155bb 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -85,6 +85,10 @@
85# include "test-timerfd.c" 85# include "test-timerfd.c"
86#undef main 86#undef main
87 87
88#define main main_test_stackprotector_all
89# include "test-stackprotector-all.c"
90#undef main
91
88int main(int argc, char *argv[]) 92int main(int argc, char *argv[])
89{ 93{
90 main_test_libpython(); 94 main_test_libpython();
@@ -106,6 +110,7 @@ int main(int argc, char *argv[])
106 main_test_backtrace(); 110 main_test_backtrace();
107 main_test_libnuma(); 111 main_test_libnuma();
108 main_test_timerfd(); 112 main_test_timerfd();
113 main_test_stackprotector_all();
109 114
110 return 0; 115 return 0;
111} 116}
diff --git a/tools/perf/config/feature-checks/test-stackprotector.c b/tools/perf/config/feature-checks/test-stackprotector.c
deleted file mode 100644
index c9f398d87868..000000000000
--- a/tools/perf/config/feature-checks/test-stackprotector.c
+++ /dev/null
@@ -1,6 +0,0 @@
1#include <stdio.h>
2
3int main(void)
4{
5 return puts("hi");
6}
diff --git a/tools/perf/config/feature-checks/test-volatile-register-var.c b/tools/perf/config/feature-checks/test-volatile-register-var.c
deleted file mode 100644
index c9f398d87868..000000000000
--- a/tools/perf/config/feature-checks/test-volatile-register-var.c
+++ /dev/null
@@ -1,6 +0,0 @@
1#include <stdio.h>
2
3int main(void)
4{
5 return puts("hi");
6}
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
index f168debc5be2..4d985e0f03f5 100644
--- a/tools/perf/config/utilities.mak
+++ b/tools/perf/config/utilities.mak
@@ -178,10 +178,3 @@ endef
178_ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2))) 178_ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2)))
179_gea_warn = $(warning The path '$(1)' is not executable.) 179_gea_warn = $(warning The path '$(1)' is not executable.)
180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) 180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
181
182ifneq ($(findstring $(MAKEFLAGS),s),s)
183 ifneq ($(V),1)
184 QUIET_CLEAN = @printf ' CLEAN %s\n' $1;
185 QUIET_INSTALL = @printf ' INSTALL %s\n' $1;
186 endif
187endif
diff --git a/tools/perf/bash_completion b/tools/perf/perf-completion.sh
index 62e157db2e2b..496e2abb5482 100644
--- a/tools/perf/bash_completion
+++ b/tools/perf/perf-completion.sh
@@ -1,4 +1,4 @@
1# perf completion 1# perf bash and zsh completion
2 2
3# Taken from git.git's completion script. 3# Taken from git.git's completion script.
4__my_reassemble_comp_words_by_ref() 4__my_reassemble_comp_words_by_ref()
@@ -89,37 +89,117 @@ __ltrim_colon_completions()
89 fi 89 fi
90} 90}
91 91
92type perf &>/dev/null && 92__perfcomp ()
93_perf()
94{ 93{
95 local cur words cword prev cmd 94 COMPREPLY=( $( compgen -W "$1" -- "$2" ) )
95}
96 96
97 COMPREPLY=() 97__perfcomp_colon ()
98 _get_comp_words_by_ref -n =: cur words cword prev 98{
99 __perfcomp "$1" "$2"
100 __ltrim_colon_completions $cur
101}
102
103__perf_main ()
104{
105 local cmd
99 106
100 cmd=${words[0]} 107 cmd=${words[0]}
108 COMPREPLY=()
101 109
102 # List perf subcommands or long options 110 # List perf subcommands or long options
103 if [ $cword -eq 1 ]; then 111 if [ $cword -eq 1 ]; then
104 if [[ $cur == --* ]]; then 112 if [[ $cur == --* ]]; then
105 COMPREPLY=( $( compgen -W '--help --version \ 113 __perfcomp '--help --version \
106 --exec-path --html-path --paginate --no-pager \ 114 --exec-path --html-path --paginate --no-pager \
107 --perf-dir --work-tree --debugfs-dir' -- "$cur" ) ) 115 --perf-dir --work-tree --debugfs-dir' -- "$cur"
108 else 116 else
109 cmds=$($cmd --list-cmds) 117 cmds=$($cmd --list-cmds)
110 COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) 118 __perfcomp "$cmds" "$cur"
111 fi 119 fi
112 # List possible events for -e option 120 # List possible events for -e option
113 elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then 121 elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then
114 evts=$($cmd list --raw-dump) 122 evts=$($cmd list --raw-dump)
115 COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) ) 123 __perfcomp_colon "$evts" "$cur"
116 __ltrim_colon_completions $cur 124 # List subcommands for 'perf kvm'
125 elif [[ $prev == "kvm" ]]; then
126 subcmds="top record report diff buildid-list stat"
127 __perfcomp_colon "$subcmds" "$cur"
117 # List long option names 128 # List long option names
118 elif [[ $cur == --* ]]; then 129 elif [[ $cur == --* ]]; then
119 subcmd=${words[1]} 130 subcmd=${words[1]}
120 opts=$($cmd $subcmd --list-opts) 131 opts=$($cmd $subcmd --list-opts)
121 COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) ) 132 __perfcomp "$opts" "$cur"
122 fi 133 fi
134}
135
136if [[ -n ${ZSH_VERSION-} ]]; then
137 autoload -U +X compinit && compinit
138
139 __perfcomp ()
140 {
141 emulate -L zsh
142
143 local c IFS=$' \t\n'
144 local -a array
145
146 for c in ${=1}; do
147 case $c in
148 --*=*|*.) ;;
149 *) c="$c " ;;
150 esac
151 array[${#array[@]}+1]="$c"
152 done
153
154 compset -P '*[=:]'
155 compadd -Q -S '' -a -- array && _ret=0
156 }
157
158 __perfcomp_colon ()
159 {
160 emulate -L zsh
161
162 local cur_="${2-$cur}"
163 local c IFS=$' \t\n'
164 local -a array
165
166 if [[ "$cur_" == *:* ]]; then
167 local colon_word=${cur_%"${cur_##*:}"}
168 fi
169
170 for c in ${=1}; do
171 case $c in
172 --*=*|*.) ;;
173 *) c="$c " ;;
174 esac
175 array[$#array+1]=${c#"$colon_word"}
176 done
177
178 compset -P '*[=:]'
179 compadd -Q -S '' -a -- array && _ret=0
180 }
181
182 _perf ()
183 {
184 local _ret=1 cur cword prev
185 cur=${words[CURRENT]}
186 prev=${words[CURRENT-1]}
187 let cword=CURRENT-1
188 emulate ksh -c __perf_main
189 let _ret && _default && _ret=0
190 return _ret
191 }
192
193 compdef _perf perf
194 return
195fi
196
197type perf &>/dev/null &&
198_perf()
199{
200 local cur words cword prev
201 _get_comp_words_by_ref -n =: cur words cword prev
202 __perf_main
123} && 203} &&
124 204
125complete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \ 205complete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 8b38b4e80ec2..431798a4110d 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -13,7 +13,7 @@
13#include "util/quote.h" 13#include "util/quote.h"
14#include "util/run-command.h" 14#include "util/run-command.h"
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16#include <lk/debugfs.h> 16#include <api/fs/debugfs.h>
17#include <pthread.h> 17#include <pthread.h>
18 18
19const char perf_usage_string[] = 19const char perf_usage_string[] =
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index b079304bd53d..3c2f213e979d 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -247,13 +247,14 @@ enum perf_call_graph_mode {
247 CALLCHAIN_DWARF 247 CALLCHAIN_DWARF
248}; 248};
249 249
250struct perf_record_opts { 250struct record_opts {
251 struct target target; 251 struct target target;
252 int call_graph; 252 int call_graph;
253 bool group; 253 bool group;
254 bool inherit_stat; 254 bool inherit_stat;
255 bool no_delay; 255 bool no_buffering;
256 bool no_inherit; 256 bool no_inherit;
257 bool no_inherit_set;
257 bool no_samples; 258 bool no_samples;
258 bool raw_samples; 259 bool raw_samples;
259 bool sample_address; 260 bool sample_address;
@@ -268,6 +269,7 @@ struct perf_record_opts {
268 u64 user_interval; 269 u64 user_interval;
269 u16 stack_dump_size; 270 u16 stack_dump_size;
270 bool sample_transaction; 271 bool sample_transaction;
272 unsigned initial_delay;
271}; 273};
272 274
273#endif 275#endif
diff --git a/tools/perf/tests/attr/test-record-no-inherit b/tools/perf/tests/attr/test-record-no-inherit
index 9079a25cd643..44edcb2edcd5 100644
--- a/tools/perf/tests/attr/test-record-no-inherit
+++ b/tools/perf/tests/attr/test-record-no-inherit
@@ -3,5 +3,5 @@ command = record
3args = -i kill >/dev/null 2>&1 3args = -i kill >/dev/null 2>&1
4 4
5[event:base-record] 5[event:base-record]
6sample_type=259 6sample_type=263
7inherit=0 7inherit=0
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 85d4919dd623..653a8fe2db95 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -391,7 +391,7 @@ static int do_test_code_reading(bool try_kcore)
391 struct machines machines; 391 struct machines machines;
392 struct machine *machine; 392 struct machine *machine;
393 struct thread *thread; 393 struct thread *thread;
394 struct perf_record_opts opts = { 394 struct record_opts opts = {
395 .mmap_pages = UINT_MAX, 395 .mmap_pages = UINT_MAX,
396 .user_freq = UINT_MAX, 396 .user_freq = UINT_MAX,
397 .user_interval = ULLONG_MAX, 397 .user_interval = ULLONG_MAX,
@@ -540,14 +540,11 @@ static int do_test_code_reading(bool try_kcore)
540 err = TEST_CODE_READING_OK; 540 err = TEST_CODE_READING_OK;
541out_err: 541out_err:
542 if (evlist) { 542 if (evlist) {
543 perf_evlist__munmap(evlist);
544 perf_evlist__close(evlist);
545 perf_evlist__delete(evlist); 543 perf_evlist__delete(evlist);
546 } 544 } else {
547 if (cpus)
548 cpu_map__delete(cpus); 545 cpu_map__delete(cpus);
549 if (threads)
550 thread_map__delete(threads); 546 thread_map__delete(threads);
547 }
551 machines__destroy_kernel_maps(&machines); 548 machines__destroy_kernel_maps(&machines);
552 machine__delete_threads(machine); 549 machine__delete_threads(machine);
553 machines__exit(&machines); 550 machines__exit(&machines);
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index 0197bda9c461..465cdbc345cf 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -79,7 +79,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names)
79 } 79 }
80 80
81 err = 0; 81 err = 0;
82 list_for_each_entry(evsel, &evlist->entries, node) { 82 evlist__for_each(evlist, evsel) {
83 if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) { 83 if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) {
84 --err; 84 --err;
85 pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]); 85 pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]);
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 173bf42cc03e..2b6519e0e36f 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -208,7 +208,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
208 * However the second evsel also has a collapsed entry for 208 * However the second evsel also has a collapsed entry for
209 * "bash [libc] malloc" so total 9 entries will be in the tree. 209 * "bash [libc] malloc" so total 9 entries will be in the tree.
210 */ 210 */
211 list_for_each_entry(evsel, &evlist->entries, node) { 211 evlist__for_each(evlist, evsel) {
212 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { 212 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
213 const union perf_event event = { 213 const union perf_event event = {
214 .header = { 214 .header = {
@@ -466,7 +466,7 @@ int test__hists_link(void)
466 if (err < 0) 466 if (err < 0)
467 goto out; 467 goto out;
468 468
469 list_for_each_entry(evsel, &evlist->entries, node) { 469 evlist__for_each(evlist, evsel) {
470 hists__collapse_resort(&evsel->hists, NULL); 470 hists__collapse_resort(&evsel->hists, NULL);
471 471
472 if (verbose > 2) 472 if (verbose > 2)
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index 376c35608534..497957f269d8 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -51,7 +51,7 @@ static int find_comm(struct perf_evlist *evlist, const char *comm)
51 */ 51 */
52int test__keep_tracking(void) 52int test__keep_tracking(void)
53{ 53{
54 struct perf_record_opts opts = { 54 struct record_opts opts = {
55 .mmap_pages = UINT_MAX, 55 .mmap_pages = UINT_MAX,
56 .user_freq = UINT_MAX, 56 .user_freq = UINT_MAX,
57 .user_interval = ULLONG_MAX, 57 .user_interval = ULLONG_MAX,
@@ -142,14 +142,11 @@ int test__keep_tracking(void)
142out_err: 142out_err:
143 if (evlist) { 143 if (evlist) {
144 perf_evlist__disable(evlist); 144 perf_evlist__disable(evlist);
145 perf_evlist__munmap(evlist);
146 perf_evlist__close(evlist);
147 perf_evlist__delete(evlist); 145 perf_evlist__delete(evlist);
148 } 146 } else {
149 if (cpus)
150 cpu_map__delete(cpus); 147 cpu_map__delete(cpus);
151 if (threads)
152 thread_map__delete(threads); 148 thread_map__delete(threads);
149 }
153 150
154 return err; 151 return err;
155} 152}
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 2ca0abf1b2b6..00544b8b644b 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -1,6 +1,16 @@
1PERF := . 1PERF := .
2MK := Makefile 2MK := Makefile
3 3
4include config/Makefile.arch
5
6# FIXME looks like x86 is the only arch running tests ;-)
7# we need some IS_(32/64) flag to make this generic
8ifeq ($(IS_X86_64),1)
9lib = lib64
10else
11lib = lib
12endif
13
4has = $(shell which $1 2>/dev/null) 14has = $(shell which $1 2>/dev/null)
5 15
6# standard single make variable specified 16# standard single make variable specified
@@ -106,10 +116,36 @@ test_make_python_perf_so := test -f $(PERF)/python/perf.so
106test_make_perf_o := test -f $(PERF)/perf.o 116test_make_perf_o := test -f $(PERF)/perf.o
107test_make_util_map_o := test -f $(PERF)/util/map.o 117test_make_util_map_o := test -f $(PERF)/util/map.o
108 118
109test_make_install := test -x $$TMP_DEST/bin/perf 119define test_dest_files
110test_make_install_O := $(test_make_install) 120 for file in $(1); do \
111test_make_install_bin := $(test_make_install) 121 if [ ! -x $$TMP_DEST/$$file ]; then \
112test_make_install_bin_O := $(test_make_install) 122 echo " failed to find: $$file"; \
123 fi \
124 done
125endef
126
127installed_files_bin := bin/perf
128installed_files_bin += etc/bash_completion.d/perf
129installed_files_bin += libexec/perf-core/perf-archive
130
131installed_files_plugins := $(lib)/traceevent/plugins/plugin_cfg80211.so
132installed_files_plugins += $(lib)/traceevent/plugins/plugin_scsi.so
133installed_files_plugins += $(lib)/traceevent/plugins/plugin_xen.so
134installed_files_plugins += $(lib)/traceevent/plugins/plugin_function.so
135installed_files_plugins += $(lib)/traceevent/plugins/plugin_sched_switch.so
136installed_files_plugins += $(lib)/traceevent/plugins/plugin_mac80211.so
137installed_files_plugins += $(lib)/traceevent/plugins/plugin_kvm.so
138installed_files_plugins += $(lib)/traceevent/plugins/plugin_kmem.so
139installed_files_plugins += $(lib)/traceevent/plugins/plugin_hrtimer.so
140installed_files_plugins += $(lib)/traceevent/plugins/plugin_jbd2.so
141
142installed_files_all := $(installed_files_bin)
143installed_files_all += $(installed_files_plugins)
144
145test_make_install := $(call test_dest_files,$(installed_files_all))
146test_make_install_O := $(call test_dest_files,$(installed_files_all))
147test_make_install_bin := $(call test_dest_files,$(installed_files_bin))
148test_make_install_bin_O := $(call test_dest_files,$(installed_files_bin))
113 149
114# FIXME nothing gets installed 150# FIXME nothing gets installed
115test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1 151test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1
@@ -162,7 +198,7 @@ $(run):
162 cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \ 198 cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \
163 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 199 echo "- $@: $$cmd" && echo $$cmd > $@ && \
164 ( eval $$cmd ) >> $@ 2>&1; \ 200 ( eval $$cmd ) >> $@ 2>&1; \
165 echo " test: $(call test,$@)"; \ 201 echo " test: $(call test,$@)" >> $@ 2>&1; \
166 $(call test,$@) && \ 202 $(call test,$@) && \
167 rm -f $@ \ 203 rm -f $@ \
168 rm -rf $$TMP_DEST 204 rm -rf $$TMP_DEST
@@ -174,16 +210,22 @@ $(run_O):
174 cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \ 210 cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \
175 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 211 echo "- $@: $$cmd" && echo $$cmd > $@ && \
176 ( eval $$cmd ) >> $@ 2>&1 && \ 212 ( eval $$cmd ) >> $@ 2>&1 && \
177 echo " test: $(call test_O,$@)"; \ 213 echo " test: $(call test_O,$@)" >> $@ 2>&1; \
178 $(call test_O,$@) && \ 214 $(call test_O,$@) && \
179 rm -f $@ && \ 215 rm -f $@ && \
180 rm -rf $$TMP_O \ 216 rm -rf $$TMP_O \
181 rm -rf $$TMP_DEST 217 rm -rf $$TMP_DEST
182 218
183all: $(run) $(run_O) 219tarpkg:
220 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
221 echo "- $@: $$cmd" && echo $$cmd > $@ && \
222 ( eval $$cmd ) >> $@ 2>&1
223
224
225all: $(run) $(run_O) tarpkg
184 @echo OK 226 @echo OK
185 227
186out: $(run_O) 228out: $(run_O)
187 @echo OK 229 @echo OK
188 230
189.PHONY: all $(run) $(run_O) clean 231.PHONY: all $(run) $(run_O) tarpkg clean
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index d64ab79c6d35..142263492f6f 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -68,7 +68,7 @@ int test__basic_mmap(void)
68 evsels[i] = perf_evsel__newtp("syscalls", name); 68 evsels[i] = perf_evsel__newtp("syscalls", name);
69 if (evsels[i] == NULL) { 69 if (evsels[i] == NULL) {
70 pr_debug("perf_evsel__new\n"); 70 pr_debug("perf_evsel__new\n");
71 goto out_free_evlist; 71 goto out_delete_evlist;
72 } 72 }
73 73
74 evsels[i]->attr.wakeup_events = 1; 74 evsels[i]->attr.wakeup_events = 1;
@@ -80,7 +80,7 @@ int test__basic_mmap(void)
80 pr_debug("failed to open counter: %s, " 80 pr_debug("failed to open counter: %s, "
81 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 81 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
82 strerror(errno)); 82 strerror(errno));
83 goto out_close_fd; 83 goto out_delete_evlist;
84 } 84 }
85 85
86 nr_events[i] = 0; 86 nr_events[i] = 0;
@@ -90,7 +90,7 @@ int test__basic_mmap(void)
90 if (perf_evlist__mmap(evlist, 128, true) < 0) { 90 if (perf_evlist__mmap(evlist, 128, true) < 0) {
91 pr_debug("failed to mmap events: %d (%s)\n", errno, 91 pr_debug("failed to mmap events: %d (%s)\n", errno,
92 strerror(errno)); 92 strerror(errno));
93 goto out_close_fd; 93 goto out_delete_evlist;
94 } 94 }
95 95
96 for (i = 0; i < nsyscalls; ++i) 96 for (i = 0; i < nsyscalls; ++i)
@@ -105,13 +105,13 @@ int test__basic_mmap(void)
105 if (event->header.type != PERF_RECORD_SAMPLE) { 105 if (event->header.type != PERF_RECORD_SAMPLE) {
106 pr_debug("unexpected %s event\n", 106 pr_debug("unexpected %s event\n",
107 perf_event__name(event->header.type)); 107 perf_event__name(event->header.type));
108 goto out_munmap; 108 goto out_delete_evlist;
109 } 109 }
110 110
111 err = perf_evlist__parse_sample(evlist, event, &sample); 111 err = perf_evlist__parse_sample(evlist, event, &sample);
112 if (err) { 112 if (err) {
113 pr_err("Can't parse sample, err = %d\n", err); 113 pr_err("Can't parse sample, err = %d\n", err);
114 goto out_munmap; 114 goto out_delete_evlist;
115 } 115 }
116 116
117 err = -1; 117 err = -1;
@@ -119,30 +119,27 @@ int test__basic_mmap(void)
119 if (evsel == NULL) { 119 if (evsel == NULL) {
120 pr_debug("event with id %" PRIu64 120 pr_debug("event with id %" PRIu64
121 " doesn't map to an evsel\n", sample.id); 121 " doesn't map to an evsel\n", sample.id);
122 goto out_munmap; 122 goto out_delete_evlist;
123 } 123 }
124 nr_events[evsel->idx]++; 124 nr_events[evsel->idx]++;
125 perf_evlist__mmap_consume(evlist, 0); 125 perf_evlist__mmap_consume(evlist, 0);
126 } 126 }
127 127
128 err = 0; 128 err = 0;
129 list_for_each_entry(evsel, &evlist->entries, node) { 129 evlist__for_each(evlist, evsel) {
130 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { 130 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
131 pr_debug("expected %d %s events, got %d\n", 131 pr_debug("expected %d %s events, got %d\n",
132 expected_nr_events[evsel->idx], 132 expected_nr_events[evsel->idx],
133 perf_evsel__name(evsel), nr_events[evsel->idx]); 133 perf_evsel__name(evsel), nr_events[evsel->idx]);
134 err = -1; 134 err = -1;
135 goto out_munmap; 135 goto out_delete_evlist;
136 } 136 }
137 } 137 }
138 138
139out_munmap: 139out_delete_evlist:
140 perf_evlist__munmap(evlist);
141out_close_fd:
142 for (i = 0; i < nsyscalls; ++i)
143 perf_evsel__close_fd(evsels[i], 1, threads->nr);
144out_free_evlist:
145 perf_evlist__delete(evlist); 140 perf_evlist__delete(evlist);
141 cpus = NULL;
142 threads = NULL;
146out_free_cpus: 143out_free_cpus:
147 cpu_map__delete(cpus); 144 cpu_map__delete(cpus);
148out_free_threads: 145out_free_threads:
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c
index 41cc0badb74b..c505ef2af245 100644
--- a/tools/perf/tests/open-syscall-tp-fields.c
+++ b/tools/perf/tests/open-syscall-tp-fields.c
@@ -6,15 +6,15 @@
6 6
7int test__syscall_open_tp_fields(void) 7int test__syscall_open_tp_fields(void)
8{ 8{
9 struct perf_record_opts opts = { 9 struct record_opts opts = {
10 .target = { 10 .target = {
11 .uid = UINT_MAX, 11 .uid = UINT_MAX,
12 .uses_mmap = true, 12 .uses_mmap = true,
13 }, 13 },
14 .no_delay = true, 14 .no_buffering = true,
15 .freq = 1, 15 .freq = 1,
16 .mmap_pages = 256, 16 .mmap_pages = 256,
17 .raw_samples = true, 17 .raw_samples = true,
18 }; 18 };
19 const char *filename = "/etc/passwd"; 19 const char *filename = "/etc/passwd";
20 int flags = O_RDONLY | O_DIRECTORY; 20 int flags = O_RDONLY | O_DIRECTORY;
@@ -48,13 +48,13 @@ int test__syscall_open_tp_fields(void)
48 err = perf_evlist__open(evlist); 48 err = perf_evlist__open(evlist);
49 if (err < 0) { 49 if (err < 0) {
50 pr_debug("perf_evlist__open: %s\n", strerror(errno)); 50 pr_debug("perf_evlist__open: %s\n", strerror(errno));
51 goto out_delete_maps; 51 goto out_delete_evlist;
52 } 52 }
53 53
54 err = perf_evlist__mmap(evlist, UINT_MAX, false); 54 err = perf_evlist__mmap(evlist, UINT_MAX, false);
55 if (err < 0) { 55 if (err < 0) {
56 pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 56 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
57 goto out_close_evlist; 57 goto out_delete_evlist;
58 } 58 }
59 59
60 perf_evlist__enable(evlist); 60 perf_evlist__enable(evlist);
@@ -85,7 +85,7 @@ int test__syscall_open_tp_fields(void)
85 err = perf_evsel__parse_sample(evsel, event, &sample); 85 err = perf_evsel__parse_sample(evsel, event, &sample);
86 if (err) { 86 if (err) {
87 pr_err("Can't parse sample, err = %d\n", err); 87 pr_err("Can't parse sample, err = %d\n", err);
88 goto out_munmap; 88 goto out_delete_evlist;
89 } 89 }
90 90
91 tp_flags = perf_evsel__intval(evsel, &sample, "flags"); 91 tp_flags = perf_evsel__intval(evsel, &sample, "flags");
@@ -93,7 +93,7 @@ int test__syscall_open_tp_fields(void)
93 if (flags != tp_flags) { 93 if (flags != tp_flags) {
94 pr_debug("%s: Expected flags=%#x, got %#x\n", 94 pr_debug("%s: Expected flags=%#x, got %#x\n",
95 __func__, flags, tp_flags); 95 __func__, flags, tp_flags);
96 goto out_munmap; 96 goto out_delete_evlist;
97 } 97 }
98 98
99 goto out_ok; 99 goto out_ok;
@@ -105,17 +105,11 @@ int test__syscall_open_tp_fields(void)
105 105
106 if (++nr_polls > 5) { 106 if (++nr_polls > 5) {
107 pr_debug("%s: no events!\n", __func__); 107 pr_debug("%s: no events!\n", __func__);
108 goto out_munmap; 108 goto out_delete_evlist;
109 } 109 }
110 } 110 }
111out_ok: 111out_ok:
112 err = 0; 112 err = 0;
113out_munmap:
114 perf_evlist__munmap(evlist);
115out_close_evlist:
116 perf_evlist__close(evlist);
117out_delete_maps:
118 perf_evlist__delete_maps(evlist);
119out_delete_evlist: 113out_delete_evlist:
120 perf_evlist__delete(evlist); 114 perf_evlist__delete(evlist);
121out: 115out:
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 3cbd10496087..4db0ae617d70 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -3,7 +3,7 @@
3#include "evsel.h" 3#include "evsel.h"
4#include "evlist.h" 4#include "evlist.h"
5#include "fs.h" 5#include "fs.h"
6#include <lk/debugfs.h> 6#include <api/fs/debugfs.h>
7#include "tests.h" 7#include "tests.h"
8#include <linux/hw_breakpoint.h> 8#include <linux/hw_breakpoint.h>
9 9
@@ -30,7 +30,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
30 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); 30 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
31 TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); 31 TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups);
32 32
33 list_for_each_entry(evsel, &evlist->entries, node) { 33 evlist__for_each(evlist, evsel) {
34 TEST_ASSERT_VAL("wrong type", 34 TEST_ASSERT_VAL("wrong type",
35 PERF_TYPE_TRACEPOINT == evsel->attr.type); 35 PERF_TYPE_TRACEPOINT == evsel->attr.type);
36 TEST_ASSERT_VAL("wrong sample_type", 36 TEST_ASSERT_VAL("wrong sample_type",
@@ -201,7 +201,7 @@ test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
201 201
202 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); 202 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
203 203
204 list_for_each_entry(evsel, &evlist->entries, node) { 204 evlist__for_each(evlist, evsel) {
205 TEST_ASSERT_VAL("wrong exclude_user", 205 TEST_ASSERT_VAL("wrong exclude_user",
206 !evsel->attr.exclude_user); 206 !evsel->attr.exclude_user);
207 TEST_ASSERT_VAL("wrong exclude_kernel", 207 TEST_ASSERT_VAL("wrong exclude_kernel",
@@ -1385,10 +1385,10 @@ static int test_event(struct evlist_test *e)
1385 if (ret) { 1385 if (ret) {
1386 pr_debug("failed to parse event '%s', err %d\n", 1386 pr_debug("failed to parse event '%s', err %d\n",
1387 e->name, ret); 1387 e->name, ret);
1388 return ret; 1388 } else {
1389 ret = e->check(evlist);
1389 } 1390 }
1390 1391
1391 ret = e->check(evlist);
1392 perf_evlist__delete(evlist); 1392 perf_evlist__delete(evlist);
1393 1393
1394 return ret; 1394 return ret;
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 93a62b06c3af..aca1a83dd13a 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -34,14 +34,14 @@ realloc:
34 34
35int test__PERF_RECORD(void) 35int test__PERF_RECORD(void)
36{ 36{
37 struct perf_record_opts opts = { 37 struct record_opts opts = {
38 .target = { 38 .target = {
39 .uid = UINT_MAX, 39 .uid = UINT_MAX,
40 .uses_mmap = true, 40 .uses_mmap = true,
41 }, 41 },
42 .no_delay = true, 42 .no_buffering = true,
43 .freq = 10, 43 .freq = 10,
44 .mmap_pages = 256, 44 .mmap_pages = 256,
45 }; 45 };
46 cpu_set_t cpu_mask; 46 cpu_set_t cpu_mask;
47 size_t cpu_mask_size = sizeof(cpu_mask); 47 size_t cpu_mask_size = sizeof(cpu_mask);
@@ -83,11 +83,10 @@ int test__PERF_RECORD(void)
83 * so that we have time to open the evlist (calling sys_perf_event_open 83 * so that we have time to open the evlist (calling sys_perf_event_open
84 * on all the fds) and then mmap them. 84 * on all the fds) and then mmap them.
85 */ 85 */
86 err = perf_evlist__prepare_workload(evlist, &opts.target, argv, 86 err = perf_evlist__prepare_workload(evlist, &opts.target, argv, false, NULL);
87 false, false);
88 if (err < 0) { 87 if (err < 0) {
89 pr_debug("Couldn't run the workload!\n"); 88 pr_debug("Couldn't run the workload!\n");
90 goto out_delete_maps; 89 goto out_delete_evlist;
91 } 90 }
92 91
93 /* 92 /*
@@ -102,7 +101,7 @@ int test__PERF_RECORD(void)
102 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); 101 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
103 if (err < 0) { 102 if (err < 0) {
104 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); 103 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
105 goto out_delete_maps; 104 goto out_delete_evlist;
106 } 105 }
107 106
108 cpu = err; 107 cpu = err;
@@ -112,7 +111,7 @@ int test__PERF_RECORD(void)
112 */ 111 */
113 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { 112 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) {
114 pr_debug("sched_setaffinity: %s\n", strerror(errno)); 113 pr_debug("sched_setaffinity: %s\n", strerror(errno));
115 goto out_delete_maps; 114 goto out_delete_evlist;
116 } 115 }
117 116
118 /* 117 /*
@@ -122,7 +121,7 @@ int test__PERF_RECORD(void)
122 err = perf_evlist__open(evlist); 121 err = perf_evlist__open(evlist);
123 if (err < 0) { 122 if (err < 0) {
124 pr_debug("perf_evlist__open: %s\n", strerror(errno)); 123 pr_debug("perf_evlist__open: %s\n", strerror(errno));
125 goto out_delete_maps; 124 goto out_delete_evlist;
126 } 125 }
127 126
128 /* 127 /*
@@ -133,7 +132,7 @@ int test__PERF_RECORD(void)
133 err = perf_evlist__mmap(evlist, opts.mmap_pages, false); 132 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
134 if (err < 0) { 133 if (err < 0) {
135 pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 134 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
136 goto out_close_evlist; 135 goto out_delete_evlist;
137 } 136 }
138 137
139 /* 138 /*
@@ -166,7 +165,7 @@ int test__PERF_RECORD(void)
166 if (verbose) 165 if (verbose)
167 perf_event__fprintf(event, stderr); 166 perf_event__fprintf(event, stderr);
168 pr_debug("Couldn't parse sample\n"); 167 pr_debug("Couldn't parse sample\n");
169 goto out_err; 168 goto out_delete_evlist;
170 } 169 }
171 170
172 if (verbose) { 171 if (verbose) {
@@ -303,12 +302,6 @@ found_exit:
303 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]"); 302 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
304 ++errs; 303 ++errs;
305 } 304 }
306out_err:
307 perf_evlist__munmap(evlist);
308out_close_evlist:
309 perf_evlist__close(evlist);
310out_delete_maps:
311 perf_evlist__delete_maps(evlist);
312out_delete_evlist: 305out_delete_evlist:
313 perf_evlist__delete(evlist); 306 perf_evlist__delete(evlist);
314out: 307out:
diff --git a/tools/perf/tests/perf-targz-src-pkg b/tools/perf/tests/perf-targz-src-pkg
new file mode 100755
index 000000000000..238aa3927c71
--- /dev/null
+++ b/tools/perf/tests/perf-targz-src-pkg
@@ -0,0 +1,21 @@
1#!/bin/sh
2# Test one of the main kernel Makefile targets to generate a perf sources tarball
3# suitable for build outside the full kernel sources.
4#
5# This is to test that the tools/perf/MANIFEST file lists all the files needed to
6# be in such tarball, which sometimes gets broken when we move files around,
7# like when we made some files that were in tools/perf/ available to other tools/
8# codebases by moving it to tools/include/, etc.
9
10PERF=$1
11cd ${PERF}/../..
12make perf-targz-src-pkg > /dev/null
13TARBALL=$(ls -rt perf-*.tar.gz)
14TMP_DEST=$(mktemp -d)
15tar xf ${TARBALL} -C $TMP_DEST
16rm -f ${TARBALL}
17cd - > /dev/null
18make -C $TMP_DEST/perf*/tools/perf > /dev/null 2>&1
19RC=$?
20rm -rf ${TMP_DEST}
21exit $RC
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index 4ca1b938f6a6..47146d388dbf 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -46,7 +46,7 @@ static u64 rdtsc(void)
46 */ 46 */
47int test__perf_time_to_tsc(void) 47int test__perf_time_to_tsc(void)
48{ 48{
49 struct perf_record_opts opts = { 49 struct record_opts opts = {
50 .mmap_pages = UINT_MAX, 50 .mmap_pages = UINT_MAX,
51 .user_freq = UINT_MAX, 51 .user_freq = UINT_MAX,
52 .user_interval = ULLONG_MAX, 52 .user_interval = ULLONG_MAX,
@@ -166,14 +166,8 @@ next_event:
166out_err: 166out_err:
167 if (evlist) { 167 if (evlist) {
168 perf_evlist__disable(evlist); 168 perf_evlist__disable(evlist);
169 perf_evlist__munmap(evlist);
170 perf_evlist__close(evlist);
171 perf_evlist__delete(evlist); 169 perf_evlist__delete(evlist);
172 } 170 }
173 if (cpus)
174 cpu_map__delete(cpus);
175 if (threads)
176 thread_map__delete(threads);
177 171
178 return err; 172 return err;
179} 173}
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
index 6664a7cd828c..983d6b8562a8 100644
--- a/tools/perf/tests/sw-clock.c
+++ b/tools/perf/tests/sw-clock.c
@@ -45,7 +45,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
45 evsel = perf_evsel__new(&attr); 45 evsel = perf_evsel__new(&attr);
46 if (evsel == NULL) { 46 if (evsel == NULL) {
47 pr_debug("perf_evsel__new\n"); 47 pr_debug("perf_evsel__new\n");
48 goto out_free_evlist; 48 goto out_delete_evlist;
49 } 49 }
50 perf_evlist__add(evlist, evsel); 50 perf_evlist__add(evlist, evsel);
51 51
@@ -54,7 +54,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
54 if (!evlist->cpus || !evlist->threads) { 54 if (!evlist->cpus || !evlist->threads) {
55 err = -ENOMEM; 55 err = -ENOMEM;
56 pr_debug("Not enough memory to create thread/cpu maps\n"); 56 pr_debug("Not enough memory to create thread/cpu maps\n");
57 goto out_delete_maps; 57 goto out_delete_evlist;
58 } 58 }
59 59
60 if (perf_evlist__open(evlist)) { 60 if (perf_evlist__open(evlist)) {
@@ -63,14 +63,14 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
63 err = -errno; 63 err = -errno;
64 pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n", 64 pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",
65 strerror(errno), knob, (u64)attr.sample_freq); 65 strerror(errno), knob, (u64)attr.sample_freq);
66 goto out_delete_maps; 66 goto out_delete_evlist;
67 } 67 }
68 68
69 err = perf_evlist__mmap(evlist, 128, true); 69 err = perf_evlist__mmap(evlist, 128, true);
70 if (err < 0) { 70 if (err < 0) {
71 pr_debug("failed to mmap event: %d (%s)\n", errno, 71 pr_debug("failed to mmap event: %d (%s)\n", errno,
72 strerror(errno)); 72 strerror(errno));
73 goto out_close_evlist; 73 goto out_delete_evlist;
74 } 74 }
75 75
76 perf_evlist__enable(evlist); 76 perf_evlist__enable(evlist);
@@ -90,7 +90,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
90 err = perf_evlist__parse_sample(evlist, event, &sample); 90 err = perf_evlist__parse_sample(evlist, event, &sample);
91 if (err < 0) { 91 if (err < 0) {
92 pr_debug("Error during parse sample\n"); 92 pr_debug("Error during parse sample\n");
93 goto out_unmap_evlist; 93 goto out_delete_evlist;
94 } 94 }
95 95
96 total_periods += sample.period; 96 total_periods += sample.period;
@@ -105,13 +105,7 @@ next_event:
105 err = -1; 105 err = -1;
106 } 106 }
107 107
108out_unmap_evlist: 108out_delete_evlist:
109 perf_evlist__munmap(evlist);
110out_close_evlist:
111 perf_evlist__close(evlist);
112out_delete_maps:
113 perf_evlist__delete_maps(evlist);
114out_free_evlist:
115 perf_evlist__delete(evlist); 109 perf_evlist__delete(evlist);
116 return err; 110 return err;
117} 111}
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
index d09ab579119e..5ff3db318f12 100644
--- a/tools/perf/tests/task-exit.c
+++ b/tools/perf/tests/task-exit.c
@@ -9,12 +9,21 @@
9static int exited; 9static int exited;
10static int nr_exit; 10static int nr_exit;
11 11
12static void sig_handler(int sig) 12static void sig_handler(int sig __maybe_unused)
13{ 13{
14 exited = 1; 14 exited = 1;
15}
15 16
16 if (sig == SIGUSR1) 17/*
17 nr_exit = -1; 18 * perf_evlist__prepare_workload will send a SIGUSR1 if the fork fails, since
19 * we asked by setting its exec_error to this handler.
20 */
21static void workload_exec_failed_signal(int signo __maybe_unused,
22 siginfo_t *info __maybe_unused,
23 void *ucontext __maybe_unused)
24{
25 exited = 1;
26 nr_exit = -1;
18} 27}
19 28
20/* 29/*
@@ -35,7 +44,6 @@ int test__task_exit(void)
35 const char *argv[] = { "true", NULL }; 44 const char *argv[] = { "true", NULL };
36 45
37 signal(SIGCHLD, sig_handler); 46 signal(SIGCHLD, sig_handler);
38 signal(SIGUSR1, sig_handler);
39 47
40 evlist = perf_evlist__new_default(); 48 evlist = perf_evlist__new_default();
41 if (evlist == NULL) { 49 if (evlist == NULL) {
@@ -54,13 +62,14 @@ int test__task_exit(void)
54 if (!evlist->cpus || !evlist->threads) { 62 if (!evlist->cpus || !evlist->threads) {
55 err = -ENOMEM; 63 err = -ENOMEM;
56 pr_debug("Not enough memory to create thread/cpu maps\n"); 64 pr_debug("Not enough memory to create thread/cpu maps\n");
57 goto out_delete_maps; 65 goto out_delete_evlist;
58 } 66 }
59 67
60 err = perf_evlist__prepare_workload(evlist, &target, argv, false, true); 68 err = perf_evlist__prepare_workload(evlist, &target, argv, false,
69 workload_exec_failed_signal);
61 if (err < 0) { 70 if (err < 0) {
62 pr_debug("Couldn't run the workload!\n"); 71 pr_debug("Couldn't run the workload!\n");
63 goto out_delete_maps; 72 goto out_delete_evlist;
64 } 73 }
65 74
66 evsel = perf_evlist__first(evlist); 75 evsel = perf_evlist__first(evlist);
@@ -74,13 +83,13 @@ int test__task_exit(void)
74 err = perf_evlist__open(evlist); 83 err = perf_evlist__open(evlist);
75 if (err < 0) { 84 if (err < 0) {
76 pr_debug("Couldn't open the evlist: %s\n", strerror(-err)); 85 pr_debug("Couldn't open the evlist: %s\n", strerror(-err));
77 goto out_delete_maps; 86 goto out_delete_evlist;
78 } 87 }
79 88
80 if (perf_evlist__mmap(evlist, 128, true) < 0) { 89 if (perf_evlist__mmap(evlist, 128, true) < 0) {
81 pr_debug("failed to mmap events: %d (%s)\n", errno, 90 pr_debug("failed to mmap events: %d (%s)\n", errno,
82 strerror(errno)); 91 strerror(errno));
83 goto out_close_evlist; 92 goto out_delete_evlist;
84 } 93 }
85 94
86 perf_evlist__start_workload(evlist); 95 perf_evlist__start_workload(evlist);
@@ -103,11 +112,7 @@ retry:
103 err = -1; 112 err = -1;
104 } 113 }
105 114
106 perf_evlist__munmap(evlist); 115out_delete_evlist:
107out_close_evlist:
108 perf_evlist__close(evlist);
109out_delete_maps:
110 perf_evlist__delete_maps(evlist);
111 perf_evlist__delete(evlist); 116 perf_evlist__delete(evlist);
112 return err; 117 return err;
113} 118}
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index cbaa7af45513..d11541d4d7d7 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -256,8 +256,7 @@ int ui_browser__show(struct ui_browser *browser, const char *title,
256 __ui_browser__show_title(browser, title); 256 __ui_browser__show_title(browser, title);
257 257
258 browser->title = title; 258 browser->title = title;
259 free(browser->helpline); 259 zfree(&browser->helpline);
260 browser->helpline = NULL;
261 260
262 va_start(ap, helpline); 261 va_start(ap, helpline);
263 err = vasprintf(&browser->helpline, helpline, ap); 262 err = vasprintf(&browser->helpline, helpline, ap);
@@ -268,12 +267,11 @@ int ui_browser__show(struct ui_browser *browser, const char *title,
268 return err ? 0 : -1; 267 return err ? 0 : -1;
269} 268}
270 269
271void ui_browser__hide(struct ui_browser *browser __maybe_unused) 270void ui_browser__hide(struct ui_browser *browser)
272{ 271{
273 pthread_mutex_lock(&ui__lock); 272 pthread_mutex_lock(&ui__lock);
274 ui_helpline__pop(); 273 ui_helpline__pop();
275 free(browser->helpline); 274 zfree(&browser->helpline);
276 browser->helpline = NULL;
277 pthread_mutex_unlock(&ui__lock); 275 pthread_mutex_unlock(&ui__lock);
278} 276}
279 277
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index 7d45d2f53601..118cca29dd26 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -59,6 +59,8 @@ int ui_browser__help_window(struct ui_browser *browser, const char *text);
59bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); 59bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
60int ui_browser__input_window(const char *title, const char *text, char *input, 60int ui_browser__input_window(const char *title, const char *text, char *input,
61 const char *exit_msg, int delay_sec); 61 const char *exit_msg, int delay_sec);
62struct perf_session_env;
63int tui__header_window(struct perf_session_env *env);
62 64
63void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); 65void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
64unsigned int ui_browser__argv_refresh(struct ui_browser *browser); 66unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
diff --git a/tools/perf/ui/browsers/header.c b/tools/perf/ui/browsers/header.c
new file mode 100644
index 000000000000..89c16b988618
--- /dev/null
+++ b/tools/perf/ui/browsers/header.c
@@ -0,0 +1,127 @@
1#include "util/cache.h"
2#include "util/debug.h"
3#include "ui/browser.h"
4#include "ui/ui.h"
5#include "ui/util.h"
6#include "ui/libslang.h"
7#include "util/header.h"
8#include "util/session.h"
9
10static void ui_browser__argv_write(struct ui_browser *browser,
11 void *entry, int row)
12{
13 char **arg = entry;
14 char *str = *arg;
15 char empty[] = " ";
16 bool current_entry = ui_browser__is_current_entry(browser, row);
17 unsigned long offset = (unsigned long)browser->priv;
18
19 if (offset >= strlen(str))
20 str = empty;
21 else
22 str = str + offset;
23
24 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
25 HE_COLORSET_NORMAL);
26
27 slsmg_write_nstring(str, browser->width);
28}
29
30static int list_menu__run(struct ui_browser *menu)
31{
32 int key;
33 unsigned long offset;
34 const char help[] =
35 "h/?/F1 Show this window\n"
36 "UP/DOWN/PGUP\n"
37 "PGDN/SPACE\n"
38 "LEFT/RIGHT Navigate\n"
39 "q/ESC/CTRL+C Exit browser";
40
41 if (ui_browser__show(menu, "Header information", "Press 'q' to exit") < 0)
42 return -1;
43
44 while (1) {
45 key = ui_browser__run(menu, 0);
46
47 switch (key) {
48 case K_RIGHT:
49 offset = (unsigned long)menu->priv;
50 offset += 10;
51 menu->priv = (void *)offset;
52 continue;
53 case K_LEFT:
54 offset = (unsigned long)menu->priv;
55 if (offset >= 10)
56 offset -= 10;
57 menu->priv = (void *)offset;
58 continue;
59 case K_F1:
60 case 'h':
61 case '?':
62 ui_browser__help_window(menu, help);
63 continue;
64 case K_ESC:
65 case 'q':
66 case CTRL('c'):
67 key = -1;
68 break;
69 default:
70 continue;
71 }
72
73 break;
74 }
75
76 ui_browser__hide(menu);
77 return key;
78}
79
80static int ui__list_menu(int argc, char * const argv[])
81{
82 struct ui_browser menu = {
83 .entries = (void *)argv,
84 .refresh = ui_browser__argv_refresh,
85 .seek = ui_browser__argv_seek,
86 .write = ui_browser__argv_write,
87 .nr_entries = argc,
88 };
89
90 return list_menu__run(&menu);
91}
92
93int tui__header_window(struct perf_session_env *env)
94{
95 int i, argc = 0;
96 char **argv;
97 struct perf_session *session;
98 char *ptr, *pos;
99 size_t size;
100 FILE *fp = open_memstream(&ptr, &size);
101
102 session = container_of(env, struct perf_session, header.env);
103 perf_header__fprintf_info(session, fp, true);
104 fclose(fp);
105
106 for (pos = ptr, argc = 0; (pos = strchr(pos, '\n')) != NULL; pos++)
107 argc++;
108
109 argv = calloc(argc + 1, sizeof(*argv));
110 if (argv == NULL)
111 goto out;
112
113 argv[0] = pos = ptr;
114 for (i = 1; (pos = strchr(pos, '\n')) != NULL; i++) {
115 *pos++ = '\0';
116 argv[i] = pos;
117 }
118
119 BUG_ON(i != argc + 1);
120
121 ui__list_menu(argc, argv);
122
123out:
124 free(argv);
125 free(ptr);
126 return 0;
127}
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index a440e03cd8c2..b720b92eba6e 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1267,10 +1267,8 @@ static inline void free_popup_options(char **options, int n)
1267{ 1267{
1268 int i; 1268 int i;
1269 1269
1270 for (i = 0; i < n; ++i) { 1270 for (i = 0; i < n; ++i)
1271 free(options[i]); 1271 zfree(&options[i]);
1272 options[i] = NULL;
1273 }
1274} 1272}
1275 1273
1276/* Check whether the browser is for 'top' or 'report' */ 1274/* Check whether the browser is for 'top' or 'report' */
@@ -1329,7 +1327,7 @@ static int switch_data_file(void)
1329 1327
1330 abs_path[nr_options] = strdup(path); 1328 abs_path[nr_options] = strdup(path);
1331 if (!abs_path[nr_options]) { 1329 if (!abs_path[nr_options]) {
1332 free(options[nr_options]); 1330 zfree(&options[nr_options]);
1333 ui__warning("Can't search all data files due to memory shortage.\n"); 1331 ui__warning("Can't search all data files due to memory shortage.\n");
1334 fclose(file); 1332 fclose(file);
1335 break; 1333 break;
@@ -1400,6 +1398,36 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1400 char script_opt[64]; 1398 char script_opt[64];
1401 int delay_secs = hbt ? hbt->refresh : 0; 1399 int delay_secs = hbt ? hbt->refresh : 0;
1402 1400
1401#define HIST_BROWSER_HELP_COMMON \
1402 "h/?/F1 Show this window\n" \
1403 "UP/DOWN/PGUP\n" \
1404 "PGDN/SPACE Navigate\n" \
1405 "q/ESC/CTRL+C Exit browser\n\n" \
1406 "For multiple event sessions:\n\n" \
1407 "TAB/UNTAB Switch events\n\n" \
1408 "For symbolic views (--sort has sym):\n\n" \
1409 "-> Zoom into DSO/Threads & Annotate current symbol\n" \
1410 "<- Zoom out\n" \
1411 "a Annotate current symbol\n" \
1412 "C Collapse all callchains\n" \
1413 "d Zoom into current DSO\n" \
1414 "E Expand all callchains\n" \
1415
1416 /* help messages are sorted by lexical order of the hotkey */
1417 const char report_help[] = HIST_BROWSER_HELP_COMMON
1418 "i Show header information\n"
1419 "P Print histograms to perf.hist.N\n"
1420 "r Run available scripts\n"
1421 "s Switch to another data file in PWD\n"
1422 "t Zoom into current Thread\n"
1423 "V Verbose (DSO names in callchains, etc)\n"
1424 "/ Filter symbol by name";
1425 const char top_help[] = HIST_BROWSER_HELP_COMMON
1426 "P Print histograms to perf.hist.N\n"
1427 "t Zoom into current Thread\n"
1428 "V Verbose (DSO names in callchains, etc)\n"
1429 "/ Filter symbol by name";
1430
1403 if (browser == NULL) 1431 if (browser == NULL)
1404 return -1; 1432 return -1;
1405 1433
@@ -1484,29 +1512,16 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1484 if (is_report_browser(hbt)) 1512 if (is_report_browser(hbt))
1485 goto do_data_switch; 1513 goto do_data_switch;
1486 continue; 1514 continue;
1515 case 'i':
1516 /* env->arch is NULL for live-mode (i.e. perf top) */
1517 if (env->arch)
1518 tui__header_window(env);
1519 continue;
1487 case K_F1: 1520 case K_F1:
1488 case 'h': 1521 case 'h':
1489 case '?': 1522 case '?':
1490 ui_browser__help_window(&browser->b, 1523 ui_browser__help_window(&browser->b,
1491 "h/?/F1 Show this window\n" 1524 is_report_browser(hbt) ? report_help : top_help);
1492 "UP/DOWN/PGUP\n"
1493 "PGDN/SPACE Navigate\n"
1494 "q/ESC/CTRL+C Exit browser\n\n"
1495 "For multiple event sessions:\n\n"
1496 "TAB/UNTAB Switch events\n\n"
1497 "For symbolic views (--sort has sym):\n\n"
1498 "-> Zoom into DSO/Threads & Annotate current symbol\n"
1499 "<- Zoom out\n"
1500 "a Annotate current symbol\n"
1501 "C Collapse all callchains\n"
1502 "E Expand all callchains\n"
1503 "d Zoom into current DSO\n"
1504 "t Zoom into current Thread\n"
1505 "r Run available scripts('perf report' only)\n"
1506 "s Switch to another data file in PWD ('perf report' only)\n"
1507 "P Print histograms to perf.hist.N\n"
1508 "V Verbose (DSO names in callchains, etc)\n"
1509 "/ Filter symbol by name");
1510 continue; 1525 continue;
1511 case K_ENTER: 1526 case K_ENTER:
1512 case K_RIGHT: 1527 case K_RIGHT:
@@ -1923,7 +1938,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1923 1938
1924 ui_helpline__push("Press ESC to exit"); 1939 ui_helpline__push("Press ESC to exit");
1925 1940
1926 list_for_each_entry(pos, &evlist->entries, node) { 1941 evlist__for_each(evlist, pos) {
1927 const char *ev_name = perf_evsel__name(pos); 1942 const char *ev_name = perf_evsel__name(pos);
1928 size_t line_len = strlen(ev_name) + 7; 1943 size_t line_len = strlen(ev_name) + 7;
1929 1944
@@ -1955,9 +1970,10 @@ single_entry:
1955 struct perf_evsel *pos; 1970 struct perf_evsel *pos;
1956 1971
1957 nr_entries = 0; 1972 nr_entries = 0;
1958 list_for_each_entry(pos, &evlist->entries, node) 1973 evlist__for_each(evlist, pos) {
1959 if (perf_evsel__is_group_leader(pos)) 1974 if (perf_evsel__is_group_leader(pos))
1960 nr_entries++; 1975 nr_entries++;
1976 }
1961 1977
1962 if (nr_entries == 1) 1978 if (nr_entries == 1)
1963 goto single_entry; 1979 goto single_entry;
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
index d63c68ea02a8..402d2bd30b09 100644
--- a/tools/perf/ui/browsers/scripts.c
+++ b/tools/perf/ui/browsers/scripts.c
@@ -173,8 +173,7 @@ int script_browse(const char *script_opt)
173 if (script.b.width > AVERAGE_LINE_LEN) 173 if (script.b.width > AVERAGE_LINE_LEN)
174 script.b.width = AVERAGE_LINE_LEN; 174 script.b.width = AVERAGE_LINE_LEN;
175 175
176 if (line) 176 free(line);
177 free(line);
178 pclose(fp); 177 pclose(fp);
179 178
180 script.nr_lines = nr_entries; 179 script.nr_lines = nr_entries;
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 2ca66cc1160f..5b95c44f3435 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -375,7 +375,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
375 375
376 gtk_container_add(GTK_CONTAINER(window), vbox); 376 gtk_container_add(GTK_CONTAINER(window), vbox);
377 377
378 list_for_each_entry(pos, &evlist->entries, node) { 378 evlist__for_each(evlist, pos) {
379 struct hists *hists = &pos->hists; 379 struct hists *hists = &pos->hists;
380 const char *evname = perf_evsel__name(pos); 380 const char *evname = perf_evsel__name(pos);
381 GtkWidget *scrolled_window; 381 GtkWidget *scrolled_window;
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
index 696c1fbe4248..52e7fc48af9f 100644
--- a/tools/perf/ui/gtk/util.c
+++ b/tools/perf/ui/gtk/util.c
@@ -23,8 +23,7 @@ int perf_gtk__deactivate_context(struct perf_gtk_context **ctx)
23 if (!perf_gtk__is_active_context(*ctx)) 23 if (!perf_gtk__is_active_context(*ctx))
24 return -1; 24 return -1;
25 25
26 free(*ctx); 26 zfree(ctx);
27 *ctx = NULL;
28 return 0; 27 return 0;
29} 28}
30 29
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index c244cb524ef2..831fbb77d1ff 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -510,7 +510,7 @@ print_entries:
510 510
511 free(line); 511 free(line);
512out: 512out:
513 free(rem_sq_bracket); 513 zfree(&rem_sq_bracket);
514 514
515 return ret; 515 return ret;
516} 516}
diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c
index 092902e30cee..bf890f72fe80 100644
--- a/tools/perf/ui/tui/util.c
+++ b/tools/perf/ui/tui/util.c
@@ -92,6 +92,8 @@ int ui_browser__input_window(const char *title, const char *text, char *input,
92 t = sep + 1; 92 t = sep + 1;
93 } 93 }
94 94
95 pthread_mutex_lock(&ui__lock);
96
95 max_len += 2; 97 max_len += 2;
96 nr_lines += 8; 98 nr_lines += 8;
97 y = SLtt_Screen_Rows / 2 - nr_lines / 2; 99 y = SLtt_Screen_Rows / 2 - nr_lines / 2;
@@ -120,13 +122,19 @@ int ui_browser__input_window(const char *title, const char *text, char *input,
120 SLsmg_write_nstring((char *)exit_msg, max_len); 122 SLsmg_write_nstring((char *)exit_msg, max_len);
121 SLsmg_refresh(); 123 SLsmg_refresh();
122 124
125 pthread_mutex_unlock(&ui__lock);
126
123 x += 2; 127 x += 2;
124 len = 0; 128 len = 0;
125 key = ui__getch(delay_secs); 129 key = ui__getch(delay_secs);
126 while (key != K_TIMER && key != K_ENTER && key != K_ESC) { 130 while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
131 pthread_mutex_lock(&ui__lock);
132
127 if (key == K_BKSPC) { 133 if (key == K_BKSPC) {
128 if (len == 0) 134 if (len == 0) {
135 pthread_mutex_unlock(&ui__lock);
129 goto next_key; 136 goto next_key;
137 }
130 SLsmg_gotorc(y, x + --len); 138 SLsmg_gotorc(y, x + --len);
131 SLsmg_write_char(' '); 139 SLsmg_write_char(' ');
132 } else { 140 } else {
@@ -136,6 +144,8 @@ int ui_browser__input_window(const char *title, const char *text, char *input,
136 } 144 }
137 SLsmg_refresh(); 145 SLsmg_refresh();
138 146
147 pthread_mutex_unlock(&ui__lock);
148
139 /* XXX more graceful overflow handling needed */ 149 /* XXX more graceful overflow handling needed */
140 if (len == sizeof(buf) - 1) { 150 if (len == sizeof(buf) - 1) {
141 ui_helpline__push("maximum size of symbol name reached!"); 151 ui_helpline__push("maximum size of symbol name reached!");
@@ -174,6 +184,8 @@ int ui__question_window(const char *title, const char *text,
174 t = sep + 1; 184 t = sep + 1;
175 } 185 }
176 186
187 pthread_mutex_lock(&ui__lock);
188
177 max_len += 2; 189 max_len += 2;
178 nr_lines += 4; 190 nr_lines += 4;
179 y = SLtt_Screen_Rows / 2 - nr_lines / 2, 191 y = SLtt_Screen_Rows / 2 - nr_lines / 2,
@@ -195,6 +207,9 @@ int ui__question_window(const char *title, const char *text,
195 SLsmg_gotorc(y + nr_lines - 1, x); 207 SLsmg_gotorc(y + nr_lines - 1, x);
196 SLsmg_write_nstring((char *)exit_msg, max_len); 208 SLsmg_write_nstring((char *)exit_msg, max_len);
197 SLsmg_refresh(); 209 SLsmg_refresh();
210
211 pthread_mutex_unlock(&ui__lock);
212
198 return ui__getch(delay_secs); 213 return ui__getch(delay_secs);
199} 214}
200 215
@@ -215,9 +230,7 @@ static int __ui__warning(const char *title, const char *format, va_list args)
215 if (vasprintf(&s, format, args) > 0) { 230 if (vasprintf(&s, format, args) > 0) {
216 int key; 231 int key;
217 232
218 pthread_mutex_lock(&ui__lock);
219 key = ui__question_window(title, s, "Press any key...", 0); 233 key = ui__question_window(title, s, "Press any key...", 0);
220 pthread_mutex_unlock(&ui__lock);
221 free(s); 234 free(s);
222 return key; 235 return key;
223 } 236 }
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c
index e6d134773d0a..c0b43ee40d95 100644
--- a/tools/perf/util/alias.c
+++ b/tools/perf/util/alias.c
@@ -55,8 +55,7 @@ int split_cmdline(char *cmdline, const char ***argv)
55 src++; 55 src++;
56 c = cmdline[src]; 56 c = cmdline[src];
57 if (!c) { 57 if (!c) {
58 free(*argv); 58 zfree(argv);
59 *argv = NULL;
60 return error("cmdline ends with \\"); 59 return error("cmdline ends with \\");
61 } 60 }
62 } 61 }
@@ -68,8 +67,7 @@ int split_cmdline(char *cmdline, const char ***argv)
68 cmdline[dst] = 0; 67 cmdline[dst] = 0;
69 68
70 if (quoted) { 69 if (quoted) {
71 free(*argv); 70 zfree(argv);
72 *argv = NULL;
73 return error("unclosed quote"); 71 return error("unclosed quote");
74 } 72 }
75 73
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index cf6242c92ee2..469eb679fb9d 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -26,10 +26,10 @@ static int disasm_line__parse(char *line, char **namep, char **rawp);
26 26
27static void ins__delete(struct ins_operands *ops) 27static void ins__delete(struct ins_operands *ops)
28{ 28{
29 free(ops->source.raw); 29 zfree(&ops->source.raw);
30 free(ops->source.name); 30 zfree(&ops->source.name);
31 free(ops->target.raw); 31 zfree(&ops->target.raw);
32 free(ops->target.name); 32 zfree(&ops->target.name);
33} 33}
34 34
35static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, 35static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
@@ -185,8 +185,7 @@ static int lock__parse(struct ins_operands *ops)
185 return 0; 185 return 0;
186 186
187out_free_ops: 187out_free_ops:
188 free(ops->locked.ops); 188 zfree(&ops->locked.ops);
189 ops->locked.ops = NULL;
190 return 0; 189 return 0;
191} 190}
192 191
@@ -205,9 +204,9 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
205 204
206static void lock__delete(struct ins_operands *ops) 205static void lock__delete(struct ins_operands *ops)
207{ 206{
208 free(ops->locked.ops); 207 zfree(&ops->locked.ops);
209 free(ops->target.raw); 208 zfree(&ops->target.raw);
210 free(ops->target.name); 209 zfree(&ops->target.name);
211} 210}
212 211
213static struct ins_ops lock_ops = { 212static struct ins_ops lock_ops = {
@@ -256,8 +255,7 @@ static int mov__parse(struct ins_operands *ops)
256 return 0; 255 return 0;
257 256
258out_free_source: 257out_free_source:
259 free(ops->source.raw); 258 zfree(&ops->source.raw);
260 ops->source.raw = NULL;
261 return -1; 259 return -1;
262} 260}
263 261
@@ -464,17 +462,12 @@ void symbol__annotate_zero_histograms(struct symbol *sym)
464 pthread_mutex_unlock(&notes->lock); 462 pthread_mutex_unlock(&notes->lock);
465} 463}
466 464
467int symbol__inc_addr_samples(struct symbol *sym, struct map *map, 465static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
468 int evidx, u64 addr) 466 struct annotation *notes, int evidx, u64 addr)
469{ 467{
470 unsigned offset; 468 unsigned offset;
471 struct annotation *notes;
472 struct sym_hist *h; 469 struct sym_hist *h;
473 470
474 notes = symbol__annotation(sym);
475 if (notes->src == NULL)
476 return -ENOMEM;
477
478 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); 471 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
479 472
480 if (addr < sym->start || addr > sym->end) 473 if (addr < sym->start || addr > sym->end)
@@ -491,6 +484,33 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
491 return 0; 484 return 0;
492} 485}
493 486
487static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
488 int evidx, u64 addr)
489{
490 struct annotation *notes;
491
492 if (sym == NULL || use_browser != 1 || !sort__has_sym)
493 return 0;
494
495 notes = symbol__annotation(sym);
496 if (notes->src == NULL) {
497 if (symbol__alloc_hist(sym) < 0)
498 return -ENOMEM;
499 }
500
501 return __symbol__inc_addr_samples(sym, map, notes, evidx, addr);
502}
503
504int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx)
505{
506 return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr);
507}
508
509int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
510{
511 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
512}
513
494static void disasm_line__init_ins(struct disasm_line *dl) 514static void disasm_line__init_ins(struct disasm_line *dl)
495{ 515{
496 dl->ins = ins__find(dl->name); 516 dl->ins = ins__find(dl->name);
@@ -538,8 +558,7 @@ static int disasm_line__parse(char *line, char **namep, char **rawp)
538 return 0; 558 return 0;
539 559
540out_free_name: 560out_free_name:
541 free(*namep); 561 zfree(namep);
542 *namep = NULL;
543 return -1; 562 return -1;
544} 563}
545 564
@@ -564,7 +583,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs
564 return dl; 583 return dl;
565 584
566out_free_line: 585out_free_line:
567 free(dl->line); 586 zfree(&dl->line);
568out_delete: 587out_delete:
569 free(dl); 588 free(dl);
570 return NULL; 589 return NULL;
@@ -572,8 +591,8 @@ out_delete:
572 591
573void disasm_line__free(struct disasm_line *dl) 592void disasm_line__free(struct disasm_line *dl)
574{ 593{
575 free(dl->line); 594 zfree(&dl->line);
576 free(dl->name); 595 zfree(&dl->name);
577 if (dl->ins && dl->ins->ops->free) 596 if (dl->ins && dl->ins->ops->free)
578 dl->ins->ops->free(&dl->ops); 597 dl->ins->ops->free(&dl->ops);
579 else 598 else
@@ -900,7 +919,7 @@ fallback:
900 * cache, or is just a kallsyms file, well, lets hope that this 919 * cache, or is just a kallsyms file, well, lets hope that this
901 * DSO is the same as when 'perf record' ran. 920 * DSO is the same as when 'perf record' ran.
902 */ 921 */
903 filename = dso->long_name; 922 filename = (char *)dso->long_name;
904 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", 923 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
905 symbol_conf.symfs, filename); 924 symbol_conf.symfs, filename);
906 free_filename = false; 925 free_filename = false;
@@ -1091,8 +1110,7 @@ static void symbol__free_source_line(struct symbol *sym, int len)
1091 src_line = (void *)src_line + sizeof_src_line; 1110 src_line = (void *)src_line + sizeof_src_line;
1092 } 1111 }
1093 1112
1094 free(notes->src->lines); 1113 zfree(&notes->src->lines);
1095 notes->src->lines = NULL;
1096} 1114}
1097 1115
1098/* Get the filename:line for the colored entries */ 1116/* Get the filename:line for the colored entries */
@@ -1376,3 +1394,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
1376 1394
1377 return 0; 1395 return 0;
1378} 1396}
1397
1398int hist_entry__annotate(struct hist_entry *he, size_t privsize)
1399{
1400 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
1401}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 834b7b57b788..b2aef59d6bb2 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -132,12 +132,17 @@ static inline struct annotation *symbol__annotation(struct symbol *sym)
132 return &a->annotation; 132 return &a->annotation;
133} 133}
134 134
135int symbol__inc_addr_samples(struct symbol *sym, struct map *map, 135int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx);
136 int evidx, u64 addr); 136
137int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr);
138
137int symbol__alloc_hist(struct symbol *sym); 139int symbol__alloc_hist(struct symbol *sym);
138void symbol__annotate_zero_histograms(struct symbol *sym); 140void symbol__annotate_zero_histograms(struct symbol *sym);
139 141
140int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); 142int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
143
144int hist_entry__annotate(struct hist_entry *he, size_t privsize);
145
141int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); 146int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym);
142int symbol__annotate_printf(struct symbol *sym, struct map *map, 147int symbol__annotate_printf(struct symbol *sym, struct map *map,
143 struct perf_evsel *evsel, bool full_paths, 148 struct perf_evsel *evsel, bool full_paths,
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index a92770c98cc7..6baabe63182b 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -89,7 +89,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
89 return raw - build_id; 89 return raw - build_id;
90} 90}
91 91
92char *dso__build_id_filename(struct dso *dso, char *bf, size_t size) 92char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
93{ 93{
94 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 94 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
95 95
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 929f28a7c14d..845ef865eced 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -10,7 +10,7 @@ extern struct perf_tool build_id__mark_dso_hit_ops;
10struct dso; 10struct dso;
11 11
12int build_id__sprintf(const u8 *build_id, int len, char *bf); 12int build_id__sprintf(const u8 *build_id, int len, char *bf);
13char *dso__build_id_filename(struct dso *dso, char *bf, size_t size); 13char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
14 14
15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, 15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
16 struct perf_sample *sample, struct perf_evsel *evsel, 16 struct perf_sample *sample, struct perf_evsel *evsel,
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index e3970e3eaacf..8d9db454f1a9 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -15,8 +15,12 @@
15#include <errno.h> 15#include <errno.h>
16#include <math.h> 16#include <math.h>
17 17
18#include "asm/bug.h"
19
18#include "hist.h" 20#include "hist.h"
19#include "util.h" 21#include "util.h"
22#include "sort.h"
23#include "machine.h"
20#include "callchain.h" 24#include "callchain.h"
21 25
22__thread struct callchain_cursor callchain_cursor; 26__thread struct callchain_cursor callchain_cursor;
@@ -356,19 +360,14 @@ append_chain_children(struct callchain_node *root,
356 /* lookup in childrens */ 360 /* lookup in childrens */
357 while (*p) { 361 while (*p) {
358 s64 ret; 362 s64 ret;
359 struct callchain_list *cnode;
360 363
361 parent = *p; 364 parent = *p;
362 rnode = rb_entry(parent, struct callchain_node, rb_node_in); 365 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
363 cnode = list_first_entry(&rnode->val, struct callchain_list,
364 list);
365 366
366 /* just check first entry */ 367 /* If at least first entry matches, rely to children */
367 ret = match_chain(node, cnode); 368 ret = append_chain(rnode, cursor, period);
368 if (ret == 0) { 369 if (ret == 0)
369 append_chain(rnode, cursor, period);
370 goto inc_children_hit; 370 goto inc_children_hit;
371 }
372 371
373 if (ret < 0) 372 if (ret < 0)
374 p = &parent->rb_left; 373 p = &parent->rb_left;
@@ -389,11 +388,11 @@ append_chain(struct callchain_node *root,
389 struct callchain_cursor *cursor, 388 struct callchain_cursor *cursor,
390 u64 period) 389 u64 period)
391{ 390{
392 struct callchain_cursor_node *curr_snap = cursor->curr;
393 struct callchain_list *cnode; 391 struct callchain_list *cnode;
394 u64 start = cursor->pos; 392 u64 start = cursor->pos;
395 bool found = false; 393 bool found = false;
396 u64 matches; 394 u64 matches;
395 int cmp = 0;
397 396
398 /* 397 /*
399 * Lookup in the current node 398 * Lookup in the current node
@@ -408,7 +407,8 @@ append_chain(struct callchain_node *root,
408 if (!node) 407 if (!node)
409 break; 408 break;
410 409
411 if (match_chain(node, cnode) != 0) 410 cmp = match_chain(node, cnode);
411 if (cmp)
412 break; 412 break;
413 413
414 found = true; 414 found = true;
@@ -418,9 +418,8 @@ append_chain(struct callchain_node *root,
418 418
419 /* matches not, relay no the parent */ 419 /* matches not, relay no the parent */
420 if (!found) { 420 if (!found) {
421 cursor->curr = curr_snap; 421 WARN_ONCE(!cmp, "Chain comparison error\n");
422 cursor->pos = start; 422 return cmp;
423 return -1;
424 } 423 }
425 424
426 matches = cursor->pos - start; 425 matches = cursor->pos - start;
@@ -531,3 +530,24 @@ int callchain_cursor_append(struct callchain_cursor *cursor,
531 530
532 return 0; 531 return 0;
533} 532}
533
534int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent,
535 struct perf_evsel *evsel, struct addr_location *al,
536 int max_stack)
537{
538 if (sample->callchain == NULL)
539 return 0;
540
541 if (symbol_conf.use_callchain || sort__has_parent) {
542 return machine__resolve_callchain(al->machine, evsel, al->thread,
543 sample, parent, al, max_stack);
544 }
545 return 0;
546}
547
548int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
549{
550 if (!symbol_conf.use_callchain)
551 return 0;
552 return callchain_append(he->callchain, &callchain_cursor, sample->period);
553}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 4f7f989876ec..8ad97e9b119f 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -145,10 +145,16 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
145} 145}
146 146
147struct option; 147struct option;
148struct hist_entry;
148 149
149int record_parse_callchain(const char *arg, struct perf_record_opts *opts); 150int record_parse_callchain(const char *arg, struct record_opts *opts);
150int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); 151int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
151int record_callchain_opt(const struct option *opt, const char *arg, int unset); 152int record_callchain_opt(const struct option *opt, const char *arg, int unset);
152 153
154int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent,
155 struct perf_evsel *evsel, struct addr_location *al,
156 int max_stack);
157int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample);
158
153extern const char record_callchain_help[]; 159extern const char record_callchain_help[];
154#endif /* __PERF_CALLCHAIN_H */ 160#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 96bbda1ddb83..88f7be399432 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -81,7 +81,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str)
81 /* 81 /*
82 * check if cgrp is already defined, if so we reuse it 82 * check if cgrp is already defined, if so we reuse it
83 */ 83 */
84 list_for_each_entry(counter, &evlist->entries, node) { 84 evlist__for_each(evlist, counter) {
85 cgrp = counter->cgrp; 85 cgrp = counter->cgrp;
86 if (!cgrp) 86 if (!cgrp)
87 continue; 87 continue;
@@ -110,7 +110,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str)
110 * if add cgroup N, then need to find event N 110 * if add cgroup N, then need to find event N
111 */ 111 */
112 n = 0; 112 n = 0;
113 list_for_each_entry(counter, &evlist->entries, node) { 113 evlist__for_each(evlist, counter) {
114 if (n == nr_cgroups) 114 if (n == nr_cgroups)
115 goto found; 115 goto found;
116 n++; 116 n++;
@@ -133,7 +133,7 @@ void close_cgroup(struct cgroup_sel *cgrp)
133 /* XXX: not reentrant */ 133 /* XXX: not reentrant */
134 if (--cgrp->refcnt == 0) { 134 if (--cgrp->refcnt == 0) {
135 close(cgrp->fd); 135 close(cgrp->fd);
136 free(cgrp->name); 136 zfree(&cgrp->name);
137 free(cgrp); 137 free(cgrp);
138 } 138 }
139} 139}
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 66e44a5019d5..87b8672eb413 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -1,6 +1,7 @@
1#include <linux/kernel.h> 1#include <linux/kernel.h>
2#include "cache.h" 2#include "cache.h"
3#include "color.h" 3#include "color.h"
4#include <math.h>
4 5
5int perf_use_color_default = -1; 6int perf_use_color_default = -1;
6 7
@@ -298,10 +299,10 @@ const char *get_percent_color(double percent)
298 * entries in green - and keep the low overhead places 299 * entries in green - and keep the low overhead places
299 * normal: 300 * normal:
300 */ 301 */
301 if (percent >= MIN_RED) 302 if (fabs(percent) >= MIN_RED)
302 color = PERF_COLOR_RED; 303 color = PERF_COLOR_RED;
303 else { 304 else {
304 if (percent > MIN_GREEN) 305 if (fabs(percent) > MIN_GREEN)
305 color = PERF_COLOR_GREEN; 306 color = PERF_COLOR_GREEN;
306 } 307 }
307 return color; 308 return color;
@@ -318,15 +319,19 @@ int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
318 return r; 319 return r;
319} 320}
320 321
322int value_color_snprintf(char *bf, size_t size, const char *fmt, double value)
323{
324 const char *color = get_percent_color(value);
325 return color_snprintf(bf, size, color, fmt, value);
326}
327
321int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...) 328int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...)
322{ 329{
323 va_list args; 330 va_list args;
324 double percent; 331 double percent;
325 const char *color;
326 332
327 va_start(args, fmt); 333 va_start(args, fmt);
328 percent = va_arg(args, double); 334 percent = va_arg(args, double);
329 va_end(args); 335 va_end(args);
330 color = get_percent_color(percent); 336 return value_color_snprintf(bf, size, fmt, percent);
331 return color_snprintf(bf, size, color, fmt, percent);
332} 337}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index fced3840e99c..7ff30a62a132 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -39,6 +39,7 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
39int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...); 39int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...);
40int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); 40int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); 41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
42int value_color_snprintf(char *bf, size_t size, const char *fmt, double value);
42int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...); 43int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...);
43int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 44int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
44const char *get_percent_color(double percent); 45const char *get_percent_color(double percent);
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c
index ee0df0e24cdb..f9e777629e21 100644
--- a/tools/perf/util/comm.c
+++ b/tools/perf/util/comm.c
@@ -21,7 +21,7 @@ static void comm_str__put(struct comm_str *cs)
21{ 21{
22 if (!--cs->ref) { 22 if (!--cs->ref) {
23 rb_erase(&cs->rb_node, &comm_str_root); 23 rb_erase(&cs->rb_node, &comm_str_root);
24 free(cs->str); 24 zfree(&cs->str);
25 free(cs); 25 free(cs);
26 } 26 }
27} 27}
@@ -94,19 +94,20 @@ struct comm *comm__new(const char *str, u64 timestamp)
94 return comm; 94 return comm;
95} 95}
96 96
97void comm__override(struct comm *comm, const char *str, u64 timestamp) 97int comm__override(struct comm *comm, const char *str, u64 timestamp)
98{ 98{
99 struct comm_str *old = comm->comm_str; 99 struct comm_str *new, *old = comm->comm_str;
100 100
101 comm->comm_str = comm_str__findnew(str, &comm_str_root); 101 new = comm_str__findnew(str, &comm_str_root);
102 if (!comm->comm_str) { 102 if (!new)
103 comm->comm_str = old; 103 return -ENOMEM;
104 return;
105 }
106 104
107 comm->start = timestamp; 105 comm_str__get(new);
108 comm_str__get(comm->comm_str);
109 comm_str__put(old); 106 comm_str__put(old);
107 comm->comm_str = new;
108 comm->start = timestamp;
109
110 return 0;
110} 111}
111 112
112void comm__free(struct comm *comm) 113void comm__free(struct comm *comm)
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h
index 7a86e5656710..fac5bd51befc 100644
--- a/tools/perf/util/comm.h
+++ b/tools/perf/util/comm.h
@@ -16,6 +16,6 @@ struct comm {
16void comm__free(struct comm *comm); 16void comm__free(struct comm *comm);
17struct comm *comm__new(const char *str, u64 timestamp); 17struct comm *comm__new(const char *str, u64 timestamp);
18const char *comm__str(const struct comm *comm); 18const char *comm__str(const struct comm *comm);
19void comm__override(struct comm *comm, const char *str, u64 timestamp); 19int comm__override(struct comm *comm, const char *str, u64 timestamp);
20 20
21#endif /* __PERF_COMM_H */ 21#endif /* __PERF_COMM_H */
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 7d09faf85cf1..1fbcd8bdc11b 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -118,3 +118,9 @@ void perf_data_file__close(struct perf_data_file *file)
118{ 118{
119 close(file->fd); 119 close(file->fd);
120} 120}
121
122ssize_t perf_data_file__write(struct perf_data_file *file,
123 void *buf, size_t size)
124{
125 return writen(file->fd, buf, size);
126}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
index 8c2df80152a5..2b15d0c95c7f 100644
--- a/tools/perf/util/data.h
+++ b/tools/perf/util/data.h
@@ -9,12 +9,12 @@ enum perf_data_mode {
9}; 9};
10 10
11struct perf_data_file { 11struct perf_data_file {
12 const char *path; 12 const char *path;
13 int fd; 13 int fd;
14 bool is_pipe; 14 bool is_pipe;
15 bool force; 15 bool force;
16 unsigned long size; 16 unsigned long size;
17 enum perf_data_mode mode; 17 enum perf_data_mode mode;
18}; 18};
19 19
20static inline bool perf_data_file__is_read(struct perf_data_file *file) 20static inline bool perf_data_file__is_read(struct perf_data_file *file)
@@ -44,5 +44,7 @@ static inline unsigned long perf_data_file__size(struct perf_data_file *file)
44 44
45int perf_data_file__open(struct perf_data_file *file); 45int perf_data_file__open(struct perf_data_file *file);
46void perf_data_file__close(struct perf_data_file *file); 46void perf_data_file__close(struct perf_data_file *file);
47ssize_t perf_data_file__write(struct perf_data_file *file,
48 void *buf, size_t size);
47 49
48#endif /* __PERF_DATA_H */ 50#endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 399e74c34c1a..299b55586502 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -16,23 +16,46 @@
16int verbose; 16int verbose;
17bool dump_trace = false, quiet = false; 17bool dump_trace = false, quiet = false;
18 18
19int eprintf(int level, const char *fmt, ...) 19static int _eprintf(int level, const char *fmt, va_list args)
20{ 20{
21 va_list args;
22 int ret = 0; 21 int ret = 0;
23 22
24 if (verbose >= level) { 23 if (verbose >= level) {
25 va_start(args, fmt);
26 if (use_browser >= 1) 24 if (use_browser >= 1)
27 ui_helpline__vshow(fmt, args); 25 ui_helpline__vshow(fmt, args);
28 else 26 else
29 ret = vfprintf(stderr, fmt, args); 27 ret = vfprintf(stderr, fmt, args);
30 va_end(args);
31 } 28 }
32 29
33 return ret; 30 return ret;
34} 31}
35 32
33int eprintf(int level, const char *fmt, ...)
34{
35 va_list args;
36 int ret;
37
38 va_start(args, fmt);
39 ret = _eprintf(level, fmt, args);
40 va_end(args);
41
42 return ret;
43}
44
45/*
46 * Overloading libtraceevent standard info print
47 * function, display with -v in perf.
48 */
49void pr_stat(const char *fmt, ...)
50{
51 va_list args;
52
53 va_start(args, fmt);
54 _eprintf(1, fmt, args);
55 va_end(args);
56 eprintf(1, "\n");
57}
58
36int dump_printf(const char *fmt, ...) 59int dump_printf(const char *fmt, ...)
37{ 60{
38 va_list args; 61 va_list args;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index efbd98805ad0..443694c36b03 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -17,4 +17,6 @@ void trace_event(union perf_event *event);
17int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); 17int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
18int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 18int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
19 19
20void pr_stat(const char *fmt, ...);
21
20#endif /* __PERF_DEBUG_H */ 22#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index af4c687cc49b..4045d086d9d9 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -28,8 +28,9 @@ char dso__symtab_origin(const struct dso *dso)
28 return origin[dso->symtab_type]; 28 return origin[dso->symtab_type];
29} 29}
30 30
31int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, 31int dso__read_binary_type_filename(const struct dso *dso,
32 char *root_dir, char *file, size_t size) 32 enum dso_binary_type type,
33 char *root_dir, char *filename, size_t size)
33{ 34{
34 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 35 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
35 int ret = 0; 36 int ret = 0;
@@ -38,36 +39,36 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
38 case DSO_BINARY_TYPE__DEBUGLINK: { 39 case DSO_BINARY_TYPE__DEBUGLINK: {
39 char *debuglink; 40 char *debuglink;
40 41
41 strncpy(file, dso->long_name, size); 42 strncpy(filename, dso->long_name, size);
42 debuglink = file + dso->long_name_len; 43 debuglink = filename + dso->long_name_len;
43 while (debuglink != file && *debuglink != '/') 44 while (debuglink != filename && *debuglink != '/')
44 debuglink--; 45 debuglink--;
45 if (*debuglink == '/') 46 if (*debuglink == '/')
46 debuglink++; 47 debuglink++;
47 filename__read_debuglink(dso->long_name, debuglink, 48 filename__read_debuglink(dso->long_name, debuglink,
48 size - (debuglink - file)); 49 size - (debuglink - filename));
49 } 50 }
50 break; 51 break;
51 case DSO_BINARY_TYPE__BUILD_ID_CACHE: 52 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
52 /* skip the locally configured cache if a symfs is given */ 53 /* skip the locally configured cache if a symfs is given */
53 if (symbol_conf.symfs[0] || 54 if (symbol_conf.symfs[0] ||
54 (dso__build_id_filename(dso, file, size) == NULL)) 55 (dso__build_id_filename(dso, filename, size) == NULL))
55 ret = -1; 56 ret = -1;
56 break; 57 break;
57 58
58 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 59 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
59 snprintf(file, size, "%s/usr/lib/debug%s.debug", 60 snprintf(filename, size, "%s/usr/lib/debug%s.debug",
60 symbol_conf.symfs, dso->long_name); 61 symbol_conf.symfs, dso->long_name);
61 break; 62 break;
62 63
63 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 64 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
64 snprintf(file, size, "%s/usr/lib/debug%s", 65 snprintf(filename, size, "%s/usr/lib/debug%s",
65 symbol_conf.symfs, dso->long_name); 66 symbol_conf.symfs, dso->long_name);
66 break; 67 break;
67 68
68 case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 69 case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
69 { 70 {
70 char *last_slash; 71 const char *last_slash;
71 size_t len; 72 size_t len;
72 size_t dir_size; 73 size_t dir_size;
73 74
@@ -75,14 +76,14 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
75 while (last_slash != dso->long_name && *last_slash != '/') 76 while (last_slash != dso->long_name && *last_slash != '/')
76 last_slash--; 77 last_slash--;
77 78
78 len = scnprintf(file, size, "%s", symbol_conf.symfs); 79 len = scnprintf(filename, size, "%s", symbol_conf.symfs);
79 dir_size = last_slash - dso->long_name + 2; 80 dir_size = last_slash - dso->long_name + 2;
80 if (dir_size > (size - len)) { 81 if (dir_size > (size - len)) {
81 ret = -1; 82 ret = -1;
82 break; 83 break;
83 } 84 }
84 len += scnprintf(file + len, dir_size, "%s", dso->long_name); 85 len += scnprintf(filename + len, dir_size, "%s", dso->long_name);
85 len += scnprintf(file + len , size - len, ".debug%s", 86 len += scnprintf(filename + len , size - len, ".debug%s",
86 last_slash); 87 last_slash);
87 break; 88 break;
88 } 89 }
@@ -96,7 +97,7 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
96 build_id__sprintf(dso->build_id, 97 build_id__sprintf(dso->build_id,
97 sizeof(dso->build_id), 98 sizeof(dso->build_id),
98 build_id_hex); 99 build_id_hex);
99 snprintf(file, size, 100 snprintf(filename, size,
100 "%s/usr/lib/debug/.build-id/%.2s/%s.debug", 101 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
101 symbol_conf.symfs, build_id_hex, build_id_hex + 2); 102 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
102 break; 103 break;
@@ -104,23 +105,23 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
104 case DSO_BINARY_TYPE__VMLINUX: 105 case DSO_BINARY_TYPE__VMLINUX:
105 case DSO_BINARY_TYPE__GUEST_VMLINUX: 106 case DSO_BINARY_TYPE__GUEST_VMLINUX:
106 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 107 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
107 snprintf(file, size, "%s%s", 108 snprintf(filename, size, "%s%s",
108 symbol_conf.symfs, dso->long_name); 109 symbol_conf.symfs, dso->long_name);
109 break; 110 break;
110 111
111 case DSO_BINARY_TYPE__GUEST_KMODULE: 112 case DSO_BINARY_TYPE__GUEST_KMODULE:
112 snprintf(file, size, "%s%s%s", symbol_conf.symfs, 113 snprintf(filename, size, "%s%s%s", symbol_conf.symfs,
113 root_dir, dso->long_name); 114 root_dir, dso->long_name);
114 break; 115 break;
115 116
116 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 117 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
117 snprintf(file, size, "%s%s", symbol_conf.symfs, 118 snprintf(filename, size, "%s%s", symbol_conf.symfs,
118 dso->long_name); 119 dso->long_name);
119 break; 120 break;
120 121
121 case DSO_BINARY_TYPE__KCORE: 122 case DSO_BINARY_TYPE__KCORE:
122 case DSO_BINARY_TYPE__GUEST_KCORE: 123 case DSO_BINARY_TYPE__GUEST_KCORE:
123 snprintf(file, size, "%s", dso->long_name); 124 snprintf(filename, size, "%s", dso->long_name);
124 break; 125 break;
125 126
126 default: 127 default:
@@ -137,19 +138,18 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
137 138
138static int open_dso(struct dso *dso, struct machine *machine) 139static int open_dso(struct dso *dso, struct machine *machine)
139{ 140{
140 char *root_dir = (char *) "";
141 char *name;
142 int fd; 141 int fd;
142 char *root_dir = (char *)"";
143 char *name = malloc(PATH_MAX);
143 144
144 name = malloc(PATH_MAX);
145 if (!name) 145 if (!name)
146 return -ENOMEM; 146 return -ENOMEM;
147 147
148 if (machine) 148 if (machine)
149 root_dir = machine->root_dir; 149 root_dir = machine->root_dir;
150 150
151 if (dso__binary_type_file(dso, dso->data_type, 151 if (dso__read_binary_type_filename(dso, dso->binary_type,
152 root_dir, name, PATH_MAX)) { 152 root_dir, name, PATH_MAX)) {
153 free(name); 153 free(name);
154 return -EINVAL; 154 return -EINVAL;
155 } 155 }
@@ -161,26 +161,26 @@ static int open_dso(struct dso *dso, struct machine *machine)
161 161
162int dso__data_fd(struct dso *dso, struct machine *machine) 162int dso__data_fd(struct dso *dso, struct machine *machine)
163{ 163{
164 static enum dso_binary_type binary_type_data[] = { 164 enum dso_binary_type binary_type_data[] = {
165 DSO_BINARY_TYPE__BUILD_ID_CACHE, 165 DSO_BINARY_TYPE__BUILD_ID_CACHE,
166 DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 166 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
167 DSO_BINARY_TYPE__NOT_FOUND, 167 DSO_BINARY_TYPE__NOT_FOUND,
168 }; 168 };
169 int i = 0; 169 int i = 0;
170 170
171 if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND) 171 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND)
172 return open_dso(dso, machine); 172 return open_dso(dso, machine);
173 173
174 do { 174 do {
175 int fd; 175 int fd;
176 176
177 dso->data_type = binary_type_data[i++]; 177 dso->binary_type = binary_type_data[i++];
178 178
179 fd = open_dso(dso, machine); 179 fd = open_dso(dso, machine);
180 if (fd >= 0) 180 if (fd >= 0)
181 return fd; 181 return fd;
182 182
183 } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND); 183 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
184 184
185 return -EINVAL; 185 return -EINVAL;
186} 186}
@@ -200,11 +200,10 @@ dso_cache__free(struct rb_root *root)
200 } 200 }
201} 201}
202 202
203static struct dso_cache* 203static struct dso_cache *dso_cache__find(const struct rb_root *root, u64 offset)
204dso_cache__find(struct rb_root *root, u64 offset)
205{ 204{
206 struct rb_node **p = &root->rb_node; 205 struct rb_node * const *p = &root->rb_node;
207 struct rb_node *parent = NULL; 206 const struct rb_node *parent = NULL;
208 struct dso_cache *cache; 207 struct dso_cache *cache;
209 208
210 while (*p != NULL) { 209 while (*p != NULL) {
@@ -379,32 +378,63 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
379 * processing we had no idea this was the kernel dso. 378 * processing we had no idea this was the kernel dso.
380 */ 379 */
381 if (dso != NULL) { 380 if (dso != NULL) {
382 dso__set_short_name(dso, short_name); 381 dso__set_short_name(dso, short_name, false);
383 dso->kernel = dso_type; 382 dso->kernel = dso_type;
384 } 383 }
385 384
386 return dso; 385 return dso;
387} 386}
388 387
389void dso__set_long_name(struct dso *dso, char *name) 388void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
390{ 389{
391 if (name == NULL) 390 if (name == NULL)
392 return; 391 return;
393 dso->long_name = name; 392
394 dso->long_name_len = strlen(name); 393 if (dso->long_name_allocated)
394 free((char *)dso->long_name);
395
396 dso->long_name = name;
397 dso->long_name_len = strlen(name);
398 dso->long_name_allocated = name_allocated;
395} 399}
396 400
397void dso__set_short_name(struct dso *dso, const char *name) 401void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
398{ 402{
399 if (name == NULL) 403 if (name == NULL)
400 return; 404 return;
401 dso->short_name = name; 405
402 dso->short_name_len = strlen(name); 406 if (dso->short_name_allocated)
407 free((char *)dso->short_name);
408
409 dso->short_name = name;
410 dso->short_name_len = strlen(name);
411 dso->short_name_allocated = name_allocated;
403} 412}
404 413
405static void dso__set_basename(struct dso *dso) 414static void dso__set_basename(struct dso *dso)
406{ 415{
407 dso__set_short_name(dso, basename(dso->long_name)); 416 /*
417 * basename() may modify path buffer, so we must pass
418 * a copy.
419 */
420 char *base, *lname = strdup(dso->long_name);
421
422 if (!lname)
423 return;
424
425 /*
426 * basename() may return a pointer to internal
427 * storage which is reused in subsequent calls
428 * so copy the result.
429 */
430 base = strdup(basename(lname));
431
432 free(lname);
433
434 if (!base)
435 return;
436
437 dso__set_short_name(dso, base, true);
408} 438}
409 439
410int dso__name_len(const struct dso *dso) 440int dso__name_len(const struct dso *dso)
@@ -439,18 +469,19 @@ struct dso *dso__new(const char *name)
439 if (dso != NULL) { 469 if (dso != NULL) {
440 int i; 470 int i;
441 strcpy(dso->name, name); 471 strcpy(dso->name, name);
442 dso__set_long_name(dso, dso->name); 472 dso__set_long_name(dso, dso->name, false);
443 dso__set_short_name(dso, dso->name); 473 dso__set_short_name(dso, dso->name, false);
444 for (i = 0; i < MAP__NR_TYPES; ++i) 474 for (i = 0; i < MAP__NR_TYPES; ++i)
445 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 475 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
446 dso->cache = RB_ROOT; 476 dso->cache = RB_ROOT;
447 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 477 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
448 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; 478 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
449 dso->loaded = 0; 479 dso->loaded = 0;
450 dso->rel = 0; 480 dso->rel = 0;
451 dso->sorted_by_name = 0; 481 dso->sorted_by_name = 0;
452 dso->has_build_id = 0; 482 dso->has_build_id = 0;
453 dso->has_srcline = 1; 483 dso->has_srcline = 1;
484 dso->a2l_fails = 1;
454 dso->kernel = DSO_TYPE_USER; 485 dso->kernel = DSO_TYPE_USER;
455 dso->needs_swap = DSO_SWAP__UNSET; 486 dso->needs_swap = DSO_SWAP__UNSET;
456 INIT_LIST_HEAD(&dso->node); 487 INIT_LIST_HEAD(&dso->node);
@@ -464,11 +495,20 @@ void dso__delete(struct dso *dso)
464 int i; 495 int i;
465 for (i = 0; i < MAP__NR_TYPES; ++i) 496 for (i = 0; i < MAP__NR_TYPES; ++i)
466 symbols__delete(&dso->symbols[i]); 497 symbols__delete(&dso->symbols[i]);
467 if (dso->sname_alloc) 498
468 free((char *)dso->short_name); 499 if (dso->short_name_allocated) {
469 if (dso->lname_alloc) 500 zfree((char **)&dso->short_name);
470 free(dso->long_name); 501 dso->short_name_allocated = false;
502 }
503
504 if (dso->long_name_allocated) {
505 zfree((char **)&dso->long_name);
506 dso->long_name_allocated = false;
507 }
508
471 dso_cache__free(&dso->cache); 509 dso_cache__free(&dso->cache);
510 dso__free_a2l(dso);
511 zfree(&dso->symsrc_filename);
472 free(dso); 512 free(dso);
473} 513}
474 514
@@ -543,7 +583,7 @@ void dsos__add(struct list_head *head, struct dso *dso)
543 list_add_tail(&dso->node, head); 583 list_add_tail(&dso->node, head);
544} 584}
545 585
546struct dso *dsos__find(struct list_head *head, const char *name, bool cmp_short) 586struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short)
547{ 587{
548 struct dso *pos; 588 struct dso *pos;
549 589
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 9ac666abbe7e..cd7d6f078cdd 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -77,23 +77,26 @@ struct dso {
77 struct rb_root symbols[MAP__NR_TYPES]; 77 struct rb_root symbols[MAP__NR_TYPES];
78 struct rb_root symbol_names[MAP__NR_TYPES]; 78 struct rb_root symbol_names[MAP__NR_TYPES];
79 struct rb_root cache; 79 struct rb_root cache;
80 void *a2l;
81 char *symsrc_filename;
82 unsigned int a2l_fails;
80 enum dso_kernel_type kernel; 83 enum dso_kernel_type kernel;
81 enum dso_swap_type needs_swap; 84 enum dso_swap_type needs_swap;
82 enum dso_binary_type symtab_type; 85 enum dso_binary_type symtab_type;
83 enum dso_binary_type data_type; 86 enum dso_binary_type binary_type;
84 u8 adjust_symbols:1; 87 u8 adjust_symbols:1;
85 u8 has_build_id:1; 88 u8 has_build_id:1;
86 u8 has_srcline:1; 89 u8 has_srcline:1;
87 u8 hit:1; 90 u8 hit:1;
88 u8 annotate_warned:1; 91 u8 annotate_warned:1;
89 u8 sname_alloc:1; 92 u8 short_name_allocated:1;
90 u8 lname_alloc:1; 93 u8 long_name_allocated:1;
91 u8 sorted_by_name; 94 u8 sorted_by_name;
92 u8 loaded; 95 u8 loaded;
93 u8 rel; 96 u8 rel;
94 u8 build_id[BUILD_ID_SIZE]; 97 u8 build_id[BUILD_ID_SIZE];
95 const char *short_name; 98 const char *short_name;
96 char *long_name; 99 const char *long_name;
97 u16 long_name_len; 100 u16 long_name_len;
98 u16 short_name_len; 101 u16 short_name_len;
99 char name[0]; 102 char name[0];
@@ -107,8 +110,8 @@ static inline void dso__set_loaded(struct dso *dso, enum map_type type)
107struct dso *dso__new(const char *name); 110struct dso *dso__new(const char *name);
108void dso__delete(struct dso *dso); 111void dso__delete(struct dso *dso);
109 112
110void dso__set_short_name(struct dso *dso, const char *name); 113void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated);
111void dso__set_long_name(struct dso *dso, char *name); 114void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated);
112 115
113int dso__name_len(const struct dso *dso); 116int dso__name_len(const struct dso *dso);
114 117
@@ -125,8 +128,8 @@ void dso__read_running_kernel_build_id(struct dso *dso,
125int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir); 128int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
126 129
127char dso__symtab_origin(const struct dso *dso); 130char dso__symtab_origin(const struct dso *dso);
128int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, 131int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
129 char *root_dir, char *file, size_t size); 132 char *root_dir, char *filename, size_t size);
130 133
131int dso__data_fd(struct dso *dso, struct machine *machine); 134int dso__data_fd(struct dso *dso, struct machine *machine);
132ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 135ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
@@ -140,7 +143,7 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
140 const char *short_name, int dso_type); 143 const char *short_name, int dso_type);
141 144
142void dsos__add(struct list_head *head, struct dso *dso); 145void dsos__add(struct list_head *head, struct dso *dso);
143struct dso *dsos__find(struct list_head *head, const char *name, 146struct dso *dsos__find(const struct list_head *head, const char *name,
144 bool cmp_short); 147 bool cmp_short);
145struct dso *__dsos__findnew(struct list_head *head, const char *name); 148struct dso *__dsos__findnew(struct list_head *head, const char *name);
146bool __dsos__read_build_ids(struct list_head *head, bool with_hits); 149bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
@@ -156,14 +159,16 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
156 159
157static inline bool dso__is_vmlinux(struct dso *dso) 160static inline bool dso__is_vmlinux(struct dso *dso)
158{ 161{
159 return dso->data_type == DSO_BINARY_TYPE__VMLINUX || 162 return dso->binary_type == DSO_BINARY_TYPE__VMLINUX ||
160 dso->data_type == DSO_BINARY_TYPE__GUEST_VMLINUX; 163 dso->binary_type == DSO_BINARY_TYPE__GUEST_VMLINUX;
161} 164}
162 165
163static inline bool dso__is_kcore(struct dso *dso) 166static inline bool dso__is_kcore(struct dso *dso)
164{ 167{
165 return dso->data_type == DSO_BINARY_TYPE__KCORE || 168 return dso->binary_type == DSO_BINARY_TYPE__KCORE ||
166 dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE; 169 dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE;
167} 170}
168 171
172void dso__free_a2l(struct dso *dso);
173
169#endif /* __PERF_DSO */ 174#endif /* __PERF_DSO */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index bb788c109fe6..1fc1c2f04772 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -7,6 +7,7 @@
7#include "strlist.h" 7#include "strlist.h"
8#include "thread.h" 8#include "thread.h"
9#include "thread_map.h" 9#include "thread_map.h"
10#include "symbol/kallsyms.h"
10 11
11static const char *perf_event__names[] = { 12static const char *perf_event__names[] = {
12 [0] = "TOTAL", 13 [0] = "TOTAL",
@@ -105,8 +106,12 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
105 106
106 memset(&event->comm, 0, sizeof(event->comm)); 107 memset(&event->comm, 0, sizeof(event->comm));
107 108
108 tgid = perf_event__get_comm_tgid(pid, event->comm.comm, 109 if (machine__is_host(machine))
109 sizeof(event->comm.comm)); 110 tgid = perf_event__get_comm_tgid(pid, event->comm.comm,
111 sizeof(event->comm.comm));
112 else
113 tgid = machine->pid;
114
110 if (tgid < 0) 115 if (tgid < 0)
111 goto out; 116 goto out;
112 117
@@ -128,7 +133,11 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
128 goto out; 133 goto out;
129 } 134 }
130 135
131 snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 136 if (machine__is_default_guest(machine))
137 return 0;
138
139 snprintf(filename, sizeof(filename), "%s/proc/%d/task",
140 machine->root_dir, pid);
132 141
133 tasks = opendir(filename); 142 tasks = opendir(filename);
134 if (tasks == NULL) { 143 if (tasks == NULL) {
@@ -166,18 +175,22 @@ out:
166 return tgid; 175 return tgid;
167} 176}
168 177
169static int perf_event__synthesize_mmap_events(struct perf_tool *tool, 178int perf_event__synthesize_mmap_events(struct perf_tool *tool,
170 union perf_event *event, 179 union perf_event *event,
171 pid_t pid, pid_t tgid, 180 pid_t pid, pid_t tgid,
172 perf_event__handler_t process, 181 perf_event__handler_t process,
173 struct machine *machine, 182 struct machine *machine,
174 bool mmap_data) 183 bool mmap_data)
175{ 184{
176 char filename[PATH_MAX]; 185 char filename[PATH_MAX];
177 FILE *fp; 186 FILE *fp;
178 int rc = 0; 187 int rc = 0;
179 188
180 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); 189 if (machine__is_default_guest(machine))
190 return 0;
191
192 snprintf(filename, sizeof(filename), "%s/proc/%d/maps",
193 machine->root_dir, pid);
181 194
182 fp = fopen(filename, "r"); 195 fp = fopen(filename, "r");
183 if (fp == NULL) { 196 if (fp == NULL) {
@@ -217,7 +230,10 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
217 /* 230 /*
218 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 231 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
219 */ 232 */
220 event->header.misc = PERF_RECORD_MISC_USER; 233 if (machine__is_host(machine))
234 event->header.misc = PERF_RECORD_MISC_USER;
235 else
236 event->header.misc = PERF_RECORD_MISC_GUEST_USER;
221 237
222 if (prot[2] != 'x') { 238 if (prot[2] != 'x') {
223 if (!mmap_data || prot[0] != 'r') 239 if (!mmap_data || prot[0] != 'r')
@@ -386,6 +402,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
386 struct machine *machine, bool mmap_data) 402 struct machine *machine, bool mmap_data)
387{ 403{
388 DIR *proc; 404 DIR *proc;
405 char proc_path[PATH_MAX];
389 struct dirent dirent, *next; 406 struct dirent dirent, *next;
390 union perf_event *comm_event, *mmap_event; 407 union perf_event *comm_event, *mmap_event;
391 int err = -1; 408 int err = -1;
@@ -398,7 +415,12 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
398 if (mmap_event == NULL) 415 if (mmap_event == NULL)
399 goto out_free_comm; 416 goto out_free_comm;
400 417
401 proc = opendir("/proc"); 418 if (machine__is_default_guest(machine))
419 return 0;
420
421 snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
422 proc = opendir(proc_path);
423
402 if (proc == NULL) 424 if (proc == NULL)
403 goto out_free_mmap; 425 goto out_free_mmap;
404 426
@@ -637,6 +659,7 @@ void thread__find_addr_map(struct thread *thread,
637 struct map_groups *mg = &thread->mg; 659 struct map_groups *mg = &thread->mg;
638 bool load_map = false; 660 bool load_map = false;
639 661
662 al->machine = machine;
640 al->thread = thread; 663 al->thread = thread;
641 al->addr = addr; 664 al->addr = addr;
642 al->cpumode = cpumode; 665 al->cpumode = cpumode;
@@ -657,15 +680,10 @@ void thread__find_addr_map(struct thread *thread,
657 al->level = 'g'; 680 al->level = 'g';
658 mg = &machine->kmaps; 681 mg = &machine->kmaps;
659 load_map = true; 682 load_map = true;
683 } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) {
684 al->level = 'u';
660 } else { 685 } else {
661 /* 686 al->level = 'H';
662 * 'u' means guest os user space.
663 * TODO: We don't support guest user space. Might support late.
664 */
665 if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest)
666 al->level = 'u';
667 else
668 al->level = 'H';
669 al->map = NULL; 687 al->map = NULL;
670 688
671 if ((cpumode == PERF_RECORD_MISC_GUEST_USER || 689 if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
@@ -732,8 +750,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
732 if (thread == NULL) 750 if (thread == NULL)
733 return -1; 751 return -1;
734 752
735 if (symbol_conf.comm_list && 753 if (thread__is_filtered(thread))
736 !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread)))
737 goto out_filtered; 754 goto out_filtered;
738 755
739 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); 756 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 30fec9901e44..faf6e219be21 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -266,6 +266,13 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
266 const struct perf_sample *sample, 266 const struct perf_sample *sample,
267 bool swapped); 267 bool swapped);
268 268
269int perf_event__synthesize_mmap_events(struct perf_tool *tool,
270 union perf_event *event,
271 pid_t pid, pid_t tgid,
272 perf_event__handler_t process,
273 struct machine *machine,
274 bool mmap_data);
275
269size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); 276size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
270size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); 277size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
271size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); 278size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index bbc746aa5716..40bd2c04df8a 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -7,7 +7,7 @@
7 * Released under the GPL v2. (and only v2, not any later version) 7 * Released under the GPL v2. (and only v2, not any later version)
8 */ 8 */
9#include "util.h" 9#include "util.h"
10#include <lk/debugfs.h> 10#include <api/fs/debugfs.h>
11#include <poll.h> 11#include <poll.h>
12#include "cpumap.h" 12#include "cpumap.h"
13#include "thread_map.h" 13#include "thread_map.h"
@@ -81,7 +81,7 @@ static void perf_evlist__update_id_pos(struct perf_evlist *evlist)
81{ 81{
82 struct perf_evsel *evsel; 82 struct perf_evsel *evsel;
83 83
84 list_for_each_entry(evsel, &evlist->entries, node) 84 evlist__for_each(evlist, evsel)
85 perf_evsel__calc_id_pos(evsel); 85 perf_evsel__calc_id_pos(evsel);
86 86
87 perf_evlist__set_id_pos(evlist); 87 perf_evlist__set_id_pos(evlist);
@@ -91,7 +91,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist)
91{ 91{
92 struct perf_evsel *pos, *n; 92 struct perf_evsel *pos, *n;
93 93
94 list_for_each_entry_safe(pos, n, &evlist->entries, node) { 94 evlist__for_each_safe(evlist, n, pos) {
95 list_del_init(&pos->node); 95 list_del_init(&pos->node);
96 perf_evsel__delete(pos); 96 perf_evsel__delete(pos);
97 } 97 }
@@ -101,14 +101,18 @@ static void perf_evlist__purge(struct perf_evlist *evlist)
101 101
102void perf_evlist__exit(struct perf_evlist *evlist) 102void perf_evlist__exit(struct perf_evlist *evlist)
103{ 103{
104 free(evlist->mmap); 104 zfree(&evlist->mmap);
105 free(evlist->pollfd); 105 zfree(&evlist->pollfd);
106 evlist->mmap = NULL;
107 evlist->pollfd = NULL;
108} 106}
109 107
110void perf_evlist__delete(struct perf_evlist *evlist) 108void perf_evlist__delete(struct perf_evlist *evlist)
111{ 109{
110 perf_evlist__munmap(evlist);
111 perf_evlist__close(evlist);
112 cpu_map__delete(evlist->cpus);
113 thread_map__delete(evlist->threads);
114 evlist->cpus = NULL;
115 evlist->threads = NULL;
112 perf_evlist__purge(evlist); 116 perf_evlist__purge(evlist);
113 perf_evlist__exit(evlist); 117 perf_evlist__exit(evlist);
114 free(evlist); 118 free(evlist);
@@ -144,7 +148,7 @@ void __perf_evlist__set_leader(struct list_head *list)
144 148
145 leader->nr_members = evsel->idx - leader->idx + 1; 149 leader->nr_members = evsel->idx - leader->idx + 1;
146 150
147 list_for_each_entry(evsel, list, node) { 151 __evlist__for_each(list, evsel) {
148 evsel->leader = leader; 152 evsel->leader = leader;
149 } 153 }
150} 154}
@@ -203,7 +207,7 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist,
203 return 0; 207 return 0;
204 208
205out_delete_partial_list: 209out_delete_partial_list:
206 list_for_each_entry_safe(evsel, n, &head, node) 210 __evlist__for_each_safe(&head, n, evsel)
207 perf_evsel__delete(evsel); 211 perf_evsel__delete(evsel);
208 return -1; 212 return -1;
209} 213}
@@ -224,7 +228,7 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
224{ 228{
225 struct perf_evsel *evsel; 229 struct perf_evsel *evsel;
226 230
227 list_for_each_entry(evsel, &evlist->entries, node) { 231 evlist__for_each(evlist, evsel) {
228 if (evsel->attr.type == PERF_TYPE_TRACEPOINT && 232 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
229 (int)evsel->attr.config == id) 233 (int)evsel->attr.config == id)
230 return evsel; 234 return evsel;
@@ -239,7 +243,7 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
239{ 243{
240 struct perf_evsel *evsel; 244 struct perf_evsel *evsel;
241 245
242 list_for_each_entry(evsel, &evlist->entries, node) { 246 evlist__for_each(evlist, evsel) {
243 if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) && 247 if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) &&
244 (strcmp(evsel->name, name) == 0)) 248 (strcmp(evsel->name, name) == 0))
245 return evsel; 249 return evsel;
@@ -269,7 +273,7 @@ void perf_evlist__disable(struct perf_evlist *evlist)
269 int nr_threads = thread_map__nr(evlist->threads); 273 int nr_threads = thread_map__nr(evlist->threads);
270 274
271 for (cpu = 0; cpu < nr_cpus; cpu++) { 275 for (cpu = 0; cpu < nr_cpus; cpu++) {
272 list_for_each_entry(pos, &evlist->entries, node) { 276 evlist__for_each(evlist, pos) {
273 if (!perf_evsel__is_group_leader(pos) || !pos->fd) 277 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
274 continue; 278 continue;
275 for (thread = 0; thread < nr_threads; thread++) 279 for (thread = 0; thread < nr_threads; thread++)
@@ -287,7 +291,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
287 int nr_threads = thread_map__nr(evlist->threads); 291 int nr_threads = thread_map__nr(evlist->threads);
288 292
289 for (cpu = 0; cpu < nr_cpus; cpu++) { 293 for (cpu = 0; cpu < nr_cpus; cpu++) {
290 list_for_each_entry(pos, &evlist->entries, node) { 294 evlist__for_each(evlist, pos) {
291 if (!perf_evsel__is_group_leader(pos) || !pos->fd) 295 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
292 continue; 296 continue;
293 for (thread = 0; thread < nr_threads; thread++) 297 for (thread = 0; thread < nr_threads; thread++)
@@ -584,11 +588,13 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
584{ 588{
585 int i; 589 int i;
586 590
591 if (evlist->mmap == NULL)
592 return;
593
587 for (i = 0; i < evlist->nr_mmaps; i++) 594 for (i = 0; i < evlist->nr_mmaps; i++)
588 __perf_evlist__munmap(evlist, i); 595 __perf_evlist__munmap(evlist, i);
589 596
590 free(evlist->mmap); 597 zfree(&evlist->mmap);
591 evlist->mmap = NULL;
592} 598}
593 599
594static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) 600static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
@@ -624,7 +630,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
624{ 630{
625 struct perf_evsel *evsel; 631 struct perf_evsel *evsel;
626 632
627 list_for_each_entry(evsel, &evlist->entries, node) { 633 evlist__for_each(evlist, evsel) {
628 int fd = FD(evsel, cpu, thread); 634 int fd = FD(evsel, cpu, thread);
629 635
630 if (*output == -1) { 636 if (*output == -1) {
@@ -732,11 +738,13 @@ static long parse_pages_arg(const char *str, unsigned long min,
732 return -EINVAL; 738 return -EINVAL;
733 } 739 }
734 740
735 if ((pages == 0) && (min == 0)) { 741 if (pages == 0 && min == 0) {
736 /* leave number of pages at 0 */ 742 /* leave number of pages at 0 */
737 } else if (pages < (1UL << 31) && !is_power_of_2(pages)) { 743 } else if (!is_power_of_2(pages)) {
738 /* round pages up to next power of 2 */ 744 /* round pages up to next power of 2 */
739 pages = next_pow2(pages); 745 pages = next_pow2_l(pages);
746 if (!pages)
747 return -EINVAL;
740 pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n", 748 pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n",
741 pages * page_size, pages); 749 pages * page_size, pages);
742 } 750 }
@@ -754,7 +762,7 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
754 unsigned long max = UINT_MAX; 762 unsigned long max = UINT_MAX;
755 long pages; 763 long pages;
756 764
757 if (max < SIZE_MAX / page_size) 765 if (max > SIZE_MAX / page_size)
758 max = SIZE_MAX / page_size; 766 max = SIZE_MAX / page_size;
759 767
760 pages = parse_pages_arg(str, 1, max); 768 pages = parse_pages_arg(str, 1, max);
@@ -798,7 +806,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
798 pr_debug("mmap size %zuB\n", evlist->mmap_len); 806 pr_debug("mmap size %zuB\n", evlist->mmap_len);
799 mask = evlist->mmap_len - page_size - 1; 807 mask = evlist->mmap_len - page_size - 1;
800 808
801 list_for_each_entry(evsel, &evlist->entries, node) { 809 evlist__for_each(evlist, evsel) {
802 if ((evsel->attr.read_format & PERF_FORMAT_ID) && 810 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
803 evsel->sample_id == NULL && 811 evsel->sample_id == NULL &&
804 perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) 812 perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0)
@@ -819,11 +827,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
819 if (evlist->threads == NULL) 827 if (evlist->threads == NULL)
820 return -1; 828 return -1;
821 829
822 if (target->force_per_cpu) 830 if (target__uses_dummy_map(target))
823 evlist->cpus = cpu_map__new(target->cpu_list);
824 else if (target__has_task(target))
825 evlist->cpus = cpu_map__dummy_new();
826 else if (!target__has_cpu(target) && !target->uses_mmap)
827 evlist->cpus = cpu_map__dummy_new(); 831 evlist->cpus = cpu_map__dummy_new();
828 else 832 else
829 evlist->cpus = cpu_map__new(target->cpu_list); 833 evlist->cpus = cpu_map__new(target->cpu_list);
@@ -838,14 +842,6 @@ out_delete_threads:
838 return -1; 842 return -1;
839} 843}
840 844
841void perf_evlist__delete_maps(struct perf_evlist *evlist)
842{
843 cpu_map__delete(evlist->cpus);
844 thread_map__delete(evlist->threads);
845 evlist->cpus = NULL;
846 evlist->threads = NULL;
847}
848
849int perf_evlist__apply_filters(struct perf_evlist *evlist) 845int perf_evlist__apply_filters(struct perf_evlist *evlist)
850{ 846{
851 struct perf_evsel *evsel; 847 struct perf_evsel *evsel;
@@ -853,7 +849,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist)
853 const int ncpus = cpu_map__nr(evlist->cpus), 849 const int ncpus = cpu_map__nr(evlist->cpus),
854 nthreads = thread_map__nr(evlist->threads); 850 nthreads = thread_map__nr(evlist->threads);
855 851
856 list_for_each_entry(evsel, &evlist->entries, node) { 852 evlist__for_each(evlist, evsel) {
857 if (evsel->filter == NULL) 853 if (evsel->filter == NULL)
858 continue; 854 continue;
859 855
@@ -872,7 +868,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
872 const int ncpus = cpu_map__nr(evlist->cpus), 868 const int ncpus = cpu_map__nr(evlist->cpus),
873 nthreads = thread_map__nr(evlist->threads); 869 nthreads = thread_map__nr(evlist->threads);
874 870
875 list_for_each_entry(evsel, &evlist->entries, node) { 871 evlist__for_each(evlist, evsel) {
876 err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); 872 err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter);
877 if (err) 873 if (err)
878 break; 874 break;
@@ -891,7 +887,7 @@ bool perf_evlist__valid_sample_type(struct perf_evlist *evlist)
891 if (evlist->id_pos < 0 || evlist->is_pos < 0) 887 if (evlist->id_pos < 0 || evlist->is_pos < 0)
892 return false; 888 return false;
893 889
894 list_for_each_entry(pos, &evlist->entries, node) { 890 evlist__for_each(evlist, pos) {
895 if (pos->id_pos != evlist->id_pos || 891 if (pos->id_pos != evlist->id_pos ||
896 pos->is_pos != evlist->is_pos) 892 pos->is_pos != evlist->is_pos)
897 return false; 893 return false;
@@ -907,7 +903,7 @@ u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist)
907 if (evlist->combined_sample_type) 903 if (evlist->combined_sample_type)
908 return evlist->combined_sample_type; 904 return evlist->combined_sample_type;
909 905
910 list_for_each_entry(evsel, &evlist->entries, node) 906 evlist__for_each(evlist, evsel)
911 evlist->combined_sample_type |= evsel->attr.sample_type; 907 evlist->combined_sample_type |= evsel->attr.sample_type;
912 908
913 return evlist->combined_sample_type; 909 return evlist->combined_sample_type;
@@ -925,7 +921,7 @@ bool perf_evlist__valid_read_format(struct perf_evlist *evlist)
925 u64 read_format = first->attr.read_format; 921 u64 read_format = first->attr.read_format;
926 u64 sample_type = first->attr.sample_type; 922 u64 sample_type = first->attr.sample_type;
927 923
928 list_for_each_entry_continue(pos, &evlist->entries, node) { 924 evlist__for_each(evlist, pos) {
929 if (read_format != pos->attr.read_format) 925 if (read_format != pos->attr.read_format)
930 return false; 926 return false;
931 } 927 }
@@ -982,7 +978,7 @@ bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist)
982{ 978{
983 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; 979 struct perf_evsel *first = perf_evlist__first(evlist), *pos = first;
984 980
985 list_for_each_entry_continue(pos, &evlist->entries, node) { 981 evlist__for_each_continue(evlist, pos) {
986 if (first->attr.sample_id_all != pos->attr.sample_id_all) 982 if (first->attr.sample_id_all != pos->attr.sample_id_all)
987 return false; 983 return false;
988 } 984 }
@@ -1008,7 +1004,7 @@ void perf_evlist__close(struct perf_evlist *evlist)
1008 int ncpus = cpu_map__nr(evlist->cpus); 1004 int ncpus = cpu_map__nr(evlist->cpus);
1009 int nthreads = thread_map__nr(evlist->threads); 1005 int nthreads = thread_map__nr(evlist->threads);
1010 1006
1011 list_for_each_entry_reverse(evsel, &evlist->entries, node) 1007 evlist__for_each_reverse(evlist, evsel)
1012 perf_evsel__close(evsel, ncpus, nthreads); 1008 perf_evsel__close(evsel, ncpus, nthreads);
1013} 1009}
1014 1010
@@ -1019,7 +1015,7 @@ int perf_evlist__open(struct perf_evlist *evlist)
1019 1015
1020 perf_evlist__update_id_pos(evlist); 1016 perf_evlist__update_id_pos(evlist);
1021 1017
1022 list_for_each_entry(evsel, &evlist->entries, node) { 1018 evlist__for_each(evlist, evsel) {
1023 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); 1019 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
1024 if (err < 0) 1020 if (err < 0)
1025 goto out_err; 1021 goto out_err;
@@ -1034,7 +1030,7 @@ out_err:
1034 1030
1035int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target, 1031int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target,
1036 const char *argv[], bool pipe_output, 1032 const char *argv[], bool pipe_output,
1037 bool want_signal) 1033 void (*exec_error)(int signo, siginfo_t *info, void *ucontext))
1038{ 1034{
1039 int child_ready_pipe[2], go_pipe[2]; 1035 int child_ready_pipe[2], go_pipe[2];
1040 char bf; 1036 char bf;
@@ -1078,12 +1074,25 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
1078 1074
1079 execvp(argv[0], (char **)argv); 1075 execvp(argv[0], (char **)argv);
1080 1076
1081 perror(argv[0]); 1077 if (exec_error) {
1082 if (want_signal) 1078 union sigval val;
1083 kill(getppid(), SIGUSR1); 1079
1080 val.sival_int = errno;
1081 if (sigqueue(getppid(), SIGUSR1, val))
1082 perror(argv[0]);
1083 } else
1084 perror(argv[0]);
1084 exit(-1); 1085 exit(-1);
1085 } 1086 }
1086 1087
1088 if (exec_error) {
1089 struct sigaction act = {
1090 .sa_flags = SA_SIGINFO,
1091 .sa_sigaction = exec_error,
1092 };
1093 sigaction(SIGUSR1, &act, NULL);
1094 }
1095
1087 if (target__none(target)) 1096 if (target__none(target))
1088 evlist->threads->map[0] = evlist->workload.pid; 1097 evlist->threads->map[0] = evlist->workload.pid;
1089 1098
@@ -1145,7 +1154,7 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
1145 struct perf_evsel *evsel; 1154 struct perf_evsel *evsel;
1146 size_t printed = 0; 1155 size_t printed = 0;
1147 1156
1148 list_for_each_entry(evsel, &evlist->entries, node) { 1157 evlist__for_each(evlist, evsel) {
1149 printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", 1158 printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "",
1150 perf_evsel__name(evsel)); 1159 perf_evsel__name(evsel));
1151 } 1160 }
@@ -1193,8 +1202,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1193 "Error:\t%s.\n" 1202 "Error:\t%s.\n"
1194 "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg); 1203 "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg);
1195 1204
1196 if (filename__read_int("/proc/sys/kernel/perf_event_paranoid", &value)) 1205 value = perf_event_paranoid();
1197 break;
1198 1206
1199 printed += scnprintf(buf + printed, size - printed, "\nHint:\t"); 1207 printed += scnprintf(buf + printed, size - printed, "\nHint:\t");
1200 1208
@@ -1215,3 +1223,20 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1215 1223
1216 return 0; 1224 return 0;
1217} 1225}
1226
1227void perf_evlist__to_front(struct perf_evlist *evlist,
1228 struct perf_evsel *move_evsel)
1229{
1230 struct perf_evsel *evsel, *n;
1231 LIST_HEAD(move);
1232
1233 if (move_evsel == perf_evlist__first(evlist))
1234 return;
1235
1236 evlist__for_each_safe(evlist, n, evsel) {
1237 if (evsel->leader == move_evsel->leader)
1238 list_move_tail(&evsel->node, &move);
1239 }
1240
1241 list_splice(&move, &evlist->entries);
1242}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 649d6ea98a84..f5173cd63693 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -12,7 +12,7 @@
12struct pollfd; 12struct pollfd;
13struct thread_map; 13struct thread_map;
14struct cpu_map; 14struct cpu_map;
15struct perf_record_opts; 15struct record_opts;
16 16
17#define PERF_EVLIST__HLIST_BITS 8 17#define PERF_EVLIST__HLIST_BITS 8
18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) 18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
@@ -97,14 +97,14 @@ void perf_evlist__close(struct perf_evlist *evlist);
97 97
98void perf_evlist__set_id_pos(struct perf_evlist *evlist); 98void perf_evlist__set_id_pos(struct perf_evlist *evlist);
99bool perf_can_sample_identifier(void); 99bool perf_can_sample_identifier(void);
100void perf_evlist__config(struct perf_evlist *evlist, 100void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts);
101 struct perf_record_opts *opts); 101int record_opts__config(struct record_opts *opts);
102int perf_record_opts__config(struct perf_record_opts *opts);
103 102
104int perf_evlist__prepare_workload(struct perf_evlist *evlist, 103int perf_evlist__prepare_workload(struct perf_evlist *evlist,
105 struct target *target, 104 struct target *target,
106 const char *argv[], bool pipe_output, 105 const char *argv[], bool pipe_output,
107 bool want_signal); 106 void (*exec_error)(int signo, siginfo_t *info,
107 void *ucontext));
108int perf_evlist__start_workload(struct perf_evlist *evlist); 108int perf_evlist__start_workload(struct perf_evlist *evlist);
109 109
110int perf_evlist__parse_mmap_pages(const struct option *opt, 110int perf_evlist__parse_mmap_pages(const struct option *opt,
@@ -135,7 +135,6 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
135} 135}
136 136
137int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target); 137int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target);
138void perf_evlist__delete_maps(struct perf_evlist *evlist);
139int perf_evlist__apply_filters(struct perf_evlist *evlist); 138int perf_evlist__apply_filters(struct perf_evlist *evlist);
140 139
141void __perf_evlist__set_leader(struct list_head *list); 140void __perf_evlist__set_leader(struct list_head *list);
@@ -193,4 +192,74 @@ static inline void perf_mmap__write_tail(struct perf_mmap *md,
193 pc->data_tail = tail; 192 pc->data_tail = tail;
194} 193}
195 194
195bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str);
196void perf_evlist__to_front(struct perf_evlist *evlist,
197 struct perf_evsel *move_evsel);
198
199/**
200 * __evlist__for_each - iterate thru all the evsels
201 * @list: list_head instance to iterate
202 * @evsel: struct evsel iterator
203 */
204#define __evlist__for_each(list, evsel) \
205 list_for_each_entry(evsel, list, node)
206
207/**
208 * evlist__for_each - iterate thru all the evsels
209 * @evlist: evlist instance to iterate
210 * @evsel: struct evsel iterator
211 */
212#define evlist__for_each(evlist, evsel) \
213 __evlist__for_each(&(evlist)->entries, evsel)
214
215/**
216 * __evlist__for_each_continue - continue iteration thru all the evsels
217 * @list: list_head instance to iterate
218 * @evsel: struct evsel iterator
219 */
220#define __evlist__for_each_continue(list, evsel) \
221 list_for_each_entry_continue(evsel, list, node)
222
223/**
224 * evlist__for_each_continue - continue iteration thru all the evsels
225 * @evlist: evlist instance to iterate
226 * @evsel: struct evsel iterator
227 */
228#define evlist__for_each_continue(evlist, evsel) \
229 __evlist__for_each_continue(&(evlist)->entries, evsel)
230
231/**
232 * __evlist__for_each_reverse - iterate thru all the evsels in reverse order
233 * @list: list_head instance to iterate
234 * @evsel: struct evsel iterator
235 */
236#define __evlist__for_each_reverse(list, evsel) \
237 list_for_each_entry_reverse(evsel, list, node)
238
239/**
240 * evlist__for_each_reverse - iterate thru all the evsels in reverse order
241 * @evlist: evlist instance to iterate
242 * @evsel: struct evsel iterator
243 */
244#define evlist__for_each_reverse(evlist, evsel) \
245 __evlist__for_each_reverse(&(evlist)->entries, evsel)
246
247/**
248 * __evlist__for_each_safe - safely iterate thru all the evsels
249 * @list: list_head instance to iterate
250 * @tmp: struct evsel temp iterator
251 * @evsel: struct evsel iterator
252 */
253#define __evlist__for_each_safe(list, tmp, evsel) \
254 list_for_each_entry_safe(evsel, tmp, list, node)
255
256/**
257 * evlist__for_each_safe - safely iterate thru all the evsels
258 * @evlist: evlist instance to iterate
259 * @evsel: struct evsel iterator
260 * @tmp: struct evsel temp iterator
261 */
262#define evlist__for_each_safe(evlist, tmp, evsel) \
263 __evlist__for_each_safe(&(evlist)->entries, tmp, evsel)
264
196#endif /* __PERF_EVLIST_H */ 265#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 46dd4c2a41ce..22e18a26b7e6 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -9,7 +9,7 @@
9 9
10#include <byteswap.h> 10#include <byteswap.h>
11#include <linux/bitops.h> 11#include <linux/bitops.h>
12#include <lk/debugfs.h> 12#include <api/fs/debugfs.h>
13#include <traceevent/event-parse.h> 13#include <traceevent/event-parse.h>
14#include <linux/hw_breakpoint.h> 14#include <linux/hw_breakpoint.h>
15#include <linux/perf_event.h> 15#include <linux/perf_event.h>
@@ -23,6 +23,7 @@
23#include "target.h" 23#include "target.h"
24#include "perf_regs.h" 24#include "perf_regs.h"
25#include "debug.h" 25#include "debug.h"
26#include "trace-event.h"
26 27
27static struct { 28static struct {
28 bool sample_id_all; 29 bool sample_id_all;
@@ -162,6 +163,8 @@ void perf_evsel__init(struct perf_evsel *evsel,
162 evsel->idx = idx; 163 evsel->idx = idx;
163 evsel->attr = *attr; 164 evsel->attr = *attr;
164 evsel->leader = evsel; 165 evsel->leader = evsel;
166 evsel->unit = "";
167 evsel->scale = 1.0;
165 INIT_LIST_HEAD(&evsel->node); 168 INIT_LIST_HEAD(&evsel->node);
166 hists__init(&evsel->hists); 169 hists__init(&evsel->hists);
167 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); 170 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
@@ -178,47 +181,6 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
178 return evsel; 181 return evsel;
179} 182}
180 183
181struct event_format *event_format__new(const char *sys, const char *name)
182{
183 int fd, n;
184 char *filename;
185 void *bf = NULL, *nbf;
186 size_t size = 0, alloc_size = 0;
187 struct event_format *format = NULL;
188
189 if (asprintf(&filename, "%s/%s/%s/format", tracing_events_path, sys, name) < 0)
190 goto out;
191
192 fd = open(filename, O_RDONLY);
193 if (fd < 0)
194 goto out_free_filename;
195
196 do {
197 if (size == alloc_size) {
198 alloc_size += BUFSIZ;
199 nbf = realloc(bf, alloc_size);
200 if (nbf == NULL)
201 goto out_free_bf;
202 bf = nbf;
203 }
204
205 n = read(fd, bf + size, alloc_size - size);
206 if (n < 0)
207 goto out_free_bf;
208 size += n;
209 } while (n > 0);
210
211 pevent_parse_format(&format, bf, size, sys);
212
213out_free_bf:
214 free(bf);
215 close(fd);
216out_free_filename:
217 free(filename);
218out:
219 return format;
220}
221
222struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) 184struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx)
223{ 185{
224 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 186 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
@@ -233,7 +195,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int
233 if (asprintf(&evsel->name, "%s:%s", sys, name) < 0) 195 if (asprintf(&evsel->name, "%s:%s", sys, name) < 0)
234 goto out_free; 196 goto out_free;
235 197
236 evsel->tp_format = event_format__new(sys, name); 198 evsel->tp_format = trace_event__tp_format(sys, name);
237 if (evsel->tp_format == NULL) 199 if (evsel->tp_format == NULL)
238 goto out_free; 200 goto out_free;
239 201
@@ -246,7 +208,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int
246 return evsel; 208 return evsel;
247 209
248out_free: 210out_free:
249 free(evsel->name); 211 zfree(&evsel->name);
250 free(evsel); 212 free(evsel);
251 return NULL; 213 return NULL;
252} 214}
@@ -566,12 +528,12 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
566 * enable/disable events specifically, as there's no 528 * enable/disable events specifically, as there's no
567 * initial traced exec call. 529 * initial traced exec call.
568 */ 530 */
569void perf_evsel__config(struct perf_evsel *evsel, 531void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
570 struct perf_record_opts *opts)
571{ 532{
572 struct perf_evsel *leader = evsel->leader; 533 struct perf_evsel *leader = evsel->leader;
573 struct perf_event_attr *attr = &evsel->attr; 534 struct perf_event_attr *attr = &evsel->attr;
574 int track = !evsel->idx; /* only the first counter needs these */ 535 int track = !evsel->idx; /* only the first counter needs these */
536 bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread;
575 537
576 attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; 538 attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
577 attr->inherit = !opts->no_inherit; 539 attr->inherit = !opts->no_inherit;
@@ -645,7 +607,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
645 } 607 }
646 } 608 }
647 609
648 if (target__has_cpu(&opts->target) || opts->target.force_per_cpu) 610 if (target__has_cpu(&opts->target))
649 perf_evsel__set_sample_bit(evsel, CPU); 611 perf_evsel__set_sample_bit(evsel, CPU);
650 612
651 if (opts->period) 613 if (opts->period)
@@ -653,7 +615,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
653 615
654 if (!perf_missing_features.sample_id_all && 616 if (!perf_missing_features.sample_id_all &&
655 (opts->sample_time || !opts->no_inherit || 617 (opts->sample_time || !opts->no_inherit ||
656 target__has_cpu(&opts->target) || opts->target.force_per_cpu)) 618 target__has_cpu(&opts->target) || per_cpu))
657 perf_evsel__set_sample_bit(evsel, TIME); 619 perf_evsel__set_sample_bit(evsel, TIME);
658 620
659 if (opts->raw_samples) { 621 if (opts->raw_samples) {
@@ -665,7 +627,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
665 if (opts->sample_address) 627 if (opts->sample_address)
666 perf_evsel__set_sample_bit(evsel, DATA_SRC); 628 perf_evsel__set_sample_bit(evsel, DATA_SRC);
667 629
668 if (opts->no_delay) { 630 if (opts->no_buffering) {
669 attr->watermark = 0; 631 attr->watermark = 0;
670 attr->wakeup_events = 1; 632 attr->wakeup_events = 1;
671 } 633 }
@@ -696,7 +658,8 @@ void perf_evsel__config(struct perf_evsel *evsel,
696 * Setting enable_on_exec for independent events and 658 * Setting enable_on_exec for independent events and
697 * group leaders for traced executed by perf. 659 * group leaders for traced executed by perf.
698 */ 660 */
699 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel)) 661 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) &&
662 !opts->initial_delay)
700 attr->enable_on_exec = 1; 663 attr->enable_on_exec = 1;
701} 664}
702 665
@@ -788,8 +751,7 @@ void perf_evsel__free_id(struct perf_evsel *evsel)
788{ 751{
789 xyarray__delete(evsel->sample_id); 752 xyarray__delete(evsel->sample_id);
790 evsel->sample_id = NULL; 753 evsel->sample_id = NULL;
791 free(evsel->id); 754 zfree(&evsel->id);
792 evsel->id = NULL;
793} 755}
794 756
795void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 757void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
@@ -805,7 +767,7 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
805 767
806void perf_evsel__free_counts(struct perf_evsel *evsel) 768void perf_evsel__free_counts(struct perf_evsel *evsel)
807{ 769{
808 free(evsel->counts); 770 zfree(&evsel->counts);
809} 771}
810 772
811void perf_evsel__exit(struct perf_evsel *evsel) 773void perf_evsel__exit(struct perf_evsel *evsel)
@@ -819,10 +781,10 @@ void perf_evsel__delete(struct perf_evsel *evsel)
819{ 781{
820 perf_evsel__exit(evsel); 782 perf_evsel__exit(evsel);
821 close_cgroup(evsel->cgrp); 783 close_cgroup(evsel->cgrp);
822 free(evsel->group_name); 784 zfree(&evsel->group_name);
823 if (evsel->tp_format) 785 if (evsel->tp_format)
824 pevent_free_format(evsel->tp_format); 786 pevent_free_format(evsel->tp_format);
825 free(evsel->name); 787 zfree(&evsel->name);
826 free(evsel); 788 free(evsel);
827} 789}
828 790
@@ -1998,8 +1960,7 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
1998 evsel->attr.type = PERF_TYPE_SOFTWARE; 1960 evsel->attr.type = PERF_TYPE_SOFTWARE;
1999 evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; 1961 evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK;
2000 1962
2001 free(evsel->name); 1963 zfree(&evsel->name);
2002 evsel->name = NULL;
2003 return true; 1964 return true;
2004 } 1965 }
2005 1966
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 1ea7c92e6e33..f1b325665aae 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -68,6 +68,8 @@ struct perf_evsel {
68 u32 ids; 68 u32 ids;
69 struct hists hists; 69 struct hists hists;
70 char *name; 70 char *name;
71 double scale;
72 const char *unit;
71 struct event_format *tp_format; 73 struct event_format *tp_format;
72 union { 74 union {
73 void *priv; 75 void *priv;
@@ -94,7 +96,7 @@ struct perf_evsel {
94struct cpu_map; 96struct cpu_map;
95struct thread_map; 97struct thread_map;
96struct perf_evlist; 98struct perf_evlist;
97struct perf_record_opts; 99struct record_opts;
98 100
99struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); 101struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx);
100 102
@@ -118,7 +120,7 @@ void perf_evsel__exit(struct perf_evsel *evsel);
118void perf_evsel__delete(struct perf_evsel *evsel); 120void perf_evsel__delete(struct perf_evsel *evsel);
119 121
120void perf_evsel__config(struct perf_evsel *evsel, 122void perf_evsel__config(struct perf_evsel *evsel,
121 struct perf_record_opts *opts); 123 struct record_opts *opts);
122 124
123int __perf_evsel__sample_size(u64 sample_type); 125int __perf_evsel__sample_size(u64 sample_type);
124void perf_evsel__calc_id_pos(struct perf_evsel *evsel); 126void perf_evsel__calc_id_pos(struct perf_evsel *evsel);
@@ -138,6 +140,7 @@ extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX];
138int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, 140int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
139 char *bf, size_t size); 141 char *bf, size_t size);
140const char *perf_evsel__name(struct perf_evsel *evsel); 142const char *perf_evsel__name(struct perf_evsel *evsel);
143
141const char *perf_evsel__group_name(struct perf_evsel *evsel); 144const char *perf_evsel__group_name(struct perf_evsel *evsel);
142int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); 145int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
143 146
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 1cd035708931..bb3e0ede6183 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -177,7 +177,7 @@ perf_header__set_cmdline(int argc, const char **argv)
177 continue; \ 177 continue; \
178 else 178 else
179 179
180static int write_buildid(char *name, size_t name_len, u8 *build_id, 180static int write_buildid(const char *name, size_t name_len, u8 *build_id,
181 pid_t pid, u16 misc, int fd) 181 pid_t pid, u16 misc, int fd)
182{ 182{
183 int err; 183 int err;
@@ -209,7 +209,7 @@ static int __dsos__write_buildid_table(struct list_head *head,
209 209
210 dsos__for_each_with_build_id(pos, head) { 210 dsos__for_each_with_build_id(pos, head) {
211 int err; 211 int err;
212 char *name; 212 const char *name;
213 size_t name_len; 213 size_t name_len;
214 214
215 if (!pos->hit) 215 if (!pos->hit)
@@ -387,7 +387,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine,
387{ 387{
388 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; 388 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
389 bool is_vdso = is_vdso_map(dso->short_name); 389 bool is_vdso = is_vdso_map(dso->short_name);
390 char *name = dso->long_name; 390 const char *name = dso->long_name;
391 char nm[PATH_MAX]; 391 char nm[PATH_MAX];
392 392
393 if (dso__is_kcore(dso)) { 393 if (dso__is_kcore(dso)) {
@@ -643,8 +643,7 @@ static int write_event_desc(int fd, struct perf_header *h __maybe_unused,
643 if (ret < 0) 643 if (ret < 0)
644 return ret; 644 return ret;
645 645
646 list_for_each_entry(evsel, &evlist->entries, node) { 646 evlist__for_each(evlist, evsel) {
647
648 ret = do_write(fd, &evsel->attr, sz); 647 ret = do_write(fd, &evsel->attr, sz);
649 if (ret < 0) 648 if (ret < 0)
650 return ret; 649 return ret;
@@ -800,10 +799,10 @@ static void free_cpu_topo(struct cpu_topo *tp)
800 return; 799 return;
801 800
802 for (i = 0 ; i < tp->core_sib; i++) 801 for (i = 0 ; i < tp->core_sib; i++)
803 free(tp->core_siblings[i]); 802 zfree(&tp->core_siblings[i]);
804 803
805 for (i = 0 ; i < tp->thread_sib; i++) 804 for (i = 0 ; i < tp->thread_sib; i++)
806 free(tp->thread_siblings[i]); 805 zfree(&tp->thread_siblings[i]);
807 806
808 free(tp); 807 free(tp);
809} 808}
@@ -1092,7 +1091,7 @@ static int write_group_desc(int fd, struct perf_header *h __maybe_unused,
1092 if (ret < 0) 1091 if (ret < 0)
1093 return ret; 1092 return ret;
1094 1093
1095 list_for_each_entry(evsel, &evlist->entries, node) { 1094 evlist__for_each(evlist, evsel) {
1096 if (perf_evsel__is_group_leader(evsel) && 1095 if (perf_evsel__is_group_leader(evsel) &&
1097 evsel->nr_members > 1) { 1096 evsel->nr_members > 1) {
1098 const char *name = evsel->group_name ?: "{anon_group}"; 1097 const char *name = evsel->group_name ?: "{anon_group}";
@@ -1232,10 +1231,8 @@ static void free_event_desc(struct perf_evsel *events)
1232 return; 1231 return;
1233 1232
1234 for (evsel = events; evsel->attr.size; evsel++) { 1233 for (evsel = events; evsel->attr.size; evsel++) {
1235 if (evsel->name) 1234 zfree(&evsel->name);
1236 free(evsel->name); 1235 zfree(&evsel->id);
1237 if (evsel->id)
1238 free(evsel->id);
1239 } 1236 }
1240 1237
1241 free(events); 1238 free(events);
@@ -1326,8 +1323,7 @@ read_event_desc(struct perf_header *ph, int fd)
1326 } 1323 }
1327 } 1324 }
1328out: 1325out:
1329 if (buf) 1326 free(buf);
1330 free(buf);
1331 return events; 1327 return events;
1332error: 1328error:
1333 if (events) 1329 if (events)
@@ -1490,7 +1486,7 @@ static void print_group_desc(struct perf_header *ph, int fd __maybe_unused,
1490 1486
1491 session = container_of(ph, struct perf_session, header); 1487 session = container_of(ph, struct perf_session, header);
1492 1488
1493 list_for_each_entry(evsel, &session->evlist->entries, node) { 1489 evlist__for_each(session->evlist, evsel) {
1494 if (perf_evsel__is_group_leader(evsel) && 1490 if (perf_evsel__is_group_leader(evsel) &&
1495 evsel->nr_members > 1) { 1491 evsel->nr_members > 1) {
1496 fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", 1492 fprintf(fp, "# group: %s{%s", evsel->group_name ?: "",
@@ -1709,7 +1705,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1709 struct perf_header *ph, int fd, 1705 struct perf_header *ph, int fd,
1710 void *data __maybe_unused) 1706 void *data __maybe_unused)
1711{ 1707{
1712 size_t ret; 1708 ssize_t ret;
1713 u32 nr; 1709 u32 nr;
1714 1710
1715 ret = readn(fd, &nr, sizeof(nr)); 1711 ret = readn(fd, &nr, sizeof(nr));
@@ -1753,7 +1749,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused,
1753 void *data __maybe_unused) 1749 void *data __maybe_unused)
1754{ 1750{
1755 uint64_t mem; 1751 uint64_t mem;
1756 size_t ret; 1752 ssize_t ret;
1757 1753
1758 ret = readn(fd, &mem, sizeof(mem)); 1754 ret = readn(fd, &mem, sizeof(mem));
1759 if (ret != sizeof(mem)) 1755 if (ret != sizeof(mem))
@@ -1771,7 +1767,7 @@ perf_evlist__find_by_index(struct perf_evlist *evlist, int idx)
1771{ 1767{
1772 struct perf_evsel *evsel; 1768 struct perf_evsel *evsel;
1773 1769
1774 list_for_each_entry(evsel, &evlist->entries, node) { 1770 evlist__for_each(evlist, evsel) {
1775 if (evsel->idx == idx) 1771 if (evsel->idx == idx)
1776 return evsel; 1772 return evsel;
1777 } 1773 }
@@ -1822,7 +1818,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
1822 struct perf_header *ph, int fd, 1818 struct perf_header *ph, int fd,
1823 void *data __maybe_unused) 1819 void *data __maybe_unused)
1824{ 1820{
1825 size_t ret; 1821 ssize_t ret;
1826 char *str; 1822 char *str;
1827 u32 nr, i; 1823 u32 nr, i;
1828 struct strbuf sb; 1824 struct strbuf sb;
@@ -1858,7 +1854,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1858 struct perf_header *ph, int fd, 1854 struct perf_header *ph, int fd,
1859 void *data __maybe_unused) 1855 void *data __maybe_unused)
1860{ 1856{
1861 size_t ret; 1857 ssize_t ret;
1862 u32 nr, i; 1858 u32 nr, i;
1863 char *str; 1859 char *str;
1864 struct strbuf sb; 1860 struct strbuf sb;
@@ -1914,7 +1910,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1914 struct perf_header *ph, int fd, 1910 struct perf_header *ph, int fd,
1915 void *data __maybe_unused) 1911 void *data __maybe_unused)
1916{ 1912{
1917 size_t ret; 1913 ssize_t ret;
1918 u32 nr, node, i; 1914 u32 nr, node, i;
1919 char *str; 1915 char *str;
1920 uint64_t mem_total, mem_free; 1916 uint64_t mem_total, mem_free;
@@ -1974,7 +1970,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1974 struct perf_header *ph, int fd, 1970 struct perf_header *ph, int fd,
1975 void *data __maybe_unused) 1971 void *data __maybe_unused)
1976{ 1972{
1977 size_t ret; 1973 ssize_t ret;
1978 char *name; 1974 char *name;
1979 u32 pmu_num; 1975 u32 pmu_num;
1980 u32 type; 1976 u32 type;
@@ -2074,7 +2070,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused,
2074 session->evlist->nr_groups = nr_groups; 2070 session->evlist->nr_groups = nr_groups;
2075 2071
2076 i = nr = 0; 2072 i = nr = 0;
2077 list_for_each_entry(evsel, &session->evlist->entries, node) { 2073 evlist__for_each(session->evlist, evsel) {
2078 if (evsel->idx == (int) desc[i].leader_idx) { 2074 if (evsel->idx == (int) desc[i].leader_idx) {
2079 evsel->leader = evsel; 2075 evsel->leader = evsel;
2080 /* {anon_group} is a dummy name */ 2076 /* {anon_group} is a dummy name */
@@ -2108,7 +2104,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused,
2108 ret = 0; 2104 ret = 0;
2109out_free: 2105out_free:
2110 for (i = 0; i < nr_groups; i++) 2106 for (i = 0; i < nr_groups; i++)
2111 free(desc[i].name); 2107 zfree(&desc[i].name);
2112 free(desc); 2108 free(desc);
2113 2109
2114 return ret; 2110 return ret;
@@ -2301,7 +2297,7 @@ int perf_session__write_header(struct perf_session *session,
2301 2297
2302 lseek(fd, sizeof(f_header), SEEK_SET); 2298 lseek(fd, sizeof(f_header), SEEK_SET);
2303 2299
2304 list_for_each_entry(evsel, &evlist->entries, node) { 2300 evlist__for_each(session->evlist, evsel) {
2305 evsel->id_offset = lseek(fd, 0, SEEK_CUR); 2301 evsel->id_offset = lseek(fd, 0, SEEK_CUR);
2306 err = do_write(fd, evsel->id, evsel->ids * sizeof(u64)); 2302 err = do_write(fd, evsel->id, evsel->ids * sizeof(u64));
2307 if (err < 0) { 2303 if (err < 0) {
@@ -2312,7 +2308,7 @@ int perf_session__write_header(struct perf_session *session,
2312 2308
2313 attr_offset = lseek(fd, 0, SEEK_CUR); 2309 attr_offset = lseek(fd, 0, SEEK_CUR);
2314 2310
2315 list_for_each_entry(evsel, &evlist->entries, node) { 2311 evlist__for_each(evlist, evsel) {
2316 f_attr = (struct perf_file_attr){ 2312 f_attr = (struct perf_file_attr){
2317 .attr = evsel->attr, 2313 .attr = evsel->attr,
2318 .ids = { 2314 .ids = {
@@ -2327,7 +2323,8 @@ int perf_session__write_header(struct perf_session *session,
2327 } 2323 }
2328 } 2324 }
2329 2325
2330 header->data_offset = lseek(fd, 0, SEEK_CUR); 2326 if (!header->data_offset)
2327 header->data_offset = lseek(fd, 0, SEEK_CUR);
2331 header->feat_offset = header->data_offset + header->data_size; 2328 header->feat_offset = header->data_offset + header->data_size;
2332 2329
2333 if (at_exit) { 2330 if (at_exit) {
@@ -2534,7 +2531,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
2534int perf_file_header__read(struct perf_file_header *header, 2531int perf_file_header__read(struct perf_file_header *header,
2535 struct perf_header *ph, int fd) 2532 struct perf_header *ph, int fd)
2536{ 2533{
2537 int ret; 2534 ssize_t ret;
2538 2535
2539 lseek(fd, 0, SEEK_SET); 2536 lseek(fd, 0, SEEK_SET);
2540 2537
@@ -2628,7 +2625,7 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
2628 struct perf_header *ph, int fd, 2625 struct perf_header *ph, int fd,
2629 bool repipe) 2626 bool repipe)
2630{ 2627{
2631 int ret; 2628 ssize_t ret;
2632 2629
2633 ret = readn(fd, header, sizeof(*header)); 2630 ret = readn(fd, header, sizeof(*header));
2634 if (ret <= 0) 2631 if (ret <= 0)
@@ -2669,7 +2666,7 @@ static int read_attr(int fd, struct perf_header *ph,
2669 struct perf_event_attr *attr = &f_attr->attr; 2666 struct perf_event_attr *attr = &f_attr->attr;
2670 size_t sz, left; 2667 size_t sz, left;
2671 size_t our_sz = sizeof(f_attr->attr); 2668 size_t our_sz = sizeof(f_attr->attr);
2672 int ret; 2669 ssize_t ret;
2673 2670
2674 memset(f_attr, 0, sizeof(*f_attr)); 2671 memset(f_attr, 0, sizeof(*f_attr));
2675 2672
@@ -2744,7 +2741,7 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
2744{ 2741{
2745 struct perf_evsel *pos; 2742 struct perf_evsel *pos;
2746 2743
2747 list_for_each_entry(pos, &evlist->entries, node) { 2744 evlist__for_each(evlist, pos) {
2748 if (pos->attr.type == PERF_TYPE_TRACEPOINT && 2745 if (pos->attr.type == PERF_TYPE_TRACEPOINT &&
2749 perf_evsel__prepare_tracepoint_event(pos, pevent)) 2746 perf_evsel__prepare_tracepoint_event(pos, pevent))
2750 return -1; 2747 return -1;
@@ -2834,11 +2831,11 @@ int perf_session__read_header(struct perf_session *session)
2834 2831
2835 symbol_conf.nr_events = nr_attrs; 2832 symbol_conf.nr_events = nr_attrs;
2836 2833
2837 perf_header__process_sections(header, fd, &session->pevent, 2834 perf_header__process_sections(header, fd, &session->tevent,
2838 perf_file_section__process); 2835 perf_file_section__process);
2839 2836
2840 if (perf_evlist__prepare_tracepoint_events(session->evlist, 2837 if (perf_evlist__prepare_tracepoint_events(session->evlist,
2841 session->pevent)) 2838 session->tevent.pevent))
2842 goto out_delete_evlist; 2839 goto out_delete_evlist;
2843 2840
2844 return 0; 2841 return 0;
@@ -2892,7 +2889,7 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
2892 struct perf_evsel *evsel; 2889 struct perf_evsel *evsel;
2893 int err = 0; 2890 int err = 0;
2894 2891
2895 list_for_each_entry(evsel, &session->evlist->entries, node) { 2892 evlist__for_each(session->evlist, evsel) {
2896 err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids, 2893 err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids,
2897 evsel->id, process); 2894 evsel->id, process);
2898 if (err) { 2895 if (err) {
@@ -3003,7 +3000,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
3003 lseek(fd, offset + sizeof(struct tracing_data_event), 3000 lseek(fd, offset + sizeof(struct tracing_data_event),
3004 SEEK_SET); 3001 SEEK_SET);
3005 3002
3006 size_read = trace_report(fd, &session->pevent, 3003 size_read = trace_report(fd, &session->tevent,
3007 session->repipe); 3004 session->repipe);
3008 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 3005 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
3009 3006
@@ -3025,7 +3022,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
3025 } 3022 }
3026 3023
3027 perf_evlist__prepare_tracepoint_events(session->evlist, 3024 perf_evlist__prepare_tracepoint_events(session->evlist,
3028 session->pevent); 3025 session->tevent.pevent);
3029 3026
3030 return size_read + padding; 3027 return size_read + padding;
3031} 3028}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 307c9aed972e..a2d047bdf4ef 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -77,16 +77,16 @@ struct perf_session_env {
77 unsigned long long total_mem; 77 unsigned long long total_mem;
78 78
79 int nr_cmdline; 79 int nr_cmdline;
80 char *cmdline;
81 int nr_sibling_cores; 80 int nr_sibling_cores;
82 char *sibling_cores;
83 int nr_sibling_threads; 81 int nr_sibling_threads;
84 char *sibling_threads;
85 int nr_numa_nodes; 82 int nr_numa_nodes;
86 char *numa_nodes;
87 int nr_pmu_mappings; 83 int nr_pmu_mappings;
88 char *pmu_mappings;
89 int nr_groups; 84 int nr_groups;
85 char *cmdline;
86 char *sibling_cores;
87 char *sibling_threads;
88 char *numa_nodes;
89 char *pmu_mappings;
90}; 90};
91 91
92struct perf_header { 92struct perf_header {
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
index 8b1f6e891b8a..86c37c472263 100644
--- a/tools/perf/util/help.c
+++ b/tools/perf/util/help.c
@@ -22,8 +22,8 @@ static void clean_cmdnames(struct cmdnames *cmds)
22 unsigned int i; 22 unsigned int i;
23 23
24 for (i = 0; i < cmds->cnt; ++i) 24 for (i = 0; i < cmds->cnt; ++i)
25 free(cmds->names[i]); 25 zfree(&cmds->names[i]);
26 free(cmds->names); 26 zfree(&cmds->names);
27 cmds->cnt = 0; 27 cmds->cnt = 0;
28 cmds->alloc = 0; 28 cmds->alloc = 0;
29} 29}
@@ -263,9 +263,8 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
263 263
264 for (i = 0; i < old->cnt; i++) 264 for (i = 0; i < old->cnt; i++)
265 cmds->names[cmds->cnt++] = old->names[i]; 265 cmds->names[cmds->cnt++] = old->names[i];
266 free(old->names); 266 zfree(&old->names);
267 old->cnt = 0; 267 old->cnt = 0;
268 old->names = NULL;
269} 268}
270 269
271const char *help_unknown_cmd(const char *cmd) 270const char *help_unknown_cmd(const char *cmd)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 822903eaa201..e4e6249b87d4 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1,4 +1,3 @@
1#include "annotate.h"
2#include "util.h" 1#include "util.h"
3#include "build-id.h" 2#include "build-id.h"
4#include "hist.h" 3#include "hist.h"
@@ -182,21 +181,21 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows)
182 } 181 }
183} 182}
184 183
185static void hist_entry__add_cpumode_period(struct hist_entry *he, 184static void he_stat__add_cpumode_period(struct he_stat *he_stat,
186 unsigned int cpumode, u64 period) 185 unsigned int cpumode, u64 period)
187{ 186{
188 switch (cpumode) { 187 switch (cpumode) {
189 case PERF_RECORD_MISC_KERNEL: 188 case PERF_RECORD_MISC_KERNEL:
190 he->stat.period_sys += period; 189 he_stat->period_sys += period;
191 break; 190 break;
192 case PERF_RECORD_MISC_USER: 191 case PERF_RECORD_MISC_USER:
193 he->stat.period_us += period; 192 he_stat->period_us += period;
194 break; 193 break;
195 case PERF_RECORD_MISC_GUEST_KERNEL: 194 case PERF_RECORD_MISC_GUEST_KERNEL:
196 he->stat.period_guest_sys += period; 195 he_stat->period_guest_sys += period;
197 break; 196 break;
198 case PERF_RECORD_MISC_GUEST_USER: 197 case PERF_RECORD_MISC_GUEST_USER:
199 he->stat.period_guest_us += period; 198 he_stat->period_guest_us += period;
200 break; 199 break;
201 default: 200 default:
202 break; 201 break;
@@ -223,10 +222,10 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
223 dest->weight += src->weight; 222 dest->weight += src->weight;
224} 223}
225 224
226static void hist_entry__decay(struct hist_entry *he) 225static void he_stat__decay(struct he_stat *he_stat)
227{ 226{
228 he->stat.period = (he->stat.period * 7) / 8; 227 he_stat->period = (he_stat->period * 7) / 8;
229 he->stat.nr_events = (he->stat.nr_events * 7) / 8; 228 he_stat->nr_events = (he_stat->nr_events * 7) / 8;
230 /* XXX need decay for weight too? */ 229 /* XXX need decay for weight too? */
231} 230}
232 231
@@ -237,7 +236,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
237 if (prev_period == 0) 236 if (prev_period == 0)
238 return true; 237 return true;
239 238
240 hist_entry__decay(he); 239 he_stat__decay(&he->stat);
241 240
242 if (!he->filtered) 241 if (!he->filtered)
243 hists->stats.total_period -= prev_period - he->stat.period; 242 hists->stats.total_period -= prev_period - he->stat.period;
@@ -342,15 +341,15 @@ static u8 symbol__parent_filter(const struct symbol *parent)
342} 341}
343 342
344static struct hist_entry *add_hist_entry(struct hists *hists, 343static struct hist_entry *add_hist_entry(struct hists *hists,
345 struct hist_entry *entry, 344 struct hist_entry *entry,
346 struct addr_location *al, 345 struct addr_location *al)
347 u64 period,
348 u64 weight)
349{ 346{
350 struct rb_node **p; 347 struct rb_node **p;
351 struct rb_node *parent = NULL; 348 struct rb_node *parent = NULL;
352 struct hist_entry *he; 349 struct hist_entry *he;
353 int64_t cmp; 350 int64_t cmp;
351 u64 period = entry->stat.period;
352 u64 weight = entry->stat.weight;
354 353
355 p = &hists->entries_in->rb_node; 354 p = &hists->entries_in->rb_node;
356 355
@@ -373,7 +372,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
373 * This mem info was allocated from machine__resolve_mem 372 * This mem info was allocated from machine__resolve_mem
374 * and will not be used anymore. 373 * and will not be used anymore.
375 */ 374 */
376 free(entry->mem_info); 375 zfree(&entry->mem_info);
377 376
378 /* If the map of an existing hist_entry has 377 /* If the map of an existing hist_entry has
379 * become out-of-date due to an exec() or 378 * become out-of-date due to an exec() or
@@ -403,7 +402,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
403 rb_link_node(&he->rb_node_in, parent, p); 402 rb_link_node(&he->rb_node_in, parent, p);
404 rb_insert_color(&he->rb_node_in, hists->entries_in); 403 rb_insert_color(&he->rb_node_in, hists->entries_in);
405out: 404out:
406 hist_entry__add_cpumode_period(he, al->cpumode, period); 405 he_stat__add_cpumode_period(&he->stat, al->cpumode, period);
407 return he; 406 return he;
408} 407}
409 408
@@ -437,7 +436,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
437 .transaction = transaction, 436 .transaction = transaction,
438 }; 437 };
439 438
440 return add_hist_entry(hists, &entry, al, period, weight); 439 return add_hist_entry(hists, &entry, al);
441} 440}
442 441
443int64_t 442int64_t
@@ -476,8 +475,8 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
476 475
477void hist_entry__free(struct hist_entry *he) 476void hist_entry__free(struct hist_entry *he)
478{ 477{
479 free(he->branch_info); 478 zfree(&he->branch_info);
480 free(he->mem_info); 479 zfree(&he->mem_info);
481 free_srcline(he->srcline); 480 free_srcline(he->srcline);
482 free(he); 481 free(he);
483} 482}
@@ -807,16 +806,6 @@ void hists__filter_by_symbol(struct hists *hists)
807 } 806 }
808} 807}
809 808
810int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
811{
812 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
813}
814
815int hist_entry__annotate(struct hist_entry *he, size_t privsize)
816{
817 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
818}
819
820void events_stats__inc(struct events_stats *stats, u32 type) 809void events_stats__inc(struct events_stats *stats, u32 type)
821{ 810{
822 ++stats->nr_events[0]; 811 ++stats->nr_events[0];
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index b621347a1585..a59743fa3ef7 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -111,9 +111,6 @@ size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
111size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 111size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
112 int max_cols, float min_pcnt, FILE *fp); 112 int max_cols, float min_pcnt, FILE *fp);
113 113
114int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr);
115int hist_entry__annotate(struct hist_entry *he, size_t privsize);
116
117void hists__filter_by_dso(struct hists *hists); 114void hists__filter_by_dso(struct hists *hists);
118void hists__filter_by_thread(struct hists *hists); 115void hists__filter_by_thread(struct hists *hists);
119void hists__filter_by_symbol(struct hists *hists); 116void hists__filter_by_symbol(struct hists *hists);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 84cdb072ac83..ded74590b92f 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -9,6 +9,7 @@
9#include "strlist.h" 9#include "strlist.h"
10#include "thread.h" 10#include "thread.h"
11#include <stdbool.h> 11#include <stdbool.h>
12#include <symbol/kallsyms.h>
12#include "unwind.h" 13#include "unwind.h"
13 14
14int machine__init(struct machine *machine, const char *root_dir, pid_t pid) 15int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
@@ -26,6 +27,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
26 machine->pid = pid; 27 machine->pid = pid;
27 28
28 machine->symbol_filter = NULL; 29 machine->symbol_filter = NULL;
30 machine->id_hdr_size = 0;
29 31
30 machine->root_dir = strdup(root_dir); 32 machine->root_dir = strdup(root_dir);
31 if (machine->root_dir == NULL) 33 if (machine->root_dir == NULL)
@@ -101,8 +103,7 @@ void machine__exit(struct machine *machine)
101 map_groups__exit(&machine->kmaps); 103 map_groups__exit(&machine->kmaps);
102 dsos__delete(&machine->user_dsos); 104 dsos__delete(&machine->user_dsos);
103 dsos__delete(&machine->kernel_dsos); 105 dsos__delete(&machine->kernel_dsos);
104 free(machine->root_dir); 106 zfree(&machine->root_dir);
105 machine->root_dir = NULL;
106} 107}
107 108
108void machine__delete(struct machine *machine) 109void machine__delete(struct machine *machine)
@@ -502,15 +503,11 @@ static u64 machine__get_kernel_start_addr(struct machine *machine)
502 char path[PATH_MAX]; 503 char path[PATH_MAX];
503 struct process_args args; 504 struct process_args args;
504 505
505 if (machine__is_host(machine)) { 506 if (machine__is_default_guest(machine))
506 filename = "/proc/kallsyms"; 507 filename = (char *)symbol_conf.default_guest_kallsyms;
507 } else { 508 else {
508 if (machine__is_default_guest(machine)) 509 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
509 filename = (char *)symbol_conf.default_guest_kallsyms; 510 filename = path;
510 else {
511 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
512 filename = path;
513 }
514 } 511 }
515 512
516 if (symbol__restricted_filename(filename, "/proc/kallsyms")) 513 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
@@ -565,11 +562,10 @@ void machine__destroy_kernel_maps(struct machine *machine)
565 * on one of them. 562 * on one of them.
566 */ 563 */
567 if (type == MAP__FUNCTION) { 564 if (type == MAP__FUNCTION) {
568 free((char *)kmap->ref_reloc_sym->name); 565 zfree((char **)&kmap->ref_reloc_sym->name);
569 kmap->ref_reloc_sym->name = NULL; 566 zfree(&kmap->ref_reloc_sym);
570 free(kmap->ref_reloc_sym); 567 } else
571 } 568 kmap->ref_reloc_sym = NULL;
572 kmap->ref_reloc_sym = NULL;
573 } 569 }
574 570
575 map__delete(machine->vmlinux_maps[type]); 571 map__delete(machine->vmlinux_maps[type]);
@@ -767,8 +763,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
767 ret = -1; 763 ret = -1;
768 goto out; 764 goto out;
769 } 765 }
770 dso__set_long_name(map->dso, long_name); 766 dso__set_long_name(map->dso, long_name, true);
771 map->dso->lname_alloc = 1;
772 dso__kernel_module_get_build_id(map->dso, ""); 767 dso__kernel_module_get_build_id(map->dso, "");
773 } 768 }
774 } 769 }
@@ -939,8 +934,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
939 if (name == NULL) 934 if (name == NULL)
940 goto out_problem; 935 goto out_problem;
941 936
942 map->dso->short_name = name; 937 dso__set_short_name(map->dso, name, true);
943 map->dso->sname_alloc = 1;
944 map->end = map->start + event->mmap.len; 938 map->end = map->start + event->mmap.len;
945 } else if (is_kernel_mmap) { 939 } else if (is_kernel_mmap) {
946 const char *symbol_name = (event->mmap.filename + 940 const char *symbol_name = (event->mmap.filename +
@@ -1320,8 +1314,6 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1320 *root_al = al; 1314 *root_al = al;
1321 callchain_cursor_reset(&callchain_cursor); 1315 callchain_cursor_reset(&callchain_cursor);
1322 } 1316 }
1323 if (!symbol_conf.use_callchain)
1324 break;
1325 } 1317 }
1326 1318
1327 err = callchain_cursor_append(&callchain_cursor, 1319 err = callchain_cursor_append(&callchain_cursor,
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index ef5bc913ca7a..9b9bd719aa19 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -11,6 +11,7 @@
11#include "strlist.h" 11#include "strlist.h"
12#include "vdso.h" 12#include "vdso.h"
13#include "build-id.h" 13#include "build-id.h"
14#include "util.h"
14#include <linux/string.h> 15#include <linux/string.h>
15 16
16const char *map_type__name[MAP__NR_TYPES] = { 17const char *map_type__name[MAP__NR_TYPES] = {
@@ -252,6 +253,22 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp)
252 return fprintf(fp, "%s", dsoname); 253 return fprintf(fp, "%s", dsoname);
253} 254}
254 255
256int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
257 FILE *fp)
258{
259 char *srcline;
260 int ret = 0;
261
262 if (map && map->dso) {
263 srcline = get_srcline(map->dso,
264 map__rip_2objdump(map, addr));
265 if (srcline != SRCLINE_UNKNOWN)
266 ret = fprintf(fp, "%s%s", prefix, srcline);
267 free_srcline(srcline);
268 }
269 return ret;
270}
271
255/** 272/**
256 * map__rip_2objdump - convert symbol start address to objdump address. 273 * map__rip_2objdump - convert symbol start address to objdump address.
257 * @map: memory map 274 * @map: memory map
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index e4e259c3ba16..18068c6b71c1 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -103,6 +103,8 @@ struct map *map__clone(struct map *map);
103int map__overlap(struct map *l, struct map *r); 103int map__overlap(struct map *l, struct map *r);
104size_t map__fprintf(struct map *map, FILE *fp); 104size_t map__fprintf(struct map *map, FILE *fp);
105size_t map__fprintf_dsoname(struct map *map, FILE *fp); 105size_t map__fprintf_dsoname(struct map *map, FILE *fp);
106int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
107 FILE *fp);
106 108
107int map__load(struct map *map, symbol_filter_t filter); 109int map__load(struct map *map, symbol_filter_t filter);
108struct symbol *map__find_symbol(struct map *map, 110struct symbol *map__find_symbol(struct map *map,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6de6f89c2a61..a7f1b6a91fdd 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -10,7 +10,7 @@
10#include "symbol.h" 10#include "symbol.h"
11#include "cache.h" 11#include "cache.h"
12#include "header.h" 12#include "header.h"
13#include <lk/debugfs.h> 13#include <api/fs/debugfs.h>
14#include "parse-events-bison.h" 14#include "parse-events-bison.h"
15#define YY_EXTRA_TYPE int 15#define YY_EXTRA_TYPE int
16#include "parse-events-flex.h" 16#include "parse-events-flex.h"
@@ -204,7 +204,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
204 } 204 }
205 path->name = malloc(MAX_EVENT_LENGTH); 205 path->name = malloc(MAX_EVENT_LENGTH);
206 if (!path->name) { 206 if (!path->name) {
207 free(path->system); 207 zfree(&path->system);
208 free(path); 208 free(path);
209 return NULL; 209 return NULL;
210 } 210 }
@@ -236,8 +236,8 @@ struct tracepoint_path *tracepoint_name_to_path(const char *name)
236 path->name = strdup(str+1); 236 path->name = strdup(str+1);
237 237
238 if (path->system == NULL || path->name == NULL) { 238 if (path->system == NULL || path->name == NULL) {
239 free(path->system); 239 zfree(&path->system);
240 free(path->name); 240 zfree(&path->name);
241 free(path); 241 free(path);
242 path = NULL; 242 path = NULL;
243 } 243 }
@@ -269,9 +269,10 @@ const char *event_type(int type)
269 269
270 270
271 271
272static int __add_event(struct list_head *list, int *idx, 272static struct perf_evsel *
273 struct perf_event_attr *attr, 273__add_event(struct list_head *list, int *idx,
274 char *name, struct cpu_map *cpus) 274 struct perf_event_attr *attr,
275 char *name, struct cpu_map *cpus)
275{ 276{
276 struct perf_evsel *evsel; 277 struct perf_evsel *evsel;
277 278
@@ -279,19 +280,19 @@ static int __add_event(struct list_head *list, int *idx,
279 280
280 evsel = perf_evsel__new_idx(attr, (*idx)++); 281 evsel = perf_evsel__new_idx(attr, (*idx)++);
281 if (!evsel) 282 if (!evsel)
282 return -ENOMEM; 283 return NULL;
283 284
284 evsel->cpus = cpus; 285 evsel->cpus = cpus;
285 if (name) 286 if (name)
286 evsel->name = strdup(name); 287 evsel->name = strdup(name);
287 list_add_tail(&evsel->node, list); 288 list_add_tail(&evsel->node, list);
288 return 0; 289 return evsel;
289} 290}
290 291
291static int add_event(struct list_head *list, int *idx, 292static int add_event(struct list_head *list, int *idx,
292 struct perf_event_attr *attr, char *name) 293 struct perf_event_attr *attr, char *name)
293{ 294{
294 return __add_event(list, idx, attr, name, NULL); 295 return __add_event(list, idx, attr, name, NULL) ? 0 : -ENOMEM;
295} 296}
296 297
297static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) 298static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
@@ -633,6 +634,9 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
633{ 634{
634 struct perf_event_attr attr; 635 struct perf_event_attr attr;
635 struct perf_pmu *pmu; 636 struct perf_pmu *pmu;
637 struct perf_evsel *evsel;
638 char *unit;
639 double scale;
636 640
637 pmu = perf_pmu__find(name); 641 pmu = perf_pmu__find(name);
638 if (!pmu) 642 if (!pmu)
@@ -640,7 +644,7 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
640 644
641 memset(&attr, 0, sizeof(attr)); 645 memset(&attr, 0, sizeof(attr));
642 646
643 if (perf_pmu__check_alias(pmu, head_config)) 647 if (perf_pmu__check_alias(pmu, head_config, &unit, &scale))
644 return -EINVAL; 648 return -EINVAL;
645 649
646 /* 650 /*
@@ -652,8 +656,14 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
652 if (perf_pmu__config(pmu, &attr, head_config)) 656 if (perf_pmu__config(pmu, &attr, head_config))
653 return -EINVAL; 657 return -EINVAL;
654 658
655 return __add_event(list, idx, &attr, pmu_event_name(head_config), 659 evsel = __add_event(list, idx, &attr, pmu_event_name(head_config),
656 pmu->cpus); 660 pmu->cpus);
661 if (evsel) {
662 evsel->unit = unit;
663 evsel->scale = scale;
664 }
665
666 return evsel ? 0 : -ENOMEM;
657} 667}
658 668
659int parse_events__modifier_group(struct list_head *list, 669int parse_events__modifier_group(struct list_head *list,
@@ -810,8 +820,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add)
810 if (!add && get_event_modifier(&mod, str, NULL)) 820 if (!add && get_event_modifier(&mod, str, NULL))
811 return -EINVAL; 821 return -EINVAL;
812 822
813 list_for_each_entry(evsel, list, node) { 823 __evlist__for_each(list, evsel) {
814
815 if (add && get_event_modifier(&mod, str, evsel)) 824 if (add && get_event_modifier(&mod, str, evsel))
816 return -EINVAL; 825 return -EINVAL;
817 826
@@ -835,7 +844,7 @@ int parse_events_name(struct list_head *list, char *name)
835{ 844{
836 struct perf_evsel *evsel; 845 struct perf_evsel *evsel;
837 846
838 list_for_each_entry(evsel, list, node) { 847 __evlist__for_each(list, evsel) {
839 if (!evsel->name) 848 if (!evsel->name)
840 evsel->name = strdup(name); 849 evsel->name = strdup(name);
841 } 850 }
@@ -907,7 +916,7 @@ int parse_events_terms(struct list_head *terms, const char *str)
907 ret = parse_events__scanner(str, &data, PE_START_TERMS); 916 ret = parse_events__scanner(str, &data, PE_START_TERMS);
908 if (!ret) { 917 if (!ret) {
909 list_splice(data.terms, terms); 918 list_splice(data.terms, terms);
910 free(data.terms); 919 zfree(&data.terms);
911 return 0; 920 return 0;
912 } 921 }
913 922
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 31f404a032a9..d22e3f8017dc 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -78,6 +78,8 @@ static int get_value(struct parse_opt_ctx_t *p,
78 78
79 case OPTION_BOOLEAN: 79 case OPTION_BOOLEAN:
80 *(bool *)opt->value = unset ? false : true; 80 *(bool *)opt->value = unset ? false : true;
81 if (opt->set)
82 *(bool *)opt->set = true;
81 return 0; 83 return 0;
82 84
83 case OPTION_INCR: 85 case OPTION_INCR:
@@ -224,6 +226,24 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
224 return 0; 226 return 0;
225 } 227 }
226 if (!rest) { 228 if (!rest) {
229 if (!prefixcmp(options->long_name, "no-")) {
230 /*
231 * The long name itself starts with "no-", so
232 * accept the option without "no-" so that users
233 * do not have to enter "no-no-" to get the
234 * negation.
235 */
236 rest = skip_prefix(arg, options->long_name + 3);
237 if (rest) {
238 flags |= OPT_UNSET;
239 goto match;
240 }
241 /* Abbreviated case */
242 if (!prefixcmp(options->long_name + 3, arg)) {
243 flags |= OPT_UNSET;
244 goto is_abbreviated;
245 }
246 }
227 /* abbreviated? */ 247 /* abbreviated? */
228 if (!strncmp(options->long_name, arg, arg_end - arg)) { 248 if (!strncmp(options->long_name, arg, arg_end - arg)) {
229is_abbreviated: 249is_abbreviated:
@@ -259,6 +279,7 @@ is_abbreviated:
259 if (!rest) 279 if (!rest)
260 continue; 280 continue;
261 } 281 }
282match:
262 if (*rest) { 283 if (*rest) {
263 if (*rest != '=') 284 if (*rest != '=')
264 continue; 285 continue;
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index b0241e28eaf7..cbf0149cf221 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -82,6 +82,9 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
82 * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in 82 * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in
83 * the value when met. 83 * the value when met.
84 * CALLBACKS can use it like they want. 84 * CALLBACKS can use it like they want.
85 *
86 * `set`::
87 * whether an option was set by the user
85 */ 88 */
86struct option { 89struct option {
87 enum parse_opt_type type; 90 enum parse_opt_type type;
@@ -94,6 +97,7 @@ struct option {
94 int flags; 97 int flags;
95 parse_opt_cb *callback; 98 parse_opt_cb *callback;
96 intptr_t defval; 99 intptr_t defval;
100 bool *set;
97}; 101};
98 102
99#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) 103#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
@@ -103,6 +107,10 @@ struct option {
103#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) } 107#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) }
104#define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) } 108#define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) }
105#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) } 109#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) }
110#define OPT_BOOLEAN_SET(s, l, v, os, h) \
111 { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), \
112 .value = check_vtype(v, bool *), .help = (h), \
113 .set = check_vtype(os, bool *)}
106#define OPT_INCR(s, l, v, h) { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) } 114#define OPT_INCR(s, l, v, h) { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
107#define OPT_SET_UINT(s, l, v, h, i) { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) } 115#define OPT_SET_UINT(s, l, v, h, i) { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) }
108#define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) } 116#define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index c232d8dd410b..d9cab4d27192 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1,19 +1,23 @@
1#include <linux/list.h> 1#include <linux/list.h>
2#include <sys/types.h> 2#include <sys/types.h>
3#include <sys/stat.h>
4#include <unistd.h> 3#include <unistd.h>
5#include <stdio.h> 4#include <stdio.h>
6#include <dirent.h> 5#include <dirent.h>
7#include "fs.h" 6#include "fs.h"
7#include <locale.h>
8#include "util.h" 8#include "util.h"
9#include "pmu.h" 9#include "pmu.h"
10#include "parse-events.h" 10#include "parse-events.h"
11#include "cpumap.h" 11#include "cpumap.h"
12 12
13#define UNIT_MAX_LEN 31 /* max length for event unit name */
14
13struct perf_pmu_alias { 15struct perf_pmu_alias {
14 char *name; 16 char *name;
15 struct list_head terms; 17 struct list_head terms;
16 struct list_head list; 18 struct list_head list;
19 char unit[UNIT_MAX_LEN+1];
20 double scale;
17}; 21};
18 22
19struct perf_pmu_format { 23struct perf_pmu_format {
@@ -94,7 +98,80 @@ static int pmu_format(const char *name, struct list_head *format)
94 return 0; 98 return 0;
95} 99}
96 100
97static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) 101static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name)
102{
103 struct stat st;
104 ssize_t sret;
105 char scale[128];
106 int fd, ret = -1;
107 char path[PATH_MAX];
108 char *lc;
109
110 snprintf(path, PATH_MAX, "%s/%s.scale", dir, name);
111
112 fd = open(path, O_RDONLY);
113 if (fd == -1)
114 return -1;
115
116 if (fstat(fd, &st) < 0)
117 goto error;
118
119 sret = read(fd, scale, sizeof(scale)-1);
120 if (sret < 0)
121 goto error;
122
123 scale[sret] = '\0';
124 /*
125 * save current locale
126 */
127 lc = setlocale(LC_NUMERIC, NULL);
128
129 /*
130 * force to C locale to ensure kernel
131 * scale string is converted correctly.
132 * kernel uses default C locale.
133 */
134 setlocale(LC_NUMERIC, "C");
135
136 alias->scale = strtod(scale, NULL);
137
138 /* restore locale */
139 setlocale(LC_NUMERIC, lc);
140
141 ret = 0;
142error:
143 close(fd);
144 return ret;
145}
146
147static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name)
148{
149 char path[PATH_MAX];
150 ssize_t sret;
151 int fd;
152
153 snprintf(path, PATH_MAX, "%s/%s.unit", dir, name);
154
155 fd = open(path, O_RDONLY);
156 if (fd == -1)
157 return -1;
158
159 sret = read(fd, alias->unit, UNIT_MAX_LEN);
160 if (sret < 0)
161 goto error;
162
163 close(fd);
164
165 alias->unit[sret] = '\0';
166
167 return 0;
168error:
169 close(fd);
170 alias->unit[0] = '\0';
171 return -1;
172}
173
174static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
98{ 175{
99 struct perf_pmu_alias *alias; 176 struct perf_pmu_alias *alias;
100 char buf[256]; 177 char buf[256];
@@ -110,6 +187,9 @@ static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
110 return -ENOMEM; 187 return -ENOMEM;
111 188
112 INIT_LIST_HEAD(&alias->terms); 189 INIT_LIST_HEAD(&alias->terms);
190 alias->scale = 1.0;
191 alias->unit[0] = '\0';
192
113 ret = parse_events_terms(&alias->terms, buf); 193 ret = parse_events_terms(&alias->terms, buf);
114 if (ret) { 194 if (ret) {
115 free(alias); 195 free(alias);
@@ -117,7 +197,14 @@ static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
117 } 197 }
118 198
119 alias->name = strdup(name); 199 alias->name = strdup(name);
200 /*
201 * load unit name and scale if available
202 */
203 perf_pmu__parse_unit(alias, dir, name);
204 perf_pmu__parse_scale(alias, dir, name);
205
120 list_add_tail(&alias->list, list); 206 list_add_tail(&alias->list, list);
207
121 return 0; 208 return 0;
122} 209}
123 210
@@ -129,6 +216,7 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
129{ 216{
130 struct dirent *evt_ent; 217 struct dirent *evt_ent;
131 DIR *event_dir; 218 DIR *event_dir;
219 size_t len;
132 int ret = 0; 220 int ret = 0;
133 221
134 event_dir = opendir(dir); 222 event_dir = opendir(dir);
@@ -143,13 +231,24 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
143 if (!strcmp(name, ".") || !strcmp(name, "..")) 231 if (!strcmp(name, ".") || !strcmp(name, ".."))
144 continue; 232 continue;
145 233
234 /*
235 * skip .unit and .scale info files
236 * parsed in perf_pmu__new_alias()
237 */
238 len = strlen(name);
239 if (len > 5 && !strcmp(name + len - 5, ".unit"))
240 continue;
241 if (len > 6 && !strcmp(name + len - 6, ".scale"))
242 continue;
243
146 snprintf(path, PATH_MAX, "%s/%s", dir, name); 244 snprintf(path, PATH_MAX, "%s/%s", dir, name);
147 245
148 ret = -EINVAL; 246 ret = -EINVAL;
149 file = fopen(path, "r"); 247 file = fopen(path, "r");
150 if (!file) 248 if (!file)
151 break; 249 break;
152 ret = perf_pmu__new_alias(head, name, file); 250
251 ret = perf_pmu__new_alias(head, dir, name, file);
153 fclose(file); 252 fclose(file);
154 } 253 }
155 254
@@ -406,7 +505,7 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value)
406 505
407/* 506/*
408 * Setup one of config[12] attr members based on the 507 * Setup one of config[12] attr members based on the
409 * user input data - temr parameter. 508 * user input data - term parameter.
410 */ 509 */
411static int pmu_config_term(struct list_head *formats, 510static int pmu_config_term(struct list_head *formats,
412 struct perf_event_attr *attr, 511 struct perf_event_attr *attr,
@@ -508,16 +607,42 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
508 return NULL; 607 return NULL;
509} 608}
510 609
610
611static int check_unit_scale(struct perf_pmu_alias *alias,
612 char **unit, double *scale)
613{
614 /*
615 * Only one term in event definition can
616 * define unit and scale, fail if there's
617 * more than one.
618 */
619 if ((*unit && alias->unit) ||
620 (*scale && alias->scale))
621 return -EINVAL;
622
623 if (alias->unit)
624 *unit = alias->unit;
625
626 if (alias->scale)
627 *scale = alias->scale;
628
629 return 0;
630}
631
511/* 632/*
512 * Find alias in the terms list and replace it with the terms 633 * Find alias in the terms list and replace it with the terms
513 * defined for the alias 634 * defined for the alias
514 */ 635 */
515int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) 636int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
637 char **unit, double *scale)
516{ 638{
517 struct parse_events_term *term, *h; 639 struct parse_events_term *term, *h;
518 struct perf_pmu_alias *alias; 640 struct perf_pmu_alias *alias;
519 int ret; 641 int ret;
520 642
643 *unit = NULL;
644 *scale = 0;
645
521 list_for_each_entry_safe(term, h, head_terms, list) { 646 list_for_each_entry_safe(term, h, head_terms, list) {
522 alias = pmu_find_alias(pmu, term); 647 alias = pmu_find_alias(pmu, term);
523 if (!alias) 648 if (!alias)
@@ -525,6 +650,11 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
525 ret = pmu_alias_terms(alias, &term->list); 650 ret = pmu_alias_terms(alias, &term->list);
526 if (ret) 651 if (ret)
527 return ret; 652 return ret;
653
654 ret = check_unit_scale(alias, unit, scale);
655 if (ret)
656 return ret;
657
528 list_del(&term->list); 658 list_del(&term->list);
529 free(term); 659 free(term);
530 } 660 }
@@ -625,7 +755,7 @@ void print_pmu_events(const char *event_glob, bool name_only)
625 continue; 755 continue;
626 } 756 }
627 printf(" %-50s [Kernel PMU event]\n", aliases[j]); 757 printf(" %-50s [Kernel PMU event]\n", aliases[j]);
628 free(aliases[j]); 758 zfree(&aliases[j]);
629 printed++; 759 printed++;
630 } 760 }
631 if (printed) 761 if (printed)
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 1179b26f244a..9183380e2038 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -28,7 +28,8 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
28int perf_pmu__config_terms(struct list_head *formats, 28int perf_pmu__config_terms(struct list_head *formats,
29 struct perf_event_attr *attr, 29 struct perf_event_attr *attr,
30 struct list_head *head_terms); 30 struct list_head *head_terms);
31int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); 31int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
32 char **unit, double *scale);
32struct list_head *perf_pmu__alias(struct perf_pmu *pmu, 33struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
33 struct list_head *head_terms); 34 struct list_head *head_terms);
34int perf_pmu_wrap(void); 35int perf_pmu_wrap(void);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 9c6989ca2bea..a8a9b6cd93a8 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -40,7 +40,7 @@
40#include "color.h" 40#include "color.h"
41#include "symbol.h" 41#include "symbol.h"
42#include "thread.h" 42#include "thread.h"
43#include <lk/debugfs.h> 43#include <api/fs/debugfs.h>
44#include "trace-event.h" /* For __maybe_unused */ 44#include "trace-event.h" /* For __maybe_unused */
45#include "probe-event.h" 45#include "probe-event.h"
46#include "probe-finder.h" 46#include "probe-finder.h"
@@ -72,6 +72,7 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
72static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 72static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
73static int convert_name_to_addr(struct perf_probe_event *pev, 73static int convert_name_to_addr(struct perf_probe_event *pev,
74 const char *exec); 74 const char *exec);
75static void clear_probe_trace_event(struct probe_trace_event *tev);
75static struct machine machine; 76static struct machine machine;
76 77
77/* Initialize symbol maps and path of vmlinux/modules */ 78/* Initialize symbol maps and path of vmlinux/modules */
@@ -154,7 +155,7 @@ static struct dso *kernel_get_module_dso(const char *module)
154 155
155 vmlinux_name = symbol_conf.vmlinux_name; 156 vmlinux_name = symbol_conf.vmlinux_name;
156 if (vmlinux_name) { 157 if (vmlinux_name) {
157 if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0) 158 if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0)
158 return NULL; 159 return NULL;
159 } else { 160 } else {
160 if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { 161 if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
@@ -186,6 +187,37 @@ static int init_user_exec(void)
186 return ret; 187 return ret;
187} 188}
188 189
190static int convert_exec_to_group(const char *exec, char **result)
191{
192 char *ptr1, *ptr2, *exec_copy;
193 char buf[64];
194 int ret;
195
196 exec_copy = strdup(exec);
197 if (!exec_copy)
198 return -ENOMEM;
199
200 ptr1 = basename(exec_copy);
201 if (!ptr1) {
202 ret = -EINVAL;
203 goto out;
204 }
205
206 ptr2 = strpbrk(ptr1, "-._");
207 if (ptr2)
208 *ptr2 = '\0';
209 ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1);
210 if (ret < 0)
211 goto out;
212
213 *result = strdup(buf);
214 ret = *result ? 0 : -ENOMEM;
215
216out:
217 free(exec_copy);
218 return ret;
219}
220
189static int convert_to_perf_probe_point(struct probe_trace_point *tp, 221static int convert_to_perf_probe_point(struct probe_trace_point *tp,
190 struct perf_probe_point *pp) 222 struct perf_probe_point *pp)
191{ 223{
@@ -261,6 +293,68 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
261 return 0; 293 return 0;
262} 294}
263 295
296static int get_text_start_address(const char *exec, unsigned long *address)
297{
298 Elf *elf;
299 GElf_Ehdr ehdr;
300 GElf_Shdr shdr;
301 int fd, ret = -ENOENT;
302
303 fd = open(exec, O_RDONLY);
304 if (fd < 0)
305 return -errno;
306
307 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
308 if (elf == NULL)
309 return -EINVAL;
310
311 if (gelf_getehdr(elf, &ehdr) == NULL)
312 goto out;
313
314 if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL))
315 goto out;
316
317 *address = shdr.sh_addr - shdr.sh_offset;
318 ret = 0;
319out:
320 elf_end(elf);
321 return ret;
322}
323
324static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
325 int ntevs, const char *exec)
326{
327 int i, ret = 0;
328 unsigned long offset, stext = 0;
329 char buf[32];
330
331 if (!exec)
332 return 0;
333
334 ret = get_text_start_address(exec, &stext);
335 if (ret < 0)
336 return ret;
337
338 for (i = 0; i < ntevs && ret >= 0; i++) {
339 offset = tevs[i].point.address - stext;
340 offset += tevs[i].point.offset;
341 tevs[i].point.offset = 0;
342 zfree(&tevs[i].point.symbol);
343 ret = e_snprintf(buf, 32, "0x%lx", offset);
344 if (ret < 0)
345 break;
346 tevs[i].point.module = strdup(exec);
347 tevs[i].point.symbol = strdup(buf);
348 if (!tevs[i].point.symbol || !tevs[i].point.module) {
349 ret = -ENOMEM;
350 break;
351 }
352 tevs[i].uprobes = true;
353 }
354
355 return ret;
356}
357
264static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, 358static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
265 int ntevs, const char *module) 359 int ntevs, const char *module)
266{ 360{
@@ -290,12 +384,18 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
290 } 384 }
291 } 385 }
292 386
293 if (tmp) 387 free(tmp);
294 free(tmp);
295
296 return ret; 388 return ret;
297} 389}
298 390
391static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
392{
393 int i;
394
395 for (i = 0; i < ntevs; i++)
396 clear_probe_trace_event(tevs + i);
397}
398
299/* Try to find perf_probe_event with debuginfo */ 399/* Try to find perf_probe_event with debuginfo */
300static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 400static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
301 struct probe_trace_event **tevs, 401 struct probe_trace_event **tevs,
@@ -305,15 +405,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
305 struct debuginfo *dinfo; 405 struct debuginfo *dinfo;
306 int ntevs, ret = 0; 406 int ntevs, ret = 0;
307 407
308 if (pev->uprobes) {
309 if (need_dwarf) {
310 pr_warning("Debuginfo-analysis is not yet supported"
311 " with -x/--exec option.\n");
312 return -ENOSYS;
313 }
314 return convert_name_to_addr(pev, target);
315 }
316
317 dinfo = open_debuginfo(target); 408 dinfo = open_debuginfo(target);
318 409
319 if (!dinfo) { 410 if (!dinfo) {
@@ -332,9 +423,18 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
332 423
333 if (ntevs > 0) { /* Succeeded to find trace events */ 424 if (ntevs > 0) { /* Succeeded to find trace events */
334 pr_debug("find %d probe_trace_events.\n", ntevs); 425 pr_debug("find %d probe_trace_events.\n", ntevs);
335 if (target) 426 if (target) {
336 ret = add_module_to_probe_trace_events(*tevs, ntevs, 427 if (pev->uprobes)
337 target); 428 ret = add_exec_to_probe_trace_events(*tevs,
429 ntevs, target);
430 else
431 ret = add_module_to_probe_trace_events(*tevs,
432 ntevs, target);
433 }
434 if (ret < 0) {
435 clear_probe_trace_events(*tevs, ntevs);
436 zfree(tevs);
437 }
338 return ret < 0 ? ret : ntevs; 438 return ret < 0 ? ret : ntevs;
339 } 439 }
340 440
@@ -401,15 +501,13 @@ static int get_real_path(const char *raw_path, const char *comp_dir,
401 case EFAULT: 501 case EFAULT:
402 raw_path = strchr(++raw_path, '/'); 502 raw_path = strchr(++raw_path, '/');
403 if (!raw_path) { 503 if (!raw_path) {
404 free(*new_path); 504 zfree(new_path);
405 *new_path = NULL;
406 return -ENOENT; 505 return -ENOENT;
407 } 506 }
408 continue; 507 continue;
409 508
410 default: 509 default:
411 free(*new_path); 510 zfree(new_path);
412 *new_path = NULL;
413 return -errno; 511 return -errno;
414 } 512 }
415 } 513 }
@@ -580,7 +678,7 @@ static int show_available_vars_at(struct debuginfo *dinfo,
580 */ 678 */
581 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, 679 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
582 vl->point.offset); 680 vl->point.offset);
583 free(vl->point.symbol); 681 zfree(&vl->point.symbol);
584 nvars = 0; 682 nvars = 0;
585 if (vl->vars) { 683 if (vl->vars) {
586 strlist__for_each(node, vl->vars) { 684 strlist__for_each(node, vl->vars) {
@@ -647,16 +745,14 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
647 745
648static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 746static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
649 struct probe_trace_event **tevs __maybe_unused, 747 struct probe_trace_event **tevs __maybe_unused,
650 int max_tevs __maybe_unused, const char *target) 748 int max_tevs __maybe_unused,
749 const char *target __maybe_unused)
651{ 750{
652 if (perf_probe_event_need_dwarf(pev)) { 751 if (perf_probe_event_need_dwarf(pev)) {
653 pr_warning("Debuginfo-analysis is not supported.\n"); 752 pr_warning("Debuginfo-analysis is not supported.\n");
654 return -ENOSYS; 753 return -ENOSYS;
655 } 754 }
656 755
657 if (pev->uprobes)
658 return convert_name_to_addr(pev, target);
659
660 return 0; 756 return 0;
661} 757}
662 758
@@ -678,6 +774,28 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
678} 774}
679#endif 775#endif
680 776
777void line_range__clear(struct line_range *lr)
778{
779 struct line_node *ln;
780
781 free(lr->function);
782 free(lr->file);
783 free(lr->path);
784 free(lr->comp_dir);
785 while (!list_empty(&lr->line_list)) {
786 ln = list_first_entry(&lr->line_list, struct line_node, list);
787 list_del(&ln->list);
788 free(ln);
789 }
790 memset(lr, 0, sizeof(*lr));
791}
792
793void line_range__init(struct line_range *lr)
794{
795 memset(lr, 0, sizeof(*lr));
796 INIT_LIST_HEAD(&lr->line_list);
797}
798
681static int parse_line_num(char **ptr, int *val, const char *what) 799static int parse_line_num(char **ptr, int *val, const char *what)
682{ 800{
683 const char *start = *ptr; 801 const char *start = *ptr;
@@ -1278,8 +1396,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
1278error: 1396error:
1279 pr_debug("Failed to synthesize perf probe point: %s\n", 1397 pr_debug("Failed to synthesize perf probe point: %s\n",
1280 strerror(-ret)); 1398 strerror(-ret));
1281 if (buf) 1399 free(buf);
1282 free(buf);
1283 return NULL; 1400 return NULL;
1284} 1401}
1285 1402
@@ -1480,34 +1597,25 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
1480 struct perf_probe_arg_field *field, *next; 1597 struct perf_probe_arg_field *field, *next;
1481 int i; 1598 int i;
1482 1599
1483 if (pev->event) 1600 free(pev->event);
1484 free(pev->event); 1601 free(pev->group);
1485 if (pev->group) 1602 free(pp->file);
1486 free(pev->group); 1603 free(pp->function);
1487 if (pp->file) 1604 free(pp->lazy_line);
1488 free(pp->file); 1605
1489 if (pp->function)
1490 free(pp->function);
1491 if (pp->lazy_line)
1492 free(pp->lazy_line);
1493 for (i = 0; i < pev->nargs; i++) { 1606 for (i = 0; i < pev->nargs; i++) {
1494 if (pev->args[i].name) 1607 free(pev->args[i].name);
1495 free(pev->args[i].name); 1608 free(pev->args[i].var);
1496 if (pev->args[i].var) 1609 free(pev->args[i].type);
1497 free(pev->args[i].var);
1498 if (pev->args[i].type)
1499 free(pev->args[i].type);
1500 field = pev->args[i].field; 1610 field = pev->args[i].field;
1501 while (field) { 1611 while (field) {
1502 next = field->next; 1612 next = field->next;
1503 if (field->name) 1613 zfree(&field->name);
1504 free(field->name);
1505 free(field); 1614 free(field);
1506 field = next; 1615 field = next;
1507 } 1616 }
1508 } 1617 }
1509 if (pev->args) 1618 free(pev->args);
1510 free(pev->args);
1511 memset(pev, 0, sizeof(*pev)); 1619 memset(pev, 0, sizeof(*pev));
1512} 1620}
1513 1621
@@ -1516,21 +1624,14 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
1516 struct probe_trace_arg_ref *ref, *next; 1624 struct probe_trace_arg_ref *ref, *next;
1517 int i; 1625 int i;
1518 1626
1519 if (tev->event) 1627 free(tev->event);
1520 free(tev->event); 1628 free(tev->group);
1521 if (tev->group) 1629 free(tev->point.symbol);
1522 free(tev->group); 1630 free(tev->point.module);
1523 if (tev->point.symbol)
1524 free(tev->point.symbol);
1525 if (tev->point.module)
1526 free(tev->point.module);
1527 for (i = 0; i < tev->nargs; i++) { 1631 for (i = 0; i < tev->nargs; i++) {
1528 if (tev->args[i].name) 1632 free(tev->args[i].name);
1529 free(tev->args[i].name); 1633 free(tev->args[i].value);
1530 if (tev->args[i].value) 1634 free(tev->args[i].type);
1531 free(tev->args[i].value);
1532 if (tev->args[i].type)
1533 free(tev->args[i].type);
1534 ref = tev->args[i].ref; 1635 ref = tev->args[i].ref;
1535 while (ref) { 1636 while (ref) {
1536 next = ref->next; 1637 next = ref->next;
@@ -1538,8 +1639,7 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
1538 ref = next; 1639 ref = next;
1539 } 1640 }
1540 } 1641 }
1541 if (tev->args) 1642 free(tev->args);
1542 free(tev->args);
1543 memset(tev, 0, sizeof(*tev)); 1643 memset(tev, 0, sizeof(*tev));
1544} 1644}
1545 1645
@@ -1913,14 +2013,29 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1913 int max_tevs, const char *target) 2013 int max_tevs, const char *target)
1914{ 2014{
1915 struct symbol *sym; 2015 struct symbol *sym;
1916 int ret = 0, i; 2016 int ret, i;
1917 struct probe_trace_event *tev; 2017 struct probe_trace_event *tev;
1918 2018
2019 if (pev->uprobes && !pev->group) {
2020 /* Replace group name if not given */
2021 ret = convert_exec_to_group(target, &pev->group);
2022 if (ret != 0) {
2023 pr_warning("Failed to make a group name.\n");
2024 return ret;
2025 }
2026 }
2027
1919 /* Convert perf_probe_event with debuginfo */ 2028 /* Convert perf_probe_event with debuginfo */
1920 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); 2029 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
1921 if (ret != 0) 2030 if (ret != 0)
1922 return ret; /* Found in debuginfo or got an error */ 2031 return ret; /* Found in debuginfo or got an error */
1923 2032
2033 if (pev->uprobes) {
2034 ret = convert_name_to_addr(pev, target);
2035 if (ret < 0)
2036 return ret;
2037 }
2038
1924 /* Allocate trace event buffer */ 2039 /* Allocate trace event buffer */
1925 tev = *tevs = zalloc(sizeof(struct probe_trace_event)); 2040 tev = *tevs = zalloc(sizeof(struct probe_trace_event));
1926 if (tev == NULL) 2041 if (tev == NULL)
@@ -2056,7 +2171,7 @@ end:
2056 for (i = 0; i < npevs; i++) { 2171 for (i = 0; i < npevs; i++) {
2057 for (j = 0; j < pkgs[i].ntevs; j++) 2172 for (j = 0; j < pkgs[i].ntevs; j++)
2058 clear_probe_trace_event(&pkgs[i].tevs[j]); 2173 clear_probe_trace_event(&pkgs[i].tevs[j]);
2059 free(pkgs[i].tevs); 2174 zfree(&pkgs[i].tevs);
2060 } 2175 }
2061 free(pkgs); 2176 free(pkgs);
2062 2177
@@ -2281,7 +2396,7 @@ static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
2281 struct perf_probe_point *pp = &pev->point; 2396 struct perf_probe_point *pp = &pev->point;
2282 struct symbol *sym; 2397 struct symbol *sym;
2283 struct map *map = NULL; 2398 struct map *map = NULL;
2284 char *function = NULL, *name = NULL; 2399 char *function = NULL;
2285 int ret = -EINVAL; 2400 int ret = -EINVAL;
2286 unsigned long long vaddr = 0; 2401 unsigned long long vaddr = 0;
2287 2402
@@ -2297,12 +2412,7 @@ static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
2297 goto out; 2412 goto out;
2298 } 2413 }
2299 2414
2300 name = realpath(exec, NULL); 2415 map = dso__new_map(exec);
2301 if (!name) {
2302 pr_warning("Cannot find realpath for %s.\n", exec);
2303 goto out;
2304 }
2305 map = dso__new_map(name);
2306 if (!map) { 2416 if (!map) {
2307 pr_warning("Cannot find appropriate DSO for %s.\n", exec); 2417 pr_warning("Cannot find appropriate DSO for %s.\n", exec);
2308 goto out; 2418 goto out;
@@ -2367,7 +2477,5 @@ out:
2367 } 2477 }
2368 if (function) 2478 if (function)
2369 free(function); 2479 free(function);
2370 if (name)
2371 free(name);
2372 return ret; 2480 return ret;
2373} 2481}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index f9f3de8b4220..fcaf7273e85a 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -12,6 +12,7 @@ struct probe_trace_point {
12 char *symbol; /* Base symbol */ 12 char *symbol; /* Base symbol */
13 char *module; /* Module name */ 13 char *module; /* Module name */
14 unsigned long offset; /* Offset from symbol */ 14 unsigned long offset; /* Offset from symbol */
15 unsigned long address; /* Actual address of the trace point */
15 bool retprobe; /* Return probe flag */ 16 bool retprobe; /* Return probe flag */
16}; 17};
17 18
@@ -119,6 +120,12 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev);
119/* Command string to line-range */ 120/* Command string to line-range */
120extern int parse_line_range_desc(const char *cmd, struct line_range *lr); 121extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
121 122
123/* Release line range members */
124extern void line_range__clear(struct line_range *lr);
125
126/* Initialize line range */
127extern void line_range__init(struct line_range *lr);
128
122/* Internal use: Return kernel/module path */ 129/* Internal use: Return kernel/module path */
123extern const char *kernel_get_module_path(const char *module); 130extern const char *kernel_get_module_path(const char *module);
124 131
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index ffb657ffd327..061edb162b5b 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -226,10 +226,8 @@ struct debuginfo *debuginfo__new(const char *path)
226 if (!dbg) 226 if (!dbg)
227 return NULL; 227 return NULL;
228 228
229 if (debuginfo__init_offline_dwarf(dbg, path) < 0) { 229 if (debuginfo__init_offline_dwarf(dbg, path) < 0)
230 free(dbg); 230 zfree(&dbg);
231 dbg = NULL;
232 }
233 231
234 return dbg; 232 return dbg;
235} 233}
@@ -241,10 +239,8 @@ struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
241 if (!dbg) 239 if (!dbg)
242 return NULL; 240 return NULL;
243 241
244 if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0) { 242 if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0)
245 free(dbg); 243 zfree(&dbg);
246 dbg = NULL;
247 }
248 244
249 return dbg; 245 return dbg;
250} 246}
@@ -729,6 +725,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
729 return -ENOENT; 725 return -ENOENT;
730 } 726 }
731 tp->offset = (unsigned long)(paddr - sym.st_value); 727 tp->offset = (unsigned long)(paddr - sym.st_value);
728 tp->address = (unsigned long)paddr;
732 tp->symbol = strdup(symbol); 729 tp->symbol = strdup(symbol);
733 if (!tp->symbol) 730 if (!tp->symbol)
734 return -ENOMEM; 731 return -ENOMEM;
@@ -1301,8 +1298,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
1301 1298
1302 ret = debuginfo__find_probes(dbg, &tf.pf); 1299 ret = debuginfo__find_probes(dbg, &tf.pf);
1303 if (ret < 0) { 1300 if (ret < 0) {
1304 free(*tevs); 1301 zfree(tevs);
1305 *tevs = NULL;
1306 return ret; 1302 return ret;
1307 } 1303 }
1308 1304
@@ -1413,13 +1409,10 @@ int debuginfo__find_available_vars_at(struct debuginfo *dbg,
1413 if (ret < 0) { 1409 if (ret < 0) {
1414 /* Free vlist for error */ 1410 /* Free vlist for error */
1415 while (af.nvls--) { 1411 while (af.nvls--) {
1416 if (af.vls[af.nvls].point.symbol) 1412 zfree(&af.vls[af.nvls].point.symbol);
1417 free(af.vls[af.nvls].point.symbol); 1413 strlist__delete(af.vls[af.nvls].vars);
1418 if (af.vls[af.nvls].vars)
1419 strlist__delete(af.vls[af.nvls].vars);
1420 } 1414 }
1421 free(af.vls); 1415 zfree(vls);
1422 *vls = NULL;
1423 return ret; 1416 return ret;
1424 } 1417 }
1425 1418
@@ -1523,10 +1516,7 @@ post:
1523 if (fname) { 1516 if (fname) {
1524 ppt->file = strdup(fname); 1517 ppt->file = strdup(fname);
1525 if (ppt->file == NULL) { 1518 if (ppt->file == NULL) {
1526 if (ppt->function) { 1519 zfree(&ppt->function);
1527 free(ppt->function);
1528 ppt->function = NULL;
1529 }
1530 ret = -ENOMEM; 1520 ret = -ENOMEM;
1531 goto end; 1521 goto end;
1532 } 1522 }
@@ -1580,8 +1570,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1580 else 1570 else
1581 ret = 0; /* Lines are not found */ 1571 ret = 0; /* Lines are not found */
1582 else { 1572 else {
1583 free(lf->lr->path); 1573 zfree(&lf->lr->path);
1584 lf->lr->path = NULL;
1585 } 1574 }
1586 return ret; 1575 return ret;
1587} 1576}
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 239036fb2b2c..595bfc73d2ed 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -18,4 +18,5 @@ util/cgroup.c
18util/rblist.c 18util/rblist.c
19util/strlist.c 19util/strlist.c
20util/fs.c 20util/fs.c
21util/trace-event.c
21../../lib/rbtree.c 22../../lib/rbtree.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 4bf8ace7f511..122669c18ff4 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -908,9 +908,10 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
908 if (i >= pevlist->evlist.nr_entries) 908 if (i >= pevlist->evlist.nr_entries)
909 return NULL; 909 return NULL;
910 910
911 list_for_each_entry(pos, &pevlist->evlist.entries, node) 911 evlist__for_each(&pevlist->evlist, pos) {
912 if (i-- == 0) 912 if (i-- == 0)
913 break; 913 break;
914 }
914 915
915 return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel)); 916 return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
916} 917}
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index c8845b107f60..373762501dad 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -74,8 +74,7 @@ bool perf_can_sample_identifier(void)
74 return perf_probe_api(perf_probe_sample_identifier); 74 return perf_probe_api(perf_probe_sample_identifier);
75} 75}
76 76
77void perf_evlist__config(struct perf_evlist *evlist, 77void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
78 struct perf_record_opts *opts)
79{ 78{
80 struct perf_evsel *evsel; 79 struct perf_evsel *evsel;
81 bool use_sample_identifier = false; 80 bool use_sample_identifier = false;
@@ -90,19 +89,19 @@ void perf_evlist__config(struct perf_evlist *evlist,
90 if (evlist->cpus->map[0] < 0) 89 if (evlist->cpus->map[0] < 0)
91 opts->no_inherit = true; 90 opts->no_inherit = true;
92 91
93 list_for_each_entry(evsel, &evlist->entries, node) 92 evlist__for_each(evlist, evsel)
94 perf_evsel__config(evsel, opts); 93 perf_evsel__config(evsel, opts);
95 94
96 if (evlist->nr_entries > 1) { 95 if (evlist->nr_entries > 1) {
97 struct perf_evsel *first = perf_evlist__first(evlist); 96 struct perf_evsel *first = perf_evlist__first(evlist);
98 97
99 list_for_each_entry(evsel, &evlist->entries, node) { 98 evlist__for_each(evlist, evsel) {
100 if (evsel->attr.sample_type == first->attr.sample_type) 99 if (evsel->attr.sample_type == first->attr.sample_type)
101 continue; 100 continue;
102 use_sample_identifier = perf_can_sample_identifier(); 101 use_sample_identifier = perf_can_sample_identifier();
103 break; 102 break;
104 } 103 }
105 list_for_each_entry(evsel, &evlist->entries, node) 104 evlist__for_each(evlist, evsel)
106 perf_evsel__set_sample_id(evsel, use_sample_identifier); 105 perf_evsel__set_sample_id(evsel, use_sample_identifier);
107 } 106 }
108 107
@@ -123,7 +122,7 @@ static int get_max_rate(unsigned int *rate)
123 return filename__read_int(path, (int *) rate); 122 return filename__read_int(path, (int *) rate);
124} 123}
125 124
126static int perf_record_opts__config_freq(struct perf_record_opts *opts) 125static int record_opts__config_freq(struct record_opts *opts)
127{ 126{
128 bool user_freq = opts->user_freq != UINT_MAX; 127 bool user_freq = opts->user_freq != UINT_MAX;
129 unsigned int max_rate; 128 unsigned int max_rate;
@@ -173,7 +172,44 @@ static int perf_record_opts__config_freq(struct perf_record_opts *opts)
173 return 0; 172 return 0;
174} 173}
175 174
176int perf_record_opts__config(struct perf_record_opts *opts) 175int record_opts__config(struct record_opts *opts)
177{ 176{
178 return perf_record_opts__config_freq(opts); 177 return record_opts__config_freq(opts);
178}
179
180bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
181{
182 struct perf_evlist *temp_evlist;
183 struct perf_evsel *evsel;
184 int err, fd, cpu;
185 bool ret = false;
186
187 temp_evlist = perf_evlist__new();
188 if (!temp_evlist)
189 return false;
190
191 err = parse_events(temp_evlist, str);
192 if (err)
193 goto out_delete;
194
195 evsel = perf_evlist__last(temp_evlist);
196
197 if (!evlist || cpu_map__empty(evlist->cpus)) {
198 struct cpu_map *cpus = cpu_map__new(NULL);
199
200 cpu = cpus ? cpus->map[0] : 0;
201 cpu_map__delete(cpus);
202 } else {
203 cpu = evlist->cpus->map[0];
204 }
205
206 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0);
207 if (fd >= 0) {
208 close(fd);
209 ret = true;
210 }
211
212out_delete:
213 perf_evlist__delete(temp_evlist);
214 return ret;
179} 215}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index d5e5969f6fea..e108207c5de0 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -194,8 +194,7 @@ static void define_event_symbols(struct event_format *event,
194 zero_flag_atom = 0; 194 zero_flag_atom = 0;
195 break; 195 break;
196 case PRINT_FIELD: 196 case PRINT_FIELD:
197 if (cur_field_name) 197 free(cur_field_name);
198 free(cur_field_name);
199 cur_field_name = strdup(args->field.name); 198 cur_field_name = strdup(args->field.name);
200 break; 199 break;
201 case PRINT_FLAGS: 200 case PRINT_FLAGS:
@@ -257,12 +256,9 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
257 return event; 256 return event;
258} 257}
259 258
260static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, 259static void perl_process_tracepoint(struct perf_sample *sample,
261 struct perf_sample *sample,
262 struct perf_evsel *evsel, 260 struct perf_evsel *evsel,
263 struct machine *machine __maybe_unused, 261 struct thread *thread)
264 struct thread *thread,
265 struct addr_location *al)
266{ 262{
267 struct format_field *field; 263 struct format_field *field;
268 static char handler[256]; 264 static char handler[256];
@@ -349,10 +345,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
349 345
350static void perl_process_event_generic(union perf_event *event, 346static void perl_process_event_generic(union perf_event *event,
351 struct perf_sample *sample, 347 struct perf_sample *sample,
352 struct perf_evsel *evsel, 348 struct perf_evsel *evsel)
353 struct machine *machine __maybe_unused,
354 struct thread *thread __maybe_unused,
355 struct addr_location *al __maybe_unused)
356{ 349{
357 dSP; 350 dSP;
358 351
@@ -377,12 +370,11 @@ static void perl_process_event_generic(union perf_event *event,
377static void perl_process_event(union perf_event *event, 370static void perl_process_event(union perf_event *event,
378 struct perf_sample *sample, 371 struct perf_sample *sample,
379 struct perf_evsel *evsel, 372 struct perf_evsel *evsel,
380 struct machine *machine,
381 struct thread *thread, 373 struct thread *thread,
382 struct addr_location *al) 374 struct addr_location *al __maybe_unused)
383{ 375{
384 perl_process_tracepoint(event, sample, evsel, machine, thread, al); 376 perl_process_tracepoint(sample, evsel, thread);
385 perl_process_event_generic(event, sample, evsel, machine, thread, al); 377 perl_process_event_generic(event, sample, evsel);
386} 378}
387 379
388static void run_start_sub(void) 380static void run_start_sub(void)
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 53c20e7fd900..cd9774df3750 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -161,8 +161,7 @@ static void define_event_symbols(struct event_format *event,
161 zero_flag_atom = 0; 161 zero_flag_atom = 0;
162 break; 162 break;
163 case PRINT_FIELD: 163 case PRINT_FIELD:
164 if (cur_field_name) 164 free(cur_field_name);
165 free(cur_field_name);
166 cur_field_name = strdup(args->field.name); 165 cur_field_name = strdup(args->field.name);
167 break; 166 break;
168 case PRINT_FLAGS: 167 case PRINT_FLAGS:
@@ -231,13 +230,10 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
231 return event; 230 return event;
232} 231}
233 232
234static void python_process_tracepoint(union perf_event *perf_event 233static void python_process_tracepoint(struct perf_sample *sample,
235 __maybe_unused, 234 struct perf_evsel *evsel,
236 struct perf_sample *sample, 235 struct thread *thread,
237 struct perf_evsel *evsel, 236 struct addr_location *al)
238 struct machine *machine __maybe_unused,
239 struct thread *thread,
240 struct addr_location *al)
241{ 237{
242 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 238 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
243 static char handler_name[256]; 239 static char handler_name[256];
@@ -351,11 +347,8 @@ static void python_process_tracepoint(union perf_event *perf_event
351 Py_DECREF(t); 347 Py_DECREF(t);
352} 348}
353 349
354static void python_process_general_event(union perf_event *perf_event 350static void python_process_general_event(struct perf_sample *sample,
355 __maybe_unused,
356 struct perf_sample *sample,
357 struct perf_evsel *evsel, 351 struct perf_evsel *evsel,
358 struct machine *machine __maybe_unused,
359 struct thread *thread, 352 struct thread *thread,
360 struct addr_location *al) 353 struct addr_location *al)
361{ 354{
@@ -411,22 +404,19 @@ exit:
411 Py_DECREF(t); 404 Py_DECREF(t);
412} 405}
413 406
414static void python_process_event(union perf_event *perf_event, 407static void python_process_event(union perf_event *event __maybe_unused,
415 struct perf_sample *sample, 408 struct perf_sample *sample,
416 struct perf_evsel *evsel, 409 struct perf_evsel *evsel,
417 struct machine *machine,
418 struct thread *thread, 410 struct thread *thread,
419 struct addr_location *al) 411 struct addr_location *al)
420{ 412{
421 switch (evsel->attr.type) { 413 switch (evsel->attr.type) {
422 case PERF_TYPE_TRACEPOINT: 414 case PERF_TYPE_TRACEPOINT:
423 python_process_tracepoint(perf_event, sample, evsel, 415 python_process_tracepoint(sample, evsel, thread, al);
424 machine, thread, al);
425 break; 416 break;
426 /* Reserve for future process_hw/sw/raw APIs */ 417 /* Reserve for future process_hw/sw/raw APIs */
427 default: 418 default:
428 python_process_general_event(perf_event, sample, evsel, 419 python_process_general_event(sample, evsel, thread, al);
429 machine, thread, al);
430 } 420 }
431} 421}
432 422
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index f36d24a02445..7acc03e8f3b2 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -132,18 +132,18 @@ static void perf_session__delete_threads(struct perf_session *session)
132 132
133static void perf_session_env__delete(struct perf_session_env *env) 133static void perf_session_env__delete(struct perf_session_env *env)
134{ 134{
135 free(env->hostname); 135 zfree(&env->hostname);
136 free(env->os_release); 136 zfree(&env->os_release);
137 free(env->version); 137 zfree(&env->version);
138 free(env->arch); 138 zfree(&env->arch);
139 free(env->cpu_desc); 139 zfree(&env->cpu_desc);
140 free(env->cpuid); 140 zfree(&env->cpuid);
141 141
142 free(env->cmdline); 142 zfree(&env->cmdline);
143 free(env->sibling_cores); 143 zfree(&env->sibling_cores);
144 free(env->sibling_threads); 144 zfree(&env->sibling_threads);
145 free(env->numa_nodes); 145 zfree(&env->numa_nodes);
146 free(env->pmu_mappings); 146 zfree(&env->pmu_mappings);
147} 147}
148 148
149void perf_session__delete(struct perf_session *session) 149void perf_session__delete(struct perf_session *session)
@@ -247,27 +247,6 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
247 } 247 }
248} 248}
249 249
250void mem_bswap_32(void *src, int byte_size)
251{
252 u32 *m = src;
253 while (byte_size > 0) {
254 *m = bswap_32(*m);
255 byte_size -= sizeof(u32);
256 ++m;
257 }
258}
259
260void mem_bswap_64(void *src, int byte_size)
261{
262 u64 *m = src;
263
264 while (byte_size > 0) {
265 *m = bswap_64(*m);
266 byte_size -= sizeof(u64);
267 ++m;
268 }
269}
270
271static void swap_sample_id_all(union perf_event *event, void *data) 250static void swap_sample_id_all(union perf_event *event, void *data)
272{ 251{
273 void *end = (void *) event + event->header.size; 252 void *end = (void *) event + event->header.size;
@@ -851,6 +830,7 @@ static struct machine *
851 struct perf_sample *sample) 830 struct perf_sample *sample)
852{ 831{
853 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 832 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
833 struct machine *machine;
854 834
855 if (perf_guest && 835 if (perf_guest &&
856 ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) || 836 ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) ||
@@ -863,7 +843,11 @@ static struct machine *
863 else 843 else
864 pid = sample->pid; 844 pid = sample->pid;
865 845
866 return perf_session__findnew_machine(session, pid); 846 machine = perf_session__find_machine(session, pid);
847 if (!machine)
848 machine = perf_session__findnew_machine(session,
849 DEFAULT_GUEST_KERNEL_ID);
850 return machine;
867 } 851 }
868 852
869 return &session->machines.host; 853 return &session->machines.host;
@@ -1158,7 +1142,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,
1158 void *buf = NULL; 1142 void *buf = NULL;
1159 int skip = 0; 1143 int skip = 0;
1160 u64 head; 1144 u64 head;
1161 int err; 1145 ssize_t err;
1162 void *p; 1146 void *p;
1163 1147
1164 perf_tool__fill_defaults(tool); 1148 perf_tool__fill_defaults(tool);
@@ -1400,7 +1384,7 @@ bool perf_session__has_traces(struct perf_session *session, const char *msg)
1400{ 1384{
1401 struct perf_evsel *evsel; 1385 struct perf_evsel *evsel;
1402 1386
1403 list_for_each_entry(evsel, &session->evlist->entries, node) { 1387 evlist__for_each(session->evlist, evsel) {
1404 if (evsel->attr.type == PERF_TYPE_TRACEPOINT) 1388 if (evsel->attr.type == PERF_TYPE_TRACEPOINT)
1405 return true; 1389 return true;
1406 } 1390 }
@@ -1458,7 +1442,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1458 1442
1459 ret += events_stats__fprintf(&session->stats, fp); 1443 ret += events_stats__fprintf(&session->stats, fp);
1460 1444
1461 list_for_each_entry(pos, &session->evlist->entries, node) { 1445 evlist__for_each(session->evlist, pos) {
1462 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); 1446 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
1463 ret += events_stats__fprintf(&pos->hists.stats, fp); 1447 ret += events_stats__fprintf(&pos->hists.stats, fp);
1464 } 1448 }
@@ -1480,35 +1464,30 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
1480{ 1464{
1481 struct perf_evsel *pos; 1465 struct perf_evsel *pos;
1482 1466
1483 list_for_each_entry(pos, &session->evlist->entries, node) { 1467 evlist__for_each(session->evlist, pos) {
1484 if (pos->attr.type == type) 1468 if (pos->attr.type == type)
1485 return pos; 1469 return pos;
1486 } 1470 }
1487 return NULL; 1471 return NULL;
1488} 1472}
1489 1473
1490void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, 1474void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
1491 struct perf_sample *sample, struct machine *machine, 1475 struct addr_location *al,
1492 unsigned int print_opts, unsigned int stack_depth) 1476 unsigned int print_opts, unsigned int stack_depth)
1493{ 1477{
1494 struct addr_location al;
1495 struct callchain_cursor_node *node; 1478 struct callchain_cursor_node *node;
1496 int print_ip = print_opts & PRINT_IP_OPT_IP; 1479 int print_ip = print_opts & PRINT_IP_OPT_IP;
1497 int print_sym = print_opts & PRINT_IP_OPT_SYM; 1480 int print_sym = print_opts & PRINT_IP_OPT_SYM;
1498 int print_dso = print_opts & PRINT_IP_OPT_DSO; 1481 int print_dso = print_opts & PRINT_IP_OPT_DSO;
1499 int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; 1482 int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET;
1500 int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; 1483 int print_oneline = print_opts & PRINT_IP_OPT_ONELINE;
1484 int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE;
1501 char s = print_oneline ? ' ' : '\t'; 1485 char s = print_oneline ? ' ' : '\t';
1502 1486
1503 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
1504 error("problem processing %d event, skipping it.\n",
1505 event->header.type);
1506 return;
1507 }
1508
1509 if (symbol_conf.use_callchain && sample->callchain) { 1487 if (symbol_conf.use_callchain && sample->callchain) {
1488 struct addr_location node_al;
1510 1489
1511 if (machine__resolve_callchain(machine, evsel, al.thread, 1490 if (machine__resolve_callchain(al->machine, evsel, al->thread,
1512 sample, NULL, NULL, 1491 sample, NULL, NULL,
1513 PERF_MAX_STACK_DEPTH) != 0) { 1492 PERF_MAX_STACK_DEPTH) != 0) {
1514 if (verbose) 1493 if (verbose)
@@ -1517,20 +1496,31 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1517 } 1496 }
1518 callchain_cursor_commit(&callchain_cursor); 1497 callchain_cursor_commit(&callchain_cursor);
1519 1498
1499 if (print_symoffset)
1500 node_al = *al;
1501
1520 while (stack_depth) { 1502 while (stack_depth) {
1503 u64 addr = 0;
1504
1521 node = callchain_cursor_current(&callchain_cursor); 1505 node = callchain_cursor_current(&callchain_cursor);
1522 if (!node) 1506 if (!node)
1523 break; 1507 break;
1524 1508
1509 if (node->sym && node->sym->ignore)
1510 goto next;
1511
1525 if (print_ip) 1512 if (print_ip)
1526 printf("%c%16" PRIx64, s, node->ip); 1513 printf("%c%16" PRIx64, s, node->ip);
1527 1514
1515 if (node->map)
1516 addr = node->map->map_ip(node->map, node->ip);
1517
1528 if (print_sym) { 1518 if (print_sym) {
1529 printf(" "); 1519 printf(" ");
1530 if (print_symoffset) { 1520 if (print_symoffset) {
1531 al.addr = node->ip; 1521 node_al.addr = addr;
1532 al.map = node->map; 1522 node_al.map = node->map;
1533 symbol__fprintf_symname_offs(node->sym, &al, stdout); 1523 symbol__fprintf_symname_offs(node->sym, &node_al, stdout);
1534 } else 1524 } else
1535 symbol__fprintf_symname(node->sym, stdout); 1525 symbol__fprintf_symname(node->sym, stdout);
1536 } 1526 }
@@ -1541,32 +1531,42 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1541 printf(")"); 1531 printf(")");
1542 } 1532 }
1543 1533
1534 if (print_srcline)
1535 map__fprintf_srcline(node->map, addr, "\n ",
1536 stdout);
1537
1544 if (!print_oneline) 1538 if (!print_oneline)
1545 printf("\n"); 1539 printf("\n");
1546 1540
1547 callchain_cursor_advance(&callchain_cursor);
1548
1549 stack_depth--; 1541 stack_depth--;
1542next:
1543 callchain_cursor_advance(&callchain_cursor);
1550 } 1544 }
1551 1545
1552 } else { 1546 } else {
1547 if (al->sym && al->sym->ignore)
1548 return;
1549
1553 if (print_ip) 1550 if (print_ip)
1554 printf("%16" PRIx64, sample->ip); 1551 printf("%16" PRIx64, sample->ip);
1555 1552
1556 if (print_sym) { 1553 if (print_sym) {
1557 printf(" "); 1554 printf(" ");
1558 if (print_symoffset) 1555 if (print_symoffset)
1559 symbol__fprintf_symname_offs(al.sym, &al, 1556 symbol__fprintf_symname_offs(al->sym, al,
1560 stdout); 1557 stdout);
1561 else 1558 else
1562 symbol__fprintf_symname(al.sym, stdout); 1559 symbol__fprintf_symname(al->sym, stdout);
1563 } 1560 }
1564 1561
1565 if (print_dso) { 1562 if (print_dso) {
1566 printf(" ("); 1563 printf(" (");
1567 map__fprintf_dsoname(al.map, stdout); 1564 map__fprintf_dsoname(al->map, stdout);
1568 printf(")"); 1565 printf(")");
1569 } 1566 }
1567
1568 if (print_srcline)
1569 map__fprintf_srcline(al->map, al->addr, "\n ", stdout);
1570 } 1570 }
1571} 1571}
1572 1572
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 50f640958f0f..3140f8ae6148 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -1,6 +1,7 @@
1#ifndef __PERF_SESSION_H 1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H 2#define __PERF_SESSION_H
3 3
4#include "trace-event.h"
4#include "hist.h" 5#include "hist.h"
5#include "event.h" 6#include "event.h"
6#include "header.h" 7#include "header.h"
@@ -32,7 +33,7 @@ struct perf_session {
32 struct perf_header header; 33 struct perf_header header;
33 struct machines machines; 34 struct machines machines;
34 struct perf_evlist *evlist; 35 struct perf_evlist *evlist;
35 struct pevent *pevent; 36 struct trace_event tevent;
36 struct events_stats stats; 37 struct events_stats stats;
37 bool repipe; 38 bool repipe;
38 struct ordered_samples ordered_samples; 39 struct ordered_samples ordered_samples;
@@ -44,6 +45,7 @@ struct perf_session {
44#define PRINT_IP_OPT_DSO (1<<2) 45#define PRINT_IP_OPT_DSO (1<<2)
45#define PRINT_IP_OPT_SYMOFFSET (1<<3) 46#define PRINT_IP_OPT_SYMOFFSET (1<<3)
46#define PRINT_IP_OPT_ONELINE (1<<4) 47#define PRINT_IP_OPT_ONELINE (1<<4)
48#define PRINT_IP_OPT_SRCLINE (1<<5)
47 49
48struct perf_tool; 50struct perf_tool;
49 51
@@ -72,8 +74,6 @@ int perf_session__resolve_callchain(struct perf_session *session,
72 74
73bool perf_session__has_traces(struct perf_session *session, const char *msg); 75bool perf_session__has_traces(struct perf_session *session, const char *msg);
74 76
75void mem_bswap_64(void *src, int byte_size);
76void mem_bswap_32(void *src, int byte_size);
77void perf_event__attr_swap(struct perf_event_attr *attr); 77void perf_event__attr_swap(struct perf_event_attr *attr);
78 78
79int perf_session__create_kernel_maps(struct perf_session *session); 79int perf_session__create_kernel_maps(struct perf_session *session);
@@ -105,8 +105,8 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
105struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 105struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
106 unsigned int type); 106 unsigned int type);
107 107
108void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, 108void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
109 struct perf_sample *sample, struct machine *machine, 109 struct addr_location *al,
110 unsigned int print_opts, unsigned int stack_depth); 110 unsigned int print_opts, unsigned int stack_depth);
111 111
112int perf_session__cpu_bitmap(struct perf_session *session, 112int perf_session__cpu_bitmap(struct perf_session *session,
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 58ea5ca6c255..d0aee4b9dfd4 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -25,7 +25,7 @@ cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter'
25build_lib = getenv('PYTHON_EXTBUILD_LIB') 25build_lib = getenv('PYTHON_EXTBUILD_LIB')
26build_tmp = getenv('PYTHON_EXTBUILD_TMP') 26build_tmp = getenv('PYTHON_EXTBUILD_TMP')
27libtraceevent = getenv('LIBTRACEEVENT') 27libtraceevent = getenv('LIBTRACEEVENT')
28liblk = getenv('LIBLK') 28libapikfs = getenv('LIBAPIKFS')
29 29
30ext_sources = [f.strip() for f in file('util/python-ext-sources') 30ext_sources = [f.strip() for f in file('util/python-ext-sources')
31 if len(f.strip()) > 0 and f[0] != '#'] 31 if len(f.strip()) > 0 and f[0] != '#']
@@ -34,7 +34,7 @@ perf = Extension('perf',
34 sources = ext_sources, 34 sources = ext_sources,
35 include_dirs = ['util/include'], 35 include_dirs = ['util/include'],
36 extra_compile_args = cflags, 36 extra_compile_args = cflags,
37 extra_objects = [libtraceevent, liblk], 37 extra_objects = [libtraceevent, libapikfs],
38 ) 38 )
39 39
40setup(name='perf', 40setup(name='perf',
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 8b0bb1f4494a..635cd8f8b22e 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -13,6 +13,7 @@ int have_ignore_callees = 0;
13int sort__need_collapse = 0; 13int sort__need_collapse = 0;
14int sort__has_parent = 0; 14int sort__has_parent = 0;
15int sort__has_sym = 0; 15int sort__has_sym = 0;
16int sort__has_dso = 0;
16enum sort_mode sort__mode = SORT_MODE__NORMAL; 17enum sort_mode sort__mode = SORT_MODE__NORMAL;
17 18
18enum sort_type sort__first_dimension; 19enum sort_type sort__first_dimension;
@@ -161,6 +162,11 @@ struct sort_entry sort_dso = {
161 162
162/* --sort symbol */ 163/* --sort symbol */
163 164
165static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
166{
167 return (int64_t)(right_ip - left_ip);
168}
169
164static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) 170static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
165{ 171{
166 u64 ip_l, ip_r; 172 u64 ip_l, ip_r;
@@ -183,15 +189,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
183 int64_t ret; 189 int64_t ret;
184 190
185 if (!left->ms.sym && !right->ms.sym) 191 if (!left->ms.sym && !right->ms.sym)
186 return right->level - left->level; 192 return _sort__addr_cmp(left->ip, right->ip);
187 193
188 /* 194 /*
189 * comparing symbol address alone is not enough since it's a 195 * comparing symbol address alone is not enough since it's a
190 * relative address within a dso. 196 * relative address within a dso.
191 */ 197 */
192 ret = sort__dso_cmp(left, right); 198 if (!sort__has_dso) {
193 if (ret != 0) 199 ret = sort__dso_cmp(left, right);
194 return ret; 200 if (ret != 0)
201 return ret;
202 }
195 203
196 return _sort__sym_cmp(left->ms.sym, right->ms.sym); 204 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
197} 205}
@@ -372,7 +380,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
372 struct addr_map_symbol *from_r = &right->branch_info->from; 380 struct addr_map_symbol *from_r = &right->branch_info->from;
373 381
374 if (!from_l->sym && !from_r->sym) 382 if (!from_l->sym && !from_r->sym)
375 return right->level - left->level; 383 return _sort__addr_cmp(from_l->addr, from_r->addr);
376 384
377 return _sort__sym_cmp(from_l->sym, from_r->sym); 385 return _sort__sym_cmp(from_l->sym, from_r->sym);
378} 386}
@@ -384,7 +392,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
384 struct addr_map_symbol *to_r = &right->branch_info->to; 392 struct addr_map_symbol *to_r = &right->branch_info->to;
385 393
386 if (!to_l->sym && !to_r->sym) 394 if (!to_l->sym && !to_r->sym)
387 return right->level - left->level; 395 return _sort__addr_cmp(to_l->addr, to_r->addr);
388 396
389 return _sort__sym_cmp(to_l->sym, to_r->sym); 397 return _sort__sym_cmp(to_l->sym, to_r->sym);
390} 398}
@@ -1056,6 +1064,8 @@ int sort_dimension__add(const char *tok)
1056 sort__has_parent = 1; 1064 sort__has_parent = 1;
1057 } else if (sd->entry == &sort_sym) { 1065 } else if (sd->entry == &sort_sym) {
1058 sort__has_sym = 1; 1066 sort__has_sym = 1;
1067 } else if (sd->entry == &sort_dso) {
1068 sort__has_dso = 1;
1059 } 1069 }
1060 1070
1061 __sort_dimension__add(sd, i); 1071 __sort_dimension__add(sd, i);
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index d11aefbc4b8d..f3e4bc5fe5d2 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -129,7 +129,7 @@ static struct a2l_data *addr2line_init(const char *path)
129 129
130out: 130out:
131 if (a2l) { 131 if (a2l) {
132 free((void *)a2l->input); 132 zfree((char **)&a2l->input);
133 free(a2l); 133 free(a2l);
134 } 134 }
135 bfd_close(abfd); 135 bfd_close(abfd);
@@ -140,24 +140,30 @@ static void addr2line_cleanup(struct a2l_data *a2l)
140{ 140{
141 if (a2l->abfd) 141 if (a2l->abfd)
142 bfd_close(a2l->abfd); 142 bfd_close(a2l->abfd);
143 free((void *)a2l->input); 143 zfree((char **)&a2l->input);
144 free(a2l->syms); 144 zfree(&a2l->syms);
145 free(a2l); 145 free(a2l);
146} 146}
147 147
148static int addr2line(const char *dso_name, unsigned long addr, 148static int addr2line(const char *dso_name, unsigned long addr,
149 char **file, unsigned int *line) 149 char **file, unsigned int *line, struct dso *dso)
150{ 150{
151 int ret = 0; 151 int ret = 0;
152 struct a2l_data *a2l; 152 struct a2l_data *a2l = dso->a2l;
153
154 if (!a2l) {
155 dso->a2l = addr2line_init(dso_name);
156 a2l = dso->a2l;
157 }
153 158
154 a2l = addr2line_init(dso_name);
155 if (a2l == NULL) { 159 if (a2l == NULL) {
156 pr_warning("addr2line_init failed for %s\n", dso_name); 160 pr_warning("addr2line_init failed for %s\n", dso_name);
157 return 0; 161 return 0;
158 } 162 }
159 163
160 a2l->addr = addr; 164 a2l->addr = addr;
165 a2l->found = false;
166
161 bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); 167 bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
162 168
163 if (a2l->found && a2l->filename) { 169 if (a2l->found && a2l->filename) {
@@ -168,14 +174,26 @@ static int addr2line(const char *dso_name, unsigned long addr,
168 ret = 1; 174 ret = 1;
169 } 175 }
170 176
171 addr2line_cleanup(a2l);
172 return ret; 177 return ret;
173} 178}
174 179
180void dso__free_a2l(struct dso *dso)
181{
182 struct a2l_data *a2l = dso->a2l;
183
184 if (!a2l)
185 return;
186
187 addr2line_cleanup(a2l);
188
189 dso->a2l = NULL;
190}
191
175#else /* HAVE_LIBBFD_SUPPORT */ 192#else /* HAVE_LIBBFD_SUPPORT */
176 193
177static int addr2line(const char *dso_name, unsigned long addr, 194static int addr2line(const char *dso_name, unsigned long addr,
178 char **file, unsigned int *line_nr) 195 char **file, unsigned int *line_nr,
196 struct dso *dso __maybe_unused)
179{ 197{
180 FILE *fp; 198 FILE *fp;
181 char cmd[PATH_MAX]; 199 char cmd[PATH_MAX];
@@ -219,42 +237,58 @@ out:
219 pclose(fp); 237 pclose(fp);
220 return ret; 238 return ret;
221} 239}
240
241void dso__free_a2l(struct dso *dso __maybe_unused)
242{
243}
244
222#endif /* HAVE_LIBBFD_SUPPORT */ 245#endif /* HAVE_LIBBFD_SUPPORT */
223 246
247/*
248 * Number of addr2line failures (without success) before disabling it for that
249 * dso.
250 */
251#define A2L_FAIL_LIMIT 123
252
224char *get_srcline(struct dso *dso, unsigned long addr) 253char *get_srcline(struct dso *dso, unsigned long addr)
225{ 254{
226 char *file = NULL; 255 char *file = NULL;
227 unsigned line = 0; 256 unsigned line = 0;
228 char *srcline; 257 char *srcline;
229 char *dso_name = dso->long_name; 258 const char *dso_name;
230 size_t size;
231 259
232 if (!dso->has_srcline) 260 if (!dso->has_srcline)
233 return SRCLINE_UNKNOWN; 261 return SRCLINE_UNKNOWN;
234 262
263 if (dso->symsrc_filename)
264 dso_name = dso->symsrc_filename;
265 else
266 dso_name = dso->long_name;
267
235 if (dso_name[0] == '[') 268 if (dso_name[0] == '[')
236 goto out; 269 goto out;
237 270
238 if (!strncmp(dso_name, "/tmp/perf-", 10)) 271 if (!strncmp(dso_name, "/tmp/perf-", 10))
239 goto out; 272 goto out;
240 273
241 if (!addr2line(dso_name, addr, &file, &line)) 274 if (!addr2line(dso_name, addr, &file, &line, dso))
242 goto out; 275 goto out;
243 276
244 /* just calculate actual length */ 277 if (asprintf(&srcline, "%s:%u", file, line) < 0) {
245 size = snprintf(NULL, 0, "%s:%u", file, line) + 1; 278 free(file);
279 goto out;
280 }
246 281
247 srcline = malloc(size); 282 dso->a2l_fails = 0;
248 if (srcline)
249 snprintf(srcline, size, "%s:%u", file, line);
250 else
251 srcline = SRCLINE_UNKNOWN;
252 283
253 free(file); 284 free(file);
254 return srcline; 285 return srcline;
255 286
256out: 287out:
257 dso->has_srcline = 0; 288 if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
289 dso->has_srcline = 0;
290 dso__free_a2l(dso);
291 }
258 return SRCLINE_UNKNOWN; 292 return SRCLINE_UNKNOWN;
259} 293}
260 294
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index cfa906882e2c..4abe23550c73 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -28,7 +28,7 @@ void strbuf_init(struct strbuf *sb, ssize_t hint)
28void strbuf_release(struct strbuf *sb) 28void strbuf_release(struct strbuf *sb)
29{ 29{
30 if (sb->alloc) { 30 if (sb->alloc) {
31 free(sb->buf); 31 zfree(&sb->buf);
32 strbuf_init(sb, 0); 32 strbuf_init(sb, 0);
33 } 33 }
34} 34}
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c
index 3edd0538161f..79a757a2a15c 100644
--- a/tools/perf/util/strfilter.c
+++ b/tools/perf/util/strfilter.c
@@ -14,7 +14,7 @@ static void strfilter_node__delete(struct strfilter_node *node)
14{ 14{
15 if (node) { 15 if (node) {
16 if (node->p && !is_operator(*node->p)) 16 if (node->p && !is_operator(*node->p))
17 free((char *)node->p); 17 zfree((char **)&node->p);
18 strfilter_node__delete(node->l); 18 strfilter_node__delete(node->l);
19 strfilter_node__delete(node->r); 19 strfilter_node__delete(node->r);
20 free(node); 20 free(node);
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index f0b0c008c507..2553e5b55b89 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -128,7 +128,7 @@ void argv_free(char **argv)
128{ 128{
129 char **p; 129 char **p;
130 for (p = argv; *p; p++) 130 for (p = argv; *p; p++)
131 free(*p); 131 zfree(p);
132 132
133 free(argv); 133 free(argv);
134} 134}
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index eabdce0a2daa..71f9d102b96f 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -5,6 +5,7 @@
5 */ 5 */
6 6
7#include "strlist.h" 7#include "strlist.h"
8#include "util.h"
8#include <errno.h> 9#include <errno.h>
9#include <stdio.h> 10#include <stdio.h>
10#include <stdlib.h> 11#include <stdlib.h>
@@ -38,7 +39,7 @@ out_delete:
38static void str_node__delete(struct str_node *snode, bool dupstr) 39static void str_node__delete(struct str_node *snode, bool dupstr)
39{ 40{
40 if (dupstr) 41 if (dupstr)
41 free((void *)snode->s); 42 zfree((char **)&snode->s);
42 free(snode); 43 free(snode);
43} 44}
44 45
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 96c866045d60..43262b83c541 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -17,8 +17,12 @@
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 21
22#include "perf.h"
21#include "svghelper.h" 23#include "svghelper.h"
24#include "util.h"
25#include "cpumap.h"
22 26
23static u64 first_time, last_time; 27static u64 first_time, last_time;
24static u64 turbo_frequency, max_freq; 28static u64 turbo_frequency, max_freq;
@@ -28,6 +32,8 @@ static u64 turbo_frequency, max_freq;
28#define SLOT_HEIGHT 25.0 32#define SLOT_HEIGHT 25.0
29 33
30int svg_page_width = 1000; 34int svg_page_width = 1000;
35u64 svg_highlight;
36const char *svg_highlight_name;
31 37
32#define MIN_TEXT_SIZE 0.01 38#define MIN_TEXT_SIZE 0.01
33 39
@@ -39,9 +45,14 @@ static double cpu2slot(int cpu)
39 return 2 * cpu + 1; 45 return 2 * cpu + 1;
40} 46}
41 47
48static int *topology_map;
49
42static double cpu2y(int cpu) 50static double cpu2y(int cpu)
43{ 51{
44 return cpu2slot(cpu) * SLOT_MULT; 52 if (topology_map)
53 return cpu2slot(topology_map[cpu]) * SLOT_MULT;
54 else
55 return cpu2slot(cpu) * SLOT_MULT;
45} 56}
46 57
47static double time2pixels(u64 __time) 58static double time2pixels(u64 __time)
@@ -95,6 +106,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
95 106
96 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT; 107 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT;
97 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n"); 108 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n");
109 fprintf(svgfile, "<!DOCTYPE svg SYSTEM \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
98 fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height); 110 fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
99 111
100 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n"); 112 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
@@ -103,6 +115,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
103 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); 115 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
104 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 116 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
105 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 117 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
118 fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
106 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 119 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
107 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 120 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
108 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 121 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
@@ -128,14 +141,42 @@ void svg_box(int Yslot, u64 start, u64 end, const char *type)
128 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); 141 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type);
129} 142}
130 143
131void svg_sample(int Yslot, int cpu, u64 start, u64 end) 144static char *time_to_string(u64 duration);
145void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
146{
147 if (!svgfile)
148 return;
149
150 fprintf(svgfile, "<g>\n");
151 fprintf(svgfile, "<title>#%d blocked %s</title>\n", cpu,
152 time_to_string(end - start));
153 if (backtrace)
154 fprintf(svgfile, "<desc>Blocked on:\n%s</desc>\n", backtrace);
155 svg_box(Yslot, start, end, "blocked");
156 fprintf(svgfile, "</g>\n");
157}
158
159void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
132{ 160{
133 double text_size; 161 double text_size;
162 const char *type;
163
134 if (!svgfile) 164 if (!svgfile)
135 return; 165 return;
136 166
137 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"sample\"/>\n", 167 if (svg_highlight && end - start > svg_highlight)
138 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT); 168 type = "sample_hi";
169 else
170 type = "sample";
171 fprintf(svgfile, "<g>\n");
172
173 fprintf(svgfile, "<title>#%d running %s</title>\n",
174 cpu, time_to_string(end - start));
175 if (backtrace)
176 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
177 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n",
178 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT,
179 type);
139 180
140 text_size = (time2pixels(end)-time2pixels(start)); 181 text_size = (time2pixels(end)-time2pixels(start));
141 if (cpu > 9) 182 if (cpu > 9)
@@ -148,6 +189,7 @@ void svg_sample(int Yslot, int cpu, u64 start, u64 end)
148 fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n", 189 fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n",
149 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); 190 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1);
150 191
192 fprintf(svgfile, "</g>\n");
151} 193}
152 194
153static char *time_to_string(u64 duration) 195static char *time_to_string(u64 duration)
@@ -168,7 +210,7 @@ static char *time_to_string(u64 duration)
168 return text; 210 return text;
169} 211}
170 212
171void svg_waiting(int Yslot, u64 start, u64 end) 213void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
172{ 214{
173 char *text; 215 char *text;
174 const char *style; 216 const char *style;
@@ -192,6 +234,9 @@ void svg_waiting(int Yslot, u64 start, u64 end)
192 font_size = round_text_size(font_size); 234 font_size = round_text_size(font_size);
193 235
194 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); 236 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT);
237 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start));
238 if (backtrace)
239 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace);
195 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 240 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
196 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style); 241 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style);
197 if (font_size > MIN_TEXT_SIZE) 242 if (font_size > MIN_TEXT_SIZE)
@@ -242,28 +287,42 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
242 max_freq = __max_freq; 287 max_freq = __max_freq;
243 turbo_frequency = __turbo_freq; 288 turbo_frequency = __turbo_freq;
244 289
290 fprintf(svgfile, "<g>\n");
291
245 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", 292 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n",
246 time2pixels(first_time), 293 time2pixels(first_time),
247 time2pixels(last_time)-time2pixels(first_time), 294 time2pixels(last_time)-time2pixels(first_time),
248 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 295 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
249 296
250 sprintf(cpu_string, "CPU %i", (int)cpu+1); 297 sprintf(cpu_string, "CPU %i", (int)cpu);
251 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 298 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n",
252 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); 299 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
253 300
254 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", 301 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n",
255 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); 302 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model());
303
304 fprintf(svgfile, "</g>\n");
256} 305}
257 306
258void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name) 307void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace)
259{ 308{
260 double width; 309 double width;
310 const char *type;
261 311
262 if (!svgfile) 312 if (!svgfile)
263 return; 313 return;
264 314
315 if (svg_highlight && end - start >= svg_highlight)
316 type = "sample_hi";
317 else if (svg_highlight_name && strstr(name, svg_highlight_name))
318 type = "sample_hi";
319 else
320 type = "sample";
265 321
266 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu)); 322 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu));
323 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start));
324 if (backtrace)
325 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
267 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 326 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
268 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); 327 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
269 width = time2pixels(end)-time2pixels(start); 328 width = time2pixels(end)-time2pixels(start);
@@ -288,6 +347,8 @@ void svg_cstate(int cpu, u64 start, u64 end, int type)
288 return; 347 return;
289 348
290 349
350 fprintf(svgfile, "<g>\n");
351
291 if (type > 6) 352 if (type > 6)
292 type = 6; 353 type = 6;
293 sprintf(style, "c%i", type); 354 sprintf(style, "c%i", type);
@@ -306,6 +367,8 @@ void svg_cstate(int cpu, u64 start, u64 end, int type)
306 if (width > MIN_TEXT_SIZE) 367 if (width > MIN_TEXT_SIZE)
307 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n", 368 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n",
308 time2pixels(start), cpu2y(cpu)+width, width, type); 369 time2pixels(start), cpu2y(cpu)+width, width, type);
370
371 fprintf(svgfile, "</g>\n");
309} 372}
310 373
311static char *HzToHuman(unsigned long hz) 374static char *HzToHuman(unsigned long hz)
@@ -339,6 +402,8 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
339 if (!svgfile) 402 if (!svgfile)
340 return; 403 return;
341 404
405 fprintf(svgfile, "<g>\n");
406
342 if (max_freq) 407 if (max_freq)
343 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); 408 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT);
344 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; 409 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height;
@@ -347,10 +412,11 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
347 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n", 412 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n",
348 time2pixels(start), height+0.9, HzToHuman(freq)); 413 time2pixels(start), height+0.9, HzToHuman(freq));
349 414
415 fprintf(svgfile, "</g>\n");
350} 416}
351 417
352 418
353void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2) 419void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace)
354{ 420{
355 double height; 421 double height;
356 422
@@ -358,6 +424,15 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc
358 return; 424 return;
359 425
360 426
427 fprintf(svgfile, "<g>\n");
428
429 fprintf(svgfile, "<title>%s wakes up %s</title>\n",
430 desc1 ? desc1 : "?",
431 desc2 ? desc2 : "?");
432
433 if (backtrace)
434 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
435
361 if (row1 < row2) { 436 if (row1 < row2) {
362 if (row1) { 437 if (row1) {
363 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 438 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
@@ -395,9 +470,11 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc
395 if (row1) 470 if (row1)
396 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 471 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
397 time2pixels(start), height); 472 time2pixels(start), height);
473
474 fprintf(svgfile, "</g>\n");
398} 475}
399 476
400void svg_wakeline(u64 start, int row1, int row2) 477void svg_wakeline(u64 start, int row1, int row2, const char *backtrace)
401{ 478{
402 double height; 479 double height;
403 480
@@ -405,6 +482,11 @@ void svg_wakeline(u64 start, int row1, int row2)
405 return; 482 return;
406 483
407 484
485 fprintf(svgfile, "<g>\n");
486
487 if (backtrace)
488 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
489
408 if (row1 < row2) 490 if (row1 < row2)
409 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 491 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
410 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); 492 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT);
@@ -417,17 +499,28 @@ void svg_wakeline(u64 start, int row1, int row2)
417 height += SLOT_HEIGHT; 499 height += SLOT_HEIGHT;
418 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 500 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
419 time2pixels(start), height); 501 time2pixels(start), height);
502
503 fprintf(svgfile, "</g>\n");
420} 504}
421 505
422void svg_interrupt(u64 start, int row) 506void svg_interrupt(u64 start, int row, const char *backtrace)
423{ 507{
424 if (!svgfile) 508 if (!svgfile)
425 return; 509 return;
426 510
511 fprintf(svgfile, "<g>\n");
512
513 fprintf(svgfile, "<title>Wakeup from interrupt</title>\n");
514
515 if (backtrace)
516 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
517
427 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 518 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
428 time2pixels(start), row * SLOT_MULT); 519 time2pixels(start), row * SLOT_MULT);
429 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 520 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
430 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); 521 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT);
522
523 fprintf(svgfile, "</g>\n");
431} 524}
432 525
433void svg_text(int Yslot, u64 start, const char *text) 526void svg_text(int Yslot, u64 start, const char *text)
@@ -455,6 +548,7 @@ void svg_legenda(void)
455 if (!svgfile) 548 if (!svgfile)
456 return; 549 return;
457 550
551 fprintf(svgfile, "<g>\n");
458 svg_legenda_box(0, "Running", "sample"); 552 svg_legenda_box(0, "Running", "sample");
459 svg_legenda_box(100, "Idle","c1"); 553 svg_legenda_box(100, "Idle","c1");
460 svg_legenda_box(200, "Deeper Idle", "c3"); 554 svg_legenda_box(200, "Deeper Idle", "c3");
@@ -462,6 +556,7 @@ void svg_legenda(void)
462 svg_legenda_box(550, "Sleeping", "process2"); 556 svg_legenda_box(550, "Sleeping", "process2");
463 svg_legenda_box(650, "Waiting for cpu", "waiting"); 557 svg_legenda_box(650, "Waiting for cpu", "waiting");
464 svg_legenda_box(800, "Blocked on IO", "blocked"); 558 svg_legenda_box(800, "Blocked on IO", "blocked");
559 fprintf(svgfile, "</g>\n");
465} 560}
466 561
467void svg_time_grid(void) 562void svg_time_grid(void)
@@ -499,3 +594,123 @@ void svg_close(void)
499 svgfile = NULL; 594 svgfile = NULL;
500 } 595 }
501} 596}
597
598#define cpumask_bits(maskp) ((maskp)->bits)
599typedef struct { DECLARE_BITMAP(bits, MAX_NR_CPUS); } cpumask_t;
600
601struct topology {
602 cpumask_t *sib_core;
603 int sib_core_nr;
604 cpumask_t *sib_thr;
605 int sib_thr_nr;
606};
607
608static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos)
609{
610 int i;
611 int thr;
612
613 for (i = 0; i < t->sib_thr_nr; i++) {
614 if (!test_bit(cpu, cpumask_bits(&t->sib_thr[i])))
615 continue;
616
617 for_each_set_bit(thr,
618 cpumask_bits(&t->sib_thr[i]),
619 MAX_NR_CPUS)
620 if (map[thr] == -1)
621 map[thr] = (*pos)++;
622 }
623}
624
625static void scan_core_topology(int *map, struct topology *t)
626{
627 int pos = 0;
628 int i;
629 int cpu;
630
631 for (i = 0; i < t->sib_core_nr; i++)
632 for_each_set_bit(cpu,
633 cpumask_bits(&t->sib_core[i]),
634 MAX_NR_CPUS)
635 scan_thread_topology(map, t, cpu, &pos);
636}
637
638static int str_to_bitmap(char *s, cpumask_t *b)
639{
640 int i;
641 int ret = 0;
642 struct cpu_map *m;
643 int c;
644
645 m = cpu_map__new(s);
646 if (!m)
647 return -1;
648
649 for (i = 0; i < m->nr; i++) {
650 c = m->map[i];
651 if (c >= MAX_NR_CPUS) {
652 ret = -1;
653 break;
654 }
655
656 set_bit(c, cpumask_bits(b));
657 }
658
659 cpu_map__delete(m);
660
661 return ret;
662}
663
664int svg_build_topology_map(char *sib_core, int sib_core_nr,
665 char *sib_thr, int sib_thr_nr)
666{
667 int i;
668 struct topology t;
669
670 t.sib_core_nr = sib_core_nr;
671 t.sib_thr_nr = sib_thr_nr;
672 t.sib_core = calloc(sib_core_nr, sizeof(cpumask_t));
673 t.sib_thr = calloc(sib_thr_nr, sizeof(cpumask_t));
674
675 if (!t.sib_core || !t.sib_thr) {
676 fprintf(stderr, "topology: no memory\n");
677 goto exit;
678 }
679
680 for (i = 0; i < sib_core_nr; i++) {
681 if (str_to_bitmap(sib_core, &t.sib_core[i])) {
682 fprintf(stderr, "topology: can't parse siblings map\n");
683 goto exit;
684 }
685
686 sib_core += strlen(sib_core) + 1;
687 }
688
689 for (i = 0; i < sib_thr_nr; i++) {
690 if (str_to_bitmap(sib_thr, &t.sib_thr[i])) {
691 fprintf(stderr, "topology: can't parse siblings map\n");
692 goto exit;
693 }
694
695 sib_thr += strlen(sib_thr) + 1;
696 }
697
698 topology_map = malloc(sizeof(int) * MAX_NR_CPUS);
699 if (!topology_map) {
700 fprintf(stderr, "topology: no memory\n");
701 goto exit;
702 }
703
704 for (i = 0; i < MAX_NR_CPUS; i++)
705 topology_map[i] = -1;
706
707 scan_core_topology(topology_map, &t);
708
709 return 0;
710
711exit:
712 zfree(&t.sib_core);
713 zfree(&t.sib_thr);
714
715 return -1;
716}
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index e0781989cc31..f7b4d6e699ea 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -5,24 +5,29 @@
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);
8extern void svg_sample(int Yslot, int cpu, u64 start, u64 end); 8extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
9extern void svg_waiting(int Yslot, u64 start, u64 end); 9extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
10extern void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
10extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency); 11extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency);
11 12
12 13
13extern void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name); 14extern void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace);
14extern void svg_cstate(int cpu, u64 start, u64 end, int type); 15extern void svg_cstate(int cpu, u64 start, u64 end, int type);
15extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); 16extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
16 17
17 18
18extern void svg_time_grid(void); 19extern void svg_time_grid(void);
19extern void svg_legenda(void); 20extern void svg_legenda(void);
20extern void svg_wakeline(u64 start, int row1, int row2); 21extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace);
21extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2); 22extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace);
22extern void svg_interrupt(u64 start, int row); 23extern void svg_interrupt(u64 start, int row, const char *backtrace);
23extern void svg_text(int Yslot, u64 start, const char *text); 24extern void svg_text(int Yslot, u64 start, const char *text);
24extern void svg_close(void); 25extern void svg_close(void);
26extern int svg_build_topology_map(char *sib_core, int sib_core_nr,
27 char *sib_thr, int sib_thr_nr);
25 28
26extern int svg_page_width; 29extern int svg_page_width;
30extern u64 svg_highlight;
31extern const char *svg_highlight_name;
27 32
28#endif /* __PERF_SVGHELPER_H */ 33#endif /* __PERF_SVGHELPER_H */
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index eed0b96302af..759456728703 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -6,6 +6,7 @@
6#include <inttypes.h> 6#include <inttypes.h>
7 7
8#include "symbol.h" 8#include "symbol.h"
9#include <symbol/kallsyms.h>
9#include "debug.h" 10#include "debug.h"
10 11
11#ifndef HAVE_ELF_GETPHDRNUM_SUPPORT 12#ifndef HAVE_ELF_GETPHDRNUM_SUPPORT
@@ -135,9 +136,8 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
135 return -1; 136 return -1;
136} 137}
137 138
138static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 139Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
139 GElf_Shdr *shp, const char *name, 140 GElf_Shdr *shp, const char *name, size_t *idx)
140 size_t *idx)
141{ 141{
142 Elf_Scn *sec = NULL; 142 Elf_Scn *sec = NULL;
143 size_t cnt = 1; 143 size_t cnt = 1;
@@ -553,7 +553,7 @@ bool symsrc__has_symtab(struct symsrc *ss)
553 553
554void symsrc__destroy(struct symsrc *ss) 554void symsrc__destroy(struct symsrc *ss)
555{ 555{
556 free(ss->name); 556 zfree(&ss->name);
557 elf_end(ss->elf); 557 elf_end(ss->elf);
558 close(ss->fd); 558 close(ss->fd);
559} 559}
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 2d2dd0532b5a..bd15f490d04f 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -1,4 +1,5 @@
1#include "symbol.h" 1#include "symbol.h"
2#include "util.h"
2 3
3#include <stdio.h> 4#include <stdio.h>
4#include <fcntl.h> 5#include <fcntl.h>
@@ -253,6 +254,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
253 if (!ss->name) 254 if (!ss->name)
254 goto out_close; 255 goto out_close;
255 256
257 ss->fd = fd;
256 ss->type = type; 258 ss->type = type;
257 259
258 return 0; 260 return 0;
@@ -274,7 +276,7 @@ bool symsrc__has_symtab(struct symsrc *ss __maybe_unused)
274 276
275void symsrc__destroy(struct symsrc *ss) 277void symsrc__destroy(struct symsrc *ss)
276{ 278{
277 free(ss->name); 279 zfree(&ss->name);
278 close(ss->fd); 280 close(ss->fd);
279} 281}
280 282
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c0c36965fff0..39ce9adbaaf0 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -18,12 +18,9 @@
18 18
19#include <elf.h> 19#include <elf.h>
20#include <limits.h> 20#include <limits.h>
21#include <symbol/kallsyms.h>
21#include <sys/utsname.h> 22#include <sys/utsname.h>
22 23
23#ifndef KSYM_NAME_LEN
24#define KSYM_NAME_LEN 256
25#endif
26
27static int dso__load_kernel_sym(struct dso *dso, struct map *map, 24static int dso__load_kernel_sym(struct dso *dso, struct map *map,
28 symbol_filter_t filter); 25 symbol_filter_t filter);
29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 26static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
@@ -446,62 +443,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso,
446 return ret; 443 return ret;
447} 444}
448 445
449int kallsyms__parse(const char *filename, void *arg,
450 int (*process_symbol)(void *arg, const char *name,
451 char type, u64 start))
452{
453 char *line = NULL;
454 size_t n;
455 int err = -1;
456 FILE *file = fopen(filename, "r");
457
458 if (file == NULL)
459 goto out_failure;
460
461 err = 0;
462
463 while (!feof(file)) {
464 u64 start;
465 int line_len, len;
466 char symbol_type;
467 char *symbol_name;
468
469 line_len = getline(&line, &n, file);
470 if (line_len < 0 || !line)
471 break;
472
473 line[--line_len] = '\0'; /* \n */
474
475 len = hex2u64(line, &start);
476
477 len++;
478 if (len + 2 >= line_len)
479 continue;
480
481 symbol_type = line[len];
482 len += 2;
483 symbol_name = line + len;
484 len = line_len - len;
485
486 if (len >= KSYM_NAME_LEN) {
487 err = -1;
488 break;
489 }
490
491 err = process_symbol(arg, symbol_name,
492 symbol_type, start);
493 if (err)
494 break;
495 }
496
497 free(line);
498 fclose(file);
499 return err;
500
501out_failure:
502 return -1;
503}
504
505int modules__parse(const char *filename, void *arg, 446int modules__parse(const char *filename, void *arg,
506 int (*process_module)(void *arg, const char *name, 447 int (*process_module)(void *arg, const char *name,
507 u64 start)) 448 u64 start))
@@ -565,12 +506,34 @@ struct process_kallsyms_args {
565 struct dso *dso; 506 struct dso *dso;
566}; 507};
567 508
568static u8 kallsyms2elf_type(char type) 509bool symbol__is_idle(struct symbol *sym)
569{ 510{
570 if (type == 'W') 511 const char * const idle_symbols[] = {
571 return STB_WEAK; 512 "cpu_idle",
513 "intel_idle",
514 "default_idle",
515 "native_safe_halt",
516 "enter_idle",
517 "exit_idle",
518 "mwait_idle",
519 "mwait_idle_with_hints",
520 "poll_idle",
521 "ppc64_runlatch_off",
522 "pseries_dedicated_idle_sleep",
523 NULL
524 };
525
526 int i;
527
528 if (!sym)
529 return false;
530
531 for (i = 0; idle_symbols[i]; i++) {
532 if (!strcmp(idle_symbols[i], sym->name))
533 return true;
534 }
572 535
573 return isupper(type) ? STB_GLOBAL : STB_LOCAL; 536 return false;
574} 537}
575 538
576static int map__process_kallsym_symbol(void *arg, const char *name, 539static int map__process_kallsym_symbol(void *arg, const char *name,
@@ -833,7 +796,7 @@ static void delete_modules(struct rb_root *modules)
833 mi = rb_entry(next, struct module_info, rb_node); 796 mi = rb_entry(next, struct module_info, rb_node);
834 next = rb_next(&mi->rb_node); 797 next = rb_next(&mi->rb_node);
835 rb_erase(&mi->rb_node, modules); 798 rb_erase(&mi->rb_node, modules);
836 free(mi->name); 799 zfree(&mi->name);
837 free(mi); 800 free(mi);
838 } 801 }
839} 802}
@@ -1126,10 +1089,10 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
1126 * dso__data_read_addr(). 1089 * dso__data_read_addr().
1127 */ 1090 */
1128 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1091 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1129 dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE; 1092 dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE;
1130 else 1093 else
1131 dso->data_type = DSO_BINARY_TYPE__KCORE; 1094 dso->binary_type = DSO_BINARY_TYPE__KCORE;
1132 dso__set_long_name(dso, strdup(kcore_filename)); 1095 dso__set_long_name(dso, strdup(kcore_filename), true);
1133 1096
1134 close(fd); 1097 close(fd);
1135 1098
@@ -1295,8 +1258,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1295 1258
1296 enum dso_binary_type symtab_type = binary_type_symtab[i]; 1259 enum dso_binary_type symtab_type = binary_type_symtab[i];
1297 1260
1298 if (dso__binary_type_file(dso, symtab_type, 1261 if (dso__read_binary_type_filename(dso, symtab_type,
1299 root_dir, name, PATH_MAX)) 1262 root_dir, name, PATH_MAX))
1300 continue; 1263 continue;
1301 1264
1302 /* Name is now the name of the next image to try */ 1265 /* Name is now the name of the next image to try */
@@ -1306,6 +1269,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1306 if (!syms_ss && symsrc__has_symtab(ss)) { 1269 if (!syms_ss && symsrc__has_symtab(ss)) {
1307 syms_ss = ss; 1270 syms_ss = ss;
1308 next_slot = true; 1271 next_slot = true;
1272 if (!dso->symsrc_filename)
1273 dso->symsrc_filename = strdup(name);
1309 } 1274 }
1310 1275
1311 if (!runtime_ss && symsrc__possibly_runtime(ss)) { 1276 if (!runtime_ss && symsrc__possibly_runtime(ss)) {
@@ -1376,7 +1341,8 @@ struct map *map_groups__find_by_name(struct map_groups *mg,
1376} 1341}
1377 1342
1378int dso__load_vmlinux(struct dso *dso, struct map *map, 1343int dso__load_vmlinux(struct dso *dso, struct map *map,
1379 const char *vmlinux, symbol_filter_t filter) 1344 const char *vmlinux, bool vmlinux_allocated,
1345 symbol_filter_t filter)
1380{ 1346{
1381 int err = -1; 1347 int err = -1;
1382 struct symsrc ss; 1348 struct symsrc ss;
@@ -1402,10 +1368,10 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
1402 1368
1403 if (err > 0) { 1369 if (err > 0) {
1404 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1370 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1405 dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 1371 dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
1406 else 1372 else
1407 dso->data_type = DSO_BINARY_TYPE__VMLINUX; 1373 dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
1408 dso__set_long_name(dso, (char *)vmlinux); 1374 dso__set_long_name(dso, vmlinux, vmlinux_allocated);
1409 dso__set_loaded(dso, map->type); 1375 dso__set_loaded(dso, map->type);
1410 pr_debug("Using %s for symbols\n", symfs_vmlinux); 1376 pr_debug("Using %s for symbols\n", symfs_vmlinux);
1411 } 1377 }
@@ -1424,21 +1390,16 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1424 1390
1425 filename = dso__build_id_filename(dso, NULL, 0); 1391 filename = dso__build_id_filename(dso, NULL, 0);
1426 if (filename != NULL) { 1392 if (filename != NULL) {
1427 err = dso__load_vmlinux(dso, map, filename, filter); 1393 err = dso__load_vmlinux(dso, map, filename, true, filter);
1428 if (err > 0) { 1394 if (err > 0)
1429 dso->lname_alloc = 1;
1430 goto out; 1395 goto out;
1431 }
1432 free(filename); 1396 free(filename);
1433 } 1397 }
1434 1398
1435 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1399 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1436 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 1400 err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
1437 if (err > 0) { 1401 if (err > 0)
1438 dso__set_long_name(dso, strdup(vmlinux_path[i]));
1439 dso->lname_alloc = 1;
1440 break; 1402 break;
1441 }
1442 } 1403 }
1443out: 1404out:
1444 return err; 1405 return err;
@@ -1496,14 +1457,15 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
1496 1457
1497 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 1458 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
1498 1459
1460 scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir,
1461 sbuild_id);
1462
1499 /* Use /proc/kallsyms if possible */ 1463 /* Use /proc/kallsyms if possible */
1500 if (is_host) { 1464 if (is_host) {
1501 DIR *d; 1465 DIR *d;
1502 int fd; 1466 int fd;
1503 1467
1504 /* If no cached kcore go with /proc/kallsyms */ 1468 /* If no cached kcore go with /proc/kallsyms */
1505 scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s",
1506 buildid_dir, sbuild_id);
1507 d = opendir(path); 1469 d = opendir(path);
1508 if (!d) 1470 if (!d)
1509 goto proc_kallsyms; 1471 goto proc_kallsyms;
@@ -1528,6 +1490,10 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
1528 goto proc_kallsyms; 1490 goto proc_kallsyms;
1529 } 1491 }
1530 1492
1493 /* Find kallsyms in build-id cache with kcore */
1494 if (!find_matching_kcore(map, path, sizeof(path)))
1495 return strdup(path);
1496
1531 scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", 1497 scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
1532 buildid_dir, sbuild_id); 1498 buildid_dir, sbuild_id);
1533 1499
@@ -1570,15 +1536,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1570 } 1536 }
1571 1537
1572 if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 1538 if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
1573 err = dso__load_vmlinux(dso, map, 1539 return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name,
1574 symbol_conf.vmlinux_name, filter); 1540 false, filter);
1575 if (err > 0) {
1576 dso__set_long_name(dso,
1577 strdup(symbol_conf.vmlinux_name));
1578 dso->lname_alloc = 1;
1579 return err;
1580 }
1581 return err;
1582 } 1541 }
1583 1542
1584 if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 1543 if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
@@ -1604,7 +1563,7 @@ do_kallsyms:
1604 free(kallsyms_allocated_filename); 1563 free(kallsyms_allocated_filename);
1605 1564
1606 if (err > 0 && !dso__is_kcore(dso)) { 1565 if (err > 0 && !dso__is_kcore(dso)) {
1607 dso__set_long_name(dso, strdup("[kernel.kallsyms]")); 1566 dso__set_long_name(dso, "[kernel.kallsyms]", false);
1608 map__fixup_start(map); 1567 map__fixup_start(map);
1609 map__fixup_end(map); 1568 map__fixup_end(map);
1610 } 1569 }
@@ -1634,7 +1593,8 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1634 */ 1593 */
1635 if (symbol_conf.default_guest_vmlinux_name != NULL) { 1594 if (symbol_conf.default_guest_vmlinux_name != NULL) {
1636 err = dso__load_vmlinux(dso, map, 1595 err = dso__load_vmlinux(dso, map,
1637 symbol_conf.default_guest_vmlinux_name, filter); 1596 symbol_conf.default_guest_vmlinux_name,
1597 false, filter);
1638 return err; 1598 return err;
1639 } 1599 }
1640 1600
@@ -1651,7 +1611,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1651 pr_debug("Using %s for symbols\n", kallsyms_filename); 1611 pr_debug("Using %s for symbols\n", kallsyms_filename);
1652 if (err > 0 && !dso__is_kcore(dso)) { 1612 if (err > 0 && !dso__is_kcore(dso)) {
1653 machine__mmap_name(machine, path, sizeof(path)); 1613 machine__mmap_name(machine, path, sizeof(path));
1654 dso__set_long_name(dso, strdup(path)); 1614 dso__set_long_name(dso, strdup(path), true);
1655 map__fixup_start(map); 1615 map__fixup_start(map);
1656 map__fixup_end(map); 1616 map__fixup_end(map);
1657 } 1617 }
@@ -1661,13 +1621,10 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1661 1621
1662static void vmlinux_path__exit(void) 1622static void vmlinux_path__exit(void)
1663{ 1623{
1664 while (--vmlinux_path__nr_entries >= 0) { 1624 while (--vmlinux_path__nr_entries >= 0)
1665 free(vmlinux_path[vmlinux_path__nr_entries]); 1625 zfree(&vmlinux_path[vmlinux_path__nr_entries]);
1666 vmlinux_path[vmlinux_path__nr_entries] = NULL;
1667 }
1668 1626
1669 free(vmlinux_path); 1627 zfree(&vmlinux_path);
1670 vmlinux_path = NULL;
1671} 1628}
1672 1629
1673static int vmlinux_path__init(void) 1630static int vmlinux_path__init(void)
@@ -1719,7 +1676,7 @@ out_fail:
1719 return -1; 1676 return -1;
1720} 1677}
1721 1678
1722static int setup_list(struct strlist **list, const char *list_str, 1679int setup_list(struct strlist **list, const char *list_str,
1723 const char *list_name) 1680 const char *list_name)
1724{ 1681{
1725 if (list_str == NULL) 1682 if (list_str == NULL)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 07de8fea2f48..fffe2888a1c7 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -52,6 +52,11 @@ static inline char *bfd_demangle(void __maybe_unused *v,
52# define PERF_ELF_C_READ_MMAP ELF_C_READ 52# define PERF_ELF_C_READ_MMAP ELF_C_READ
53#endif 53#endif
54 54
55#ifdef HAVE_LIBELF_SUPPORT
56extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
57 GElf_Shdr *shp, const char *name, size_t *idx);
58#endif
59
55#ifndef DMGL_PARAMS 60#ifndef DMGL_PARAMS
56#define DMGL_PARAMS (1 << 0) /* Include function args */ 61#define DMGL_PARAMS (1 << 0) /* Include function args */
57#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 62#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
@@ -164,6 +169,7 @@ struct mem_info {
164}; 169};
165 170
166struct addr_location { 171struct addr_location {
172 struct machine *machine;
167 struct thread *thread; 173 struct thread *thread;
168 struct map *map; 174 struct map *map;
169 struct symbol *sym; 175 struct symbol *sym;
@@ -206,7 +212,8 @@ bool symsrc__possibly_runtime(struct symsrc *ss);
206 212
207int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); 213int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter);
208int dso__load_vmlinux(struct dso *dso, struct map *map, 214int dso__load_vmlinux(struct dso *dso, struct map *map,
209 const char *vmlinux, symbol_filter_t filter); 215 const char *vmlinux, bool vmlinux_allocated,
216 symbol_filter_t filter);
210int dso__load_vmlinux_path(struct dso *dso, struct map *map, 217int dso__load_vmlinux_path(struct dso *dso, struct map *map,
211 symbol_filter_t filter); 218 symbol_filter_t filter);
212int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, 219int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
@@ -220,9 +227,6 @@ struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
220 227
221int filename__read_build_id(const char *filename, void *bf, size_t size); 228int filename__read_build_id(const char *filename, void *bf, size_t size);
222int sysfs__read_build_id(const char *filename, void *bf, size_t size); 229int sysfs__read_build_id(const char *filename, void *bf, size_t size);
223int kallsyms__parse(const char *filename, void *arg,
224 int (*process_symbol)(void *arg, const char *name,
225 char type, u64 start));
226int modules__parse(const char *filename, void *arg, 230int modules__parse(const char *filename, void *arg,
227 int (*process_module)(void *arg, const char *name, 231 int (*process_module)(void *arg, const char *name,
228 u64 start)); 232 u64 start));
@@ -240,6 +244,7 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp);
240bool symbol_type__is_a(char symbol_type, enum map_type map_type); 244bool symbol_type__is_a(char symbol_type, enum map_type map_type);
241bool symbol__restricted_filename(const char *filename, 245bool symbol__restricted_filename(const char *filename,
242 const char *restricted_filename); 246 const char *restricted_filename);
247bool symbol__is_idle(struct symbol *sym);
243 248
244int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, 249int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
245 struct symsrc *runtime_ss, symbol_filter_t filter, 250 struct symsrc *runtime_ss, symbol_filter_t filter,
@@ -273,4 +278,7 @@ void kcore_extract__delete(struct kcore_extract *kce);
273int kcore_copy(const char *from_dir, const char *to_dir); 278int kcore_copy(const char *from_dir, const char *to_dir);
274int compare_proc_modules(const char *from, const char *to); 279int compare_proc_modules(const char *from, const char *to);
275 280
281int setup_list(struct strlist **list, const char *list_str,
282 const char *list_name);
283
276#endif /* __PERF_SYMBOL */ 284#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
index 3c778a07b7cc..e74c5963dc7a 100644
--- a/tools/perf/util/target.c
+++ b/tools/perf/util/target.c
@@ -55,6 +55,13 @@ enum target_errno target__validate(struct target *target)
55 ret = TARGET_ERRNO__UID_OVERRIDE_SYSTEM; 55 ret = TARGET_ERRNO__UID_OVERRIDE_SYSTEM;
56 } 56 }
57 57
58 /* THREAD and SYSTEM/CPU are mutually exclusive */
59 if (target->per_thread && (target->system_wide || target->cpu_list)) {
60 target->per_thread = false;
61 if (ret == TARGET_ERRNO__SUCCESS)
62 ret = TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD;
63 }
64
58 return ret; 65 return ret;
59} 66}
60 67
@@ -100,6 +107,7 @@ static const char *target__error_str[] = {
100 "UID switch overriding CPU", 107 "UID switch overriding CPU",
101 "PID/TID switch overriding SYSTEM", 108 "PID/TID switch overriding SYSTEM",
102 "UID switch overriding SYSTEM", 109 "UID switch overriding SYSTEM",
110 "SYSTEM/CPU switch overriding PER-THREAD",
103 "Invalid User: %s", 111 "Invalid User: %s",
104 "Problems obtaining information for user %s", 112 "Problems obtaining information for user %s",
105}; 113};
@@ -131,7 +139,8 @@ int target__strerror(struct target *target, int errnum,
131 msg = target__error_str[idx]; 139 msg = target__error_str[idx];
132 140
133 switch (errnum) { 141 switch (errnum) {
134 case TARGET_ERRNO__PID_OVERRIDE_CPU ... TARGET_ERRNO__UID_OVERRIDE_SYSTEM: 142 case TARGET_ERRNO__PID_OVERRIDE_CPU ...
143 TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD:
135 snprintf(buf, buflen, "%s", msg); 144 snprintf(buf, buflen, "%s", msg);
136 break; 145 break;
137 146
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h
index 2d0c50690892..7381b1ca4041 100644
--- a/tools/perf/util/target.h
+++ b/tools/perf/util/target.h
@@ -12,7 +12,8 @@ struct target {
12 uid_t uid; 12 uid_t uid;
13 bool system_wide; 13 bool system_wide;
14 bool uses_mmap; 14 bool uses_mmap;
15 bool force_per_cpu; 15 bool default_per_cpu;
16 bool per_thread;
16}; 17};
17 18
18enum target_errno { 19enum target_errno {
@@ -33,6 +34,7 @@ enum target_errno {
33 TARGET_ERRNO__UID_OVERRIDE_CPU, 34 TARGET_ERRNO__UID_OVERRIDE_CPU,
34 TARGET_ERRNO__PID_OVERRIDE_SYSTEM, 35 TARGET_ERRNO__PID_OVERRIDE_SYSTEM,
35 TARGET_ERRNO__UID_OVERRIDE_SYSTEM, 36 TARGET_ERRNO__UID_OVERRIDE_SYSTEM,
37 TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD,
36 38
37 /* for target__parse_uid() */ 39 /* for target__parse_uid() */
38 TARGET_ERRNO__INVALID_UID, 40 TARGET_ERRNO__INVALID_UID,
@@ -61,4 +63,17 @@ static inline bool target__none(struct target *target)
61 return !target__has_task(target) && !target__has_cpu(target); 63 return !target__has_task(target) && !target__has_cpu(target);
62} 64}
63 65
66static inline bool target__uses_dummy_map(struct target *target)
67{
68 bool use_dummy = false;
69
70 if (target->default_per_cpu)
71 use_dummy = target->per_thread ? true : false;
72 else if (target__has_task(target) ||
73 (!target__has_cpu(target) && !target->uses_mmap))
74 use_dummy = true;
75
76 return use_dummy;
77}
78
64#endif /* _PERF_TARGET_H */ 79#endif /* _PERF_TARGET_H */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 49eaf1d7d89d..0358882c8910 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -66,10 +66,13 @@ struct comm *thread__comm(const struct thread *thread)
66int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) 66int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
67{ 67{
68 struct comm *new, *curr = thread__comm(thread); 68 struct comm *new, *curr = thread__comm(thread);
69 int err;
69 70
70 /* Override latest entry if it had no specific time coverage */ 71 /* Override latest entry if it had no specific time coverage */
71 if (!curr->start) { 72 if (!curr->start) {
72 comm__override(curr, str, timestamp); 73 err = comm__override(curr, str, timestamp);
74 if (err)
75 return err;
73 } else { 76 } else {
74 new = comm__new(str, timestamp); 77 new = comm__new(str, timestamp);
75 if (!new) 78 if (!new)
@@ -126,7 +129,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
126 if (!comm) 129 if (!comm)
127 return -ENOMEM; 130 return -ENOMEM;
128 err = thread__set_comm(thread, comm, timestamp); 131 err = thread__set_comm(thread, comm, timestamp);
129 if (!err) 132 if (err)
130 return err; 133 return err;
131 thread->comm_set = true; 134 thread->comm_set = true;
132 } 135 }
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 897c1b2a750a..5b856bf942e1 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -6,6 +6,7 @@
6#include <unistd.h> 6#include <unistd.h>
7#include <sys/types.h> 7#include <sys/types.h>
8#include "symbol.h" 8#include "symbol.h"
9#include <strlist.h>
9 10
10struct thread { 11struct thread {
11 union { 12 union {
@@ -66,4 +67,15 @@ static inline void thread__set_priv(struct thread *thread, void *p)
66{ 67{
67 thread->priv = p; 68 thread->priv = p;
68} 69}
70
71static inline bool thread__is_filtered(struct thread *thread)
72{
73 if (symbol_conf.comm_list &&
74 !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread))) {
75 return true;
76 }
77
78 return false;
79}
80
69#endif /* __PERF_THREAD_H */ 81#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 9b5f856cc280..5d3215912105 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -9,6 +9,7 @@
9#include "strlist.h" 9#include "strlist.h"
10#include <string.h> 10#include <string.h>
11#include "thread_map.h" 11#include "thread_map.h"
12#include "util.h"
12 13
13/* Skip "." and ".." directories */ 14/* Skip "." and ".." directories */
14static int filter(const struct dirent *dir) 15static int filter(const struct dirent *dir)
@@ -40,7 +41,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
40 } 41 }
41 42
42 for (i=0; i<items; i++) 43 for (i=0; i<items; i++)
43 free(namelist[i]); 44 zfree(&namelist[i]);
44 free(namelist); 45 free(namelist);
45 46
46 return threads; 47 return threads;
@@ -117,7 +118,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
117 threads->map[threads->nr + i] = atoi(namelist[i]->d_name); 118 threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
118 119
119 for (i = 0; i < items; i++) 120 for (i = 0; i < items; i++)
120 free(namelist[i]); 121 zfree(&namelist[i]);
121 free(namelist); 122 free(namelist);
122 123
123 threads->nr += items; 124 threads->nr += items;
@@ -134,12 +135,11 @@ out_free_threads:
134 135
135out_free_namelist: 136out_free_namelist:
136 for (i = 0; i < items; i++) 137 for (i = 0; i < items; i++)
137 free(namelist[i]); 138 zfree(&namelist[i]);
138 free(namelist); 139 free(namelist);
139 140
140out_free_closedir: 141out_free_closedir:
141 free(threads); 142 zfree(&threads);
142 threads = NULL;
143 goto out_closedir; 143 goto out_closedir;
144} 144}
145 145
@@ -194,7 +194,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
194 194
195 for (i = 0; i < items; i++) { 195 for (i = 0; i < items; i++) {
196 threads->map[j++] = atoi(namelist[i]->d_name); 196 threads->map[j++] = atoi(namelist[i]->d_name);
197 free(namelist[i]); 197 zfree(&namelist[i]);
198 } 198 }
199 threads->nr = total_tasks; 199 threads->nr = total_tasks;
200 free(namelist); 200 free(namelist);
@@ -206,12 +206,11 @@ out:
206 206
207out_free_namelist: 207out_free_namelist:
208 for (i = 0; i < items; i++) 208 for (i = 0; i < items; i++)
209 free(namelist[i]); 209 zfree(&namelist[i]);
210 free(namelist); 210 free(namelist);
211 211
212out_free_threads: 212out_free_threads:
213 free(threads); 213 zfree(&threads);
214 threads = NULL;
215 goto out; 214 goto out;
216} 215}
217 216
@@ -262,8 +261,7 @@ out:
262 return threads; 261 return threads;
263 262
264out_free_threads: 263out_free_threads:
265 free(threads); 264 zfree(&threads);
266 threads = NULL;
267 goto out; 265 goto out;
268} 266}
269 267
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index ce793c7dd23c..8e517def925b 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -26,7 +26,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
26 float samples_per_sec; 26 float samples_per_sec;
27 float ksamples_per_sec; 27 float ksamples_per_sec;
28 float esamples_percent; 28 float esamples_percent;
29 struct perf_record_opts *opts = &top->record_opts; 29 struct record_opts *opts = &top->record_opts;
30 struct target *target = &opts->target; 30 struct target *target = &opts->target;
31 size_t ret = 0; 31 size_t ret = 0;
32 32
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 88cfeaff600b..dab14d0ad3d0 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -14,7 +14,7 @@ struct perf_session;
14struct perf_top { 14struct perf_top {
15 struct perf_tool tool; 15 struct perf_tool tool;
16 struct perf_evlist *evlist; 16 struct perf_evlist *evlist;
17 struct perf_record_opts record_opts; 17 struct record_opts record_opts;
18 /* 18 /*
19 * Symbols will be added here in perf_event__process_sample and will 19 * Symbols will be added here in perf_event__process_sample and will
20 * get out after decayed. 20 * get out after decayed.
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index f3c9e551bd35..7e6fcfe8b438 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -38,7 +38,7 @@
38 38
39#include "../perf.h" 39#include "../perf.h"
40#include "trace-event.h" 40#include "trace-event.h"
41#include <lk/debugfs.h> 41#include <api/fs/debugfs.h>
42#include "evsel.h" 42#include "evsel.h"
43 43
44#define VERSION "0.5" 44#define VERSION "0.5"
@@ -397,8 +397,8 @@ put_tracepoints_path(struct tracepoint_path *tps)
397 struct tracepoint_path *t = tps; 397 struct tracepoint_path *t = tps;
398 398
399 tps = tps->next; 399 tps = tps->next;
400 free(t->name); 400 zfree(&t->name);
401 free(t->system); 401 zfree(&t->system);
402 free(t); 402 free(t);
403 } 403 }
404} 404}
@@ -562,10 +562,8 @@ out:
562 output_fd = fd; 562 output_fd = fd;
563 } 563 }
564 564
565 if (err) { 565 if (err)
566 free(tdata); 566 zfree(&tdata);
567 tdata = NULL;
568 }
569 567
570 put_tracepoints_path(tps); 568 put_tracepoints_path(tps);
571 return tdata; 569 return tdata;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 6681f71f2f95..e0d6d07f6848 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -28,19 +28,6 @@
28#include "util.h" 28#include "util.h"
29#include "trace-event.h" 29#include "trace-event.h"
30 30
31struct pevent *read_trace_init(int file_bigendian, int host_bigendian)
32{
33 struct pevent *pevent = pevent_alloc();
34
35 if (pevent != NULL) {
36 pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
37 pevent_set_file_bigendian(pevent, file_bigendian);
38 pevent_set_host_bigendian(pevent, host_bigendian);
39 }
40
41 return pevent;
42}
43
44static int get_common_field(struct scripting_context *context, 31static int get_common_field(struct scripting_context *context,
45 int *offset, int *size, const char *type) 32 int *offset, int *size, const char *type)
46{ 33{
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index f2112270c663..e113e180c48f 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -343,7 +343,7 @@ static int read_event_files(struct pevent *pevent)
343 return 0; 343 return 0;
344} 344}
345 345
346ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) 346ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
347{ 347{
348 char buf[BUFSIZ]; 348 char buf[BUFSIZ];
349 char test[] = { 23, 8, 68 }; 349 char test[] = { 23, 8, 68 };
@@ -356,11 +356,9 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
356 int host_bigendian; 356 int host_bigendian;
357 int file_long_size; 357 int file_long_size;
358 int file_page_size; 358 int file_page_size;
359 struct pevent *pevent; 359 struct pevent *pevent = NULL;
360 int err; 360 int err;
361 361
362 *ppevent = NULL;
363
364 repipe = __repipe; 362 repipe = __repipe;
365 input_fd = fd; 363 input_fd = fd;
366 364
@@ -390,12 +388,17 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
390 file_bigendian = buf[0]; 388 file_bigendian = buf[0];
391 host_bigendian = bigendian(); 389 host_bigendian = bigendian();
392 390
393 pevent = read_trace_init(file_bigendian, host_bigendian); 391 if (trace_event__init(tevent)) {
394 if (pevent == NULL) { 392 pr_debug("trace_event__init failed");
395 pr_debug("read_trace_init failed");
396 goto out; 393 goto out;
397 } 394 }
398 395
396 pevent = tevent->pevent;
397
398 pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
399 pevent_set_file_bigendian(pevent, file_bigendian);
400 pevent_set_host_bigendian(pevent, host_bigendian);
401
399 if (do_read(buf, 1) < 0) 402 if (do_read(buf, 1) < 0)
400 goto out; 403 goto out;
401 file_long_size = buf[0]; 404 file_long_size = buf[0];
@@ -432,11 +435,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
432 pevent_print_printk(pevent); 435 pevent_print_printk(pevent);
433 } 436 }
434 437
435 *ppevent = pevent;
436 pevent = NULL; 438 pevent = NULL;
437 439
438out: 440out:
439 if (pevent) 441 if (pevent)
440 pevent_free(pevent); 442 trace_event__cleanup(tevent);
441 return size; 443 return size;
442} 444}
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index 95199e4eea97..57aaccc1692e 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -38,9 +38,8 @@ static int stop_script_unsupported(void)
38static void process_event_unsupported(union perf_event *event __maybe_unused, 38static void process_event_unsupported(union perf_event *event __maybe_unused,
39 struct perf_sample *sample __maybe_unused, 39 struct perf_sample *sample __maybe_unused,
40 struct perf_evsel *evsel __maybe_unused, 40 struct perf_evsel *evsel __maybe_unused,
41 struct machine *machine __maybe_unused,
42 struct thread *thread __maybe_unused, 41 struct thread *thread __maybe_unused,
43 struct addr_location *al __maybe_unused) 42 struct addr_location *al __maybe_unused)
44{ 43{
45} 44}
46 45
diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c
new file mode 100644
index 000000000000..6322d37164c5
--- /dev/null
+++ b/tools/perf/util/trace-event.c
@@ -0,0 +1,82 @@
1
2#include <stdio.h>
3#include <unistd.h>
4#include <stdlib.h>
5#include <errno.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <fcntl.h>
9#include <linux/kernel.h>
10#include <traceevent/event-parse.h>
11#include "trace-event.h"
12#include "util.h"
13
14/*
15 * global trace_event object used by trace_event__tp_format
16 *
17 * TODO There's no cleanup call for this. Add some sort of
18 * __exit function support and call trace_event__cleanup
19 * there.
20 */
21static struct trace_event tevent;
22
23int trace_event__init(struct trace_event *t)
24{
25 struct pevent *pevent = pevent_alloc();
26
27 if (pevent) {
28 t->plugin_list = traceevent_load_plugins(pevent);
29 t->pevent = pevent;
30 }
31
32 return pevent ? 0 : -1;
33}
34
35void trace_event__cleanup(struct trace_event *t)
36{
37 traceevent_unload_plugins(t->plugin_list, t->pevent);
38 pevent_free(t->pevent);
39}
40
41static struct event_format*
42tp_format(const char *sys, const char *name)
43{
44 struct pevent *pevent = tevent.pevent;
45 struct event_format *event = NULL;
46 char path[PATH_MAX];
47 size_t size;
48 char *data;
49
50 scnprintf(path, PATH_MAX, "%s/%s/%s/format",
51 tracing_events_path, sys, name);
52
53 if (filename__read_str(path, &data, &size))
54 return NULL;
55
56 pevent_parse_format(pevent, &event, data, size, sys);
57
58 free(data);
59 return event;
60}
61
62struct event_format*
63trace_event__tp_format(const char *sys, const char *name)
64{
65 static bool initialized;
66
67 if (!initialized) {
68 int be = traceevent_host_bigendian();
69 struct pevent *pevent;
70
71 if (trace_event__init(&tevent))
72 return NULL;
73
74 pevent = tevent.pevent;
75 pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
76 pevent_set_file_bigendian(pevent, be);
77 pevent_set_host_bigendian(pevent, be);
78 initialized = true;
79 }
80
81 return tp_format(sys, name);
82}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 04df63114109..7b6d68688327 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -3,17 +3,26 @@
3 3
4#include <traceevent/event-parse.h> 4#include <traceevent/event-parse.h>
5#include "parse-events.h" 5#include "parse-events.h"
6#include "session.h"
7 6
8struct machine; 7struct machine;
9struct perf_sample; 8struct perf_sample;
10union perf_event; 9union perf_event;
11struct perf_tool; 10struct perf_tool;
12struct thread; 11struct thread;
12struct plugin_list;
13
14struct trace_event {
15 struct pevent *pevent;
16 struct plugin_list *plugin_list;
17};
18
19int trace_event__init(struct trace_event *t);
20void trace_event__cleanup(struct trace_event *t);
21struct event_format*
22trace_event__tp_format(const char *sys, const char *name);
13 23
14int bigendian(void); 24int bigendian(void);
15 25
16struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
17void event_format__print(struct event_format *event, 26void event_format__print(struct event_format *event,
18 int cpu, void *data, int size); 27 int cpu, void *data, int size);
19 28
@@ -27,7 +36,7 @@ raw_field_value(struct event_format *event, const char *name, void *data);
27void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); 36void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
28void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); 37void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
29 38
30ssize_t trace_report(int fd, struct pevent **pevent, bool repipe); 39ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe);
31 40
32struct event_format *trace_find_next_event(struct pevent *pevent, 41struct event_format *trace_find_next_event(struct pevent *pevent,
33 struct event_format *event); 42 struct event_format *event);
@@ -59,7 +68,6 @@ struct scripting_ops {
59 void (*process_event) (union perf_event *event, 68 void (*process_event) (union perf_event *event,
60 struct perf_sample *sample, 69 struct perf_sample *sample,
61 struct perf_evsel *evsel, 70 struct perf_evsel *evsel,
62 struct machine *machine,
63 struct thread *thread, 71 struct thread *thread,
64 struct addr_location *al); 72 struct addr_location *al);
65 int (*generate_script) (struct pevent *pevent, const char *outfile); 73 int (*generate_script) (struct pevent *pevent, const char *outfile);
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 0efd5393de85..742f23bf35ff 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -28,6 +28,7 @@
28#include "session.h" 28#include "session.h"
29#include "perf_regs.h" 29#include "perf_regs.h"
30#include "unwind.h" 30#include "unwind.h"
31#include "symbol.h"
31#include "util.h" 32#include "util.h"
32 33
33extern int 34extern int
@@ -158,23 +159,6 @@ static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
158 __v; \ 159 __v; \
159 }) 160 })
160 161
161static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
162 GElf_Shdr *shp, const char *name)
163{
164 Elf_Scn *sec = NULL;
165
166 while ((sec = elf_nextscn(elf, sec)) != NULL) {
167 char *str;
168
169 gelf_getshdr(sec, shp);
170 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
171 if (!strcmp(name, str))
172 break;
173 }
174
175 return sec;
176}
177
178static u64 elf_section_offset(int fd, const char *name) 162static u64 elf_section_offset(int fd, const char *name)
179{ 163{
180 Elf *elf; 164 Elf *elf;
@@ -190,7 +174,7 @@ static u64 elf_section_offset(int fd, const char *name)
190 if (gelf_getehdr(elf, &ehdr) == NULL) 174 if (gelf_getehdr(elf, &ehdr) == NULL)
191 break; 175 break;
192 176
193 if (!elf_section_by_name(elf, &ehdr, &shdr, name)) 177 if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL))
194 break; 178 break;
195 179
196 offset = shdr.sh_offset; 180 offset = shdr.sh_offset;
@@ -340,10 +324,10 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
340 /* Check the .debug_frame section for unwinding info */ 324 /* Check the .debug_frame section for unwinding info */
341 if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { 325 if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
342 memset(&di, 0, sizeof(di)); 326 memset(&di, 0, sizeof(di));
343 dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name, 327 if (dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name,
344 map->start, map->end); 328 map->start, map->end))
345 return dwarf_search_unwind_table(as, ip, &di, pi, 329 return dwarf_search_unwind_table(as, ip, &di, pi,
346 need_unwind_info, arg); 330 need_unwind_info, arg);
347 } 331 }
348#endif 332#endif
349 333
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 28a0a89c1f73..42ad667bb317 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -1,11 +1,17 @@
1#include "../perf.h" 1#include "../perf.h"
2#include "util.h" 2#include "util.h"
3#include "fs.h"
3#include <sys/mman.h> 4#include <sys/mman.h>
4#ifdef HAVE_BACKTRACE_SUPPORT 5#ifdef HAVE_BACKTRACE_SUPPORT
5#include <execinfo.h> 6#include <execinfo.h>
6#endif 7#endif
7#include <stdio.h> 8#include <stdio.h>
8#include <stdlib.h> 9#include <stdlib.h>
10#include <string.h>
11#include <errno.h>
12#include <limits.h>
13#include <byteswap.h>
14#include <linux/kernel.h>
9 15
10/* 16/*
11 * XXX We need to find a better place for these things... 17 * XXX We need to find a better place for these things...
@@ -151,21 +157,40 @@ unsigned long convert_unit(unsigned long value, char *unit)
151 return value; 157 return value;
152} 158}
153 159
154int readn(int fd, void *buf, size_t n) 160static ssize_t ion(bool is_read, int fd, void *buf, size_t n)
155{ 161{
156 void *buf_start = buf; 162 void *buf_start = buf;
163 size_t left = n;
157 164
158 while (n) { 165 while (left) {
159 int ret = read(fd, buf, n); 166 ssize_t ret = is_read ? read(fd, buf, left) :
167 write(fd, buf, left);
160 168
161 if (ret <= 0) 169 if (ret <= 0)
162 return ret; 170 return ret;
163 171
164 n -= ret; 172 left -= ret;
165 buf += ret; 173 buf += ret;
166 } 174 }
167 175
168 return buf - buf_start; 176 BUG_ON((size_t)(buf - buf_start) != n);
177 return n;
178}
179
180/*
181 * Read exactly 'n' bytes or return an error.
182 */
183ssize_t readn(int fd, void *buf, size_t n)
184{
185 return ion(true, fd, buf, n);
186}
187
188/*
189 * Write exactly 'n' bytes or return an error.
190 */
191ssize_t writen(int fd, void *buf, size_t n)
192{
193 return ion(false, fd, buf, n);
169} 194}
170 195
171size_t hex_width(u64 v) 196size_t hex_width(u64 v)
@@ -413,3 +438,102 @@ int filename__read_int(const char *filename, int *value)
413 close(fd); 438 close(fd);
414 return err; 439 return err;
415} 440}
441
442int filename__read_str(const char *filename, char **buf, size_t *sizep)
443{
444 size_t size = 0, alloc_size = 0;
445 void *bf = NULL, *nbf;
446 int fd, n, err = 0;
447
448 fd = open(filename, O_RDONLY);
449 if (fd < 0)
450 return -errno;
451
452 do {
453 if (size == alloc_size) {
454 alloc_size += BUFSIZ;
455 nbf = realloc(bf, alloc_size);
456 if (!nbf) {
457 err = -ENOMEM;
458 break;
459 }
460
461 bf = nbf;
462 }
463
464 n = read(fd, bf + size, alloc_size - size);
465 if (n < 0) {
466 if (size) {
467 pr_warning("read failed %d: %s\n",
468 errno, strerror(errno));
469 err = 0;
470 } else
471 err = -errno;
472
473 break;
474 }
475
476 size += n;
477 } while (n > 0);
478
479 if (!err) {
480 *sizep = size;
481 *buf = bf;
482 } else
483 free(bf);
484
485 close(fd);
486 return err;
487}
488
489const char *get_filename_for_perf_kvm(void)
490{
491 const char *filename;
492
493 if (perf_host && !perf_guest)
494 filename = strdup("perf.data.host");
495 else if (!perf_host && perf_guest)
496 filename = strdup("perf.data.guest");
497 else
498 filename = strdup("perf.data.kvm");
499
500 return filename;
501}
502
503int perf_event_paranoid(void)
504{
505 char path[PATH_MAX];
506 const char *procfs = procfs__mountpoint();
507 int value;
508
509 if (!procfs)
510 return INT_MAX;
511
512 scnprintf(path, PATH_MAX, "%s/sys/kernel/perf_event_paranoid", procfs);
513
514 if (filename__read_int(path, &value))
515 return INT_MAX;
516
517 return value;
518}
519
520void mem_bswap_32(void *src, int byte_size)
521{
522 u32 *m = src;
523 while (byte_size > 0) {
524 *m = bswap_32(*m);
525 byte_size -= sizeof(u32);
526 ++m;
527 }
528}
529
530void mem_bswap_64(void *src, int byte_size)
531{
532 u64 *m = src;
533
534 while (byte_size > 0) {
535 *m = bswap_64(*m);
536 byte_size -= sizeof(u64);
537 ++m;
538 }
539}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c8f362daba87..6995d66f225c 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -71,8 +71,9 @@
71#include <linux/magic.h> 71#include <linux/magic.h>
72#include "types.h" 72#include "types.h"
73#include <sys/ttydefaults.h> 73#include <sys/ttydefaults.h>
74#include <lk/debugfs.h> 74#include <api/fs/debugfs.h>
75#include <termios.h> 75#include <termios.h>
76#include <linux/bitops.h>
76 77
77extern const char *graph_line; 78extern const char *graph_line;
78extern const char *graph_dotted_line; 79extern const char *graph_dotted_line;
@@ -185,6 +186,8 @@ static inline void *zalloc(size_t size)
185 return calloc(1, size); 186 return calloc(1, size);
186} 187}
187 188
189#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
190
188static inline int has_extension(const char *filename, const char *ext) 191static inline int has_extension(const char *filename, const char *ext)
189{ 192{
190 size_t len = strlen(filename); 193 size_t len = strlen(filename);
@@ -253,7 +256,8 @@ bool strlazymatch(const char *str, const char *pat);
253int strtailcmp(const char *s1, const char *s2); 256int strtailcmp(const char *s1, const char *s2);
254char *strxfrchar(char *s, char from, char to); 257char *strxfrchar(char *s, char from, char to);
255unsigned long convert_unit(unsigned long value, char *unit); 258unsigned long convert_unit(unsigned long value, char *unit);
256int readn(int fd, void *buf, size_t size); 259ssize_t readn(int fd, void *buf, size_t n);
260ssize_t writen(int fd, void *buf, size_t n);
257 261
258struct perf_event_attr; 262struct perf_event_attr;
259 263
@@ -280,6 +284,17 @@ static inline unsigned next_pow2(unsigned x)
280 return 1ULL << (32 - __builtin_clz(x - 1)); 284 return 1ULL << (32 - __builtin_clz(x - 1));
281} 285}
282 286
287static inline unsigned long next_pow2_l(unsigned long x)
288{
289#if BITS_PER_LONG == 64
290 if (x <= (1UL << 31))
291 return next_pow2(x);
292 return (unsigned long)next_pow2(x >> 32) << 32;
293#else
294 return next_pow2(x);
295#endif
296}
297
283size_t hex_width(u64 v); 298size_t hex_width(u64 v);
284int hex2u64(const char *ptr, u64 *val); 299int hex2u64(const char *ptr, u64 *val);
285 300
@@ -307,4 +322,11 @@ char *get_srcline(struct dso *dso, unsigned long addr);
307void free_srcline(char *srcline); 322void free_srcline(char *srcline);
308 323
309int filename__read_int(const char *filename, int *value); 324int filename__read_int(const char *filename, int *value);
325int filename__read_str(const char *filename, char **buf, size_t *sizep);
326int perf_event_paranoid(void);
327
328void mem_bswap_64(void *src, int byte_size);
329void mem_bswap_32(void *src, int byte_size);
330
331const char *get_filename_for_perf_kvm(void);
310#endif /* GIT_COMPAT_UTIL_H */ 332#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index 697c8b4e59cc..0fb3c1fcd3e6 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -31,14 +31,14 @@ void perf_read_values_destroy(struct perf_read_values *values)
31 return; 31 return;
32 32
33 for (i = 0; i < values->threads; i++) 33 for (i = 0; i < values->threads; i++)
34 free(values->value[i]); 34 zfree(&values->value[i]);
35 free(values->value); 35 zfree(&values->value);
36 free(values->pid); 36 zfree(&values->pid);
37 free(values->tid); 37 zfree(&values->tid);
38 free(values->counterrawid); 38 zfree(&values->counterrawid);
39 for (i = 0; i < values->counters; i++) 39 for (i = 0; i < values->counters; i++)
40 free(values->countername[i]); 40 zfree(&values->countername[i]);
41 free(values->countername); 41 zfree(&values->countername);
42} 42}
43 43
44static void perf_read_values__enlarge_threads(struct perf_read_values *values) 44static void perf_read_values__enlarge_threads(struct perf_read_values *values)
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c
index 39159822d58f..0ddb3b8a89ec 100644
--- a/tools/perf/util/vdso.c
+++ b/tools/perf/util/vdso.c
@@ -103,7 +103,7 @@ struct dso *vdso__dso_findnew(struct list_head *head)
103 dso = dso__new(VDSO__MAP_NAME); 103 dso = dso__new(VDSO__MAP_NAME);
104 if (dso != NULL) { 104 if (dso != NULL) {
105 dsos__add(head, dso); 105 dsos__add(head, dso);
106 dso__set_long_name(dso, file); 106 dso__set_long_name(dso, file, false);
107 } 107 }
108 } 108 }
109 109
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
index ee76544deecb..8abbef164b4e 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -61,6 +61,7 @@ QUIET_SUBDIR1 =
61ifneq ($(findstring $(MAKEFLAGS),s),s) 61ifneq ($(findstring $(MAKEFLAGS),s),s)
62 ifneq ($(V),1) 62 ifneq ($(V),1)
63 QUIET_CC = @echo ' CC '$@; 63 QUIET_CC = @echo ' CC '$@;
64 QUIET_CC_FPIC = @echo ' CC FPIC '$@;
64 QUIET_AR = @echo ' AR '$@; 65 QUIET_AR = @echo ' AR '$@;
65 QUIET_LINK = @echo ' LINK '$@; 66 QUIET_LINK = @echo ' LINK '$@;
66 QUIET_MKDIR = @echo ' MKDIR '$@; 67 QUIET_MKDIR = @echo ' MKDIR '$@;
@@ -76,5 +77,8 @@ ifneq ($(findstring $(MAKEFLAGS),s),s)
76 +@echo ' DESCEND '$(1); \ 77 +@echo ' DESCEND '$(1); \
77 mkdir -p $(OUTPUT)$(1) && \ 78 mkdir -p $(OUTPUT)$(1) && \
78 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2) 79 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2)
80
81 QUIET_CLEAN = @printf ' CLEAN %s\n' $1;
82 QUIET_INSTALL = @printf ' INSTALL %s\n' $1;
79 endif 83 endif
80endif 84endif
diff --git a/tools/vm/Makefile b/tools/vm/Makefile
index 24e9ddd93fa4..3d907dacf2ac 100644
--- a/tools/vm/Makefile
+++ b/tools/vm/Makefile
@@ -2,21 +2,21 @@
2# 2#
3TARGETS=page-types slabinfo 3TARGETS=page-types slabinfo
4 4
5LK_DIR = ../lib/lk 5LIB_DIR = ../lib/api
6LIBLK = $(LK_DIR)/liblk.a 6LIBS = $(LIB_DIR)/libapikfs.a
7 7
8CC = $(CROSS_COMPILE)gcc 8CC = $(CROSS_COMPILE)gcc
9CFLAGS = -Wall -Wextra -I../lib/ 9CFLAGS = -Wall -Wextra -I../lib/
10LDFLAGS = $(LIBLK) 10LDFLAGS = $(LIBS)
11 11
12$(TARGETS): liblk 12$(TARGETS): $(LIBS)
13 13
14liblk: 14$(LIBS):
15 make -C $(LK_DIR) 15 make -C $(LIB_DIR)
16 16
17%: %.c 17%: %.c
18 $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) 18 $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
19 19
20clean: 20clean:
21 $(RM) page-types slabinfo 21 $(RM) page-types slabinfo
22 make -C ../lib/lk clean 22 make -C $(LIB_DIR) clean
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index d5e9d6d185c8..f9be24d9efac 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -36,7 +36,7 @@
36#include <sys/statfs.h> 36#include <sys/statfs.h>
37#include "../../include/uapi/linux/magic.h" 37#include "../../include/uapi/linux/magic.h"
38#include "../../include/uapi/linux/kernel-page-flags.h" 38#include "../../include/uapi/linux/kernel-page-flags.h"
39#include <lk/debugfs.h> 39#include <api/fs/debugfs.h>
40 40
41#ifndef MAX_PATH 41#ifndef MAX_PATH
42# define MAX_PATH 256 42# define MAX_PATH 256