diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-22 14:10:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-22 14:10:36 -0400 |
commit | 2eafeb6a415864bc4c59df79151cf40f6ac74b9e (patch) | |
tree | 331ee730275276aebbda5dd278a97c941067d5fd | |
parent | 16d286e656250859946786de0df0fb01f8f241bc (diff) | |
parent | 6e0f17be0361444862637e8986c8c1a3b3f8dcf8 (diff) |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf events changes from Ingo Molnar:
"- kernel side:
- Intel uncore PMU support for Nehalem and Sandy Bridge CPUs, we
support both the events available via the MSR and via the PCI
access space.
- various uprobes cleanups and restructurings
- PMU driver quirks by microcode version and required x86 microcode
loader cleanups/robustization
- various tracing robustness updates
- static keys: remove obsolete static_branch()
- tooling side:
- GTK browser improvements
- perf report browser: support screenshots to file
- more automated tests
- perf kvm improvements
- perf bench refinements
- build environment improvements
- pipe mode improvements
- libtraceevent updates, we have now hopefully merged most bits with
the out of tree forked code base
... and many other goodies."
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (138 commits)
tracing: Check for allocation failure in __tracing_open()
perf/x86: Fix intel_perfmon_event_mapformatting
jump label: Remove static_branch()
tracepoint: Use static_key_false(), since static_branch() is deprecated
perf/x86: Uncore filter support for SandyBridge-EP
perf/x86: Detect number of instances of uncore CBox
perf/x86: Fix event constraint for SandyBridge-EP C-Box
perf/x86: Use 0xff as pseudo code for fixed uncore event
perf/x86: Save a few bytes in 'struct x86_pmu'
perf/x86: Add a microcode revision check for SNB-PEBS
perf/x86: Improve debug output in check_hw_exists()
perf/x86/amd: Unify AMD's generic and family 15h pmus
perf/x86: Move Intel specific code to intel_pmu_init()
perf/x86: Rename Intel specific macros
perf/x86: Fix USER/KERNEL tagging of samples
perf tools: Split event symbols arrays to hw and sw parts
perf tools: Split out PE_VALUE_SYM parsing token to SW and HW tokens
perf tools: Add empty rule for new line in event syntax parsing
perf test: Use ARRAY_SIZE in parse events tests
tools lib traceevent: Cleanup realloc use
...
109 files changed, 5782 insertions, 1706 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index db7c1f2709a2..2da88c0cda14 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -313,8 +313,8 @@ struct kvm_pmu { | |||
313 | u64 counter_bitmask[2]; | 313 | u64 counter_bitmask[2]; |
314 | u64 global_ctrl_mask; | 314 | u64 global_ctrl_mask; |
315 | u8 version; | 315 | u8 version; |
316 | struct kvm_pmc gp_counters[X86_PMC_MAX_GENERIC]; | 316 | struct kvm_pmc gp_counters[INTEL_PMC_MAX_GENERIC]; |
317 | struct kvm_pmc fixed_counters[X86_PMC_MAX_FIXED]; | 317 | struct kvm_pmc fixed_counters[INTEL_PMC_MAX_FIXED]; |
318 | struct irq_work irq_work; | 318 | struct irq_work irq_work; |
319 | u64 reprogram_pmi; | 319 | u64 reprogram_pmi; |
320 | }; | 320 | }; |
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index 084ef95274cd..813ed103f45e 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h | |||
@@ -115,8 +115,8 @@ notrace static inline int native_write_msr_safe(unsigned int msr, | |||
115 | 115 | ||
116 | extern unsigned long long native_read_tsc(void); | 116 | extern unsigned long long native_read_tsc(void); |
117 | 117 | ||
118 | extern int native_rdmsr_safe_regs(u32 regs[8]); | 118 | extern int rdmsr_safe_regs(u32 regs[8]); |
119 | extern int native_wrmsr_safe_regs(u32 regs[8]); | 119 | extern int wrmsr_safe_regs(u32 regs[8]); |
120 | 120 | ||
121 | static __always_inline unsigned long long __native_read_tsc(void) | 121 | static __always_inline unsigned long long __native_read_tsc(void) |
122 | { | 122 | { |
@@ -187,43 +187,6 @@ static inline int rdmsrl_safe(unsigned msr, unsigned long long *p) | |||
187 | return err; | 187 | return err; |
188 | } | 188 | } |
189 | 189 | ||
190 | static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p) | ||
191 | { | ||
192 | u32 gprs[8] = { 0 }; | ||
193 | int err; | ||
194 | |||
195 | gprs[1] = msr; | ||
196 | gprs[7] = 0x9c5a203a; | ||
197 | |||
198 | err = native_rdmsr_safe_regs(gprs); | ||
199 | |||
200 | *p = gprs[0] | ((u64)gprs[2] << 32); | ||
201 | |||
202 | return err; | ||
203 | } | ||
204 | |||
205 | static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val) | ||
206 | { | ||
207 | u32 gprs[8] = { 0 }; | ||
208 | |||
209 | gprs[0] = (u32)val; | ||
210 | gprs[1] = msr; | ||
211 | gprs[2] = val >> 32; | ||
212 | gprs[7] = 0x9c5a203a; | ||
213 | |||
214 | return native_wrmsr_safe_regs(gprs); | ||
215 | } | ||
216 | |||
217 | static inline int rdmsr_safe_regs(u32 regs[8]) | ||
218 | { | ||
219 | return native_rdmsr_safe_regs(regs); | ||
220 | } | ||
221 | |||
222 | static inline int wrmsr_safe_regs(u32 regs[8]) | ||
223 | { | ||
224 | return native_wrmsr_safe_regs(regs); | ||
225 | } | ||
226 | |||
227 | #define rdtscl(low) \ | 190 | #define rdtscl(low) \ |
228 | ((low) = (u32)__native_read_tsc()) | 191 | ((low) = (u32)__native_read_tsc()) |
229 | 192 | ||
@@ -237,6 +200,8 @@ do { \ | |||
237 | (high) = (u32)(_l >> 32); \ | 200 | (high) = (u32)(_l >> 32); \ |
238 | } while (0) | 201 | } while (0) |
239 | 202 | ||
203 | #define rdpmcl(counter, val) ((val) = native_read_pmc(counter)) | ||
204 | |||
240 | #define rdtscp(low, high, aux) \ | 205 | #define rdtscp(low, high, aux) \ |
241 | do { \ | 206 | do { \ |
242 | unsigned long long _val = native_read_tscp(&(aux)); \ | 207 | unsigned long long _val = native_read_tscp(&(aux)); \ |
@@ -248,8 +213,7 @@ do { \ | |||
248 | 213 | ||
249 | #endif /* !CONFIG_PARAVIRT */ | 214 | #endif /* !CONFIG_PARAVIRT */ |
250 | 215 | ||
251 | 216 | #define wrmsrl_safe(msr, val) wrmsr_safe((msr), (u32)(val), \ | |
252 | #define checking_wrmsrl(msr, val) wrmsr_safe((msr), (u32)(val), \ | ||
253 | (u32)((val) >> 32)) | 217 | (u32)((val) >> 32)) |
254 | 218 | ||
255 | #define write_tsc(val1, val2) wrmsr(MSR_IA32_TSC, (val1), (val2)) | 219 | #define write_tsc(val1, val2) wrmsr(MSR_IA32_TSC, (val1), (val2)) |
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 6cbbabf52707..0b47ddb6f00b 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h | |||
@@ -128,21 +128,11 @@ static inline u64 paravirt_read_msr(unsigned msr, int *err) | |||
128 | return PVOP_CALL2(u64, pv_cpu_ops.read_msr, msr, err); | 128 | return PVOP_CALL2(u64, pv_cpu_ops.read_msr, msr, err); |
129 | } | 129 | } |
130 | 130 | ||
131 | static inline int paravirt_rdmsr_regs(u32 *regs) | ||
132 | { | ||
133 | return PVOP_CALL1(int, pv_cpu_ops.rdmsr_regs, regs); | ||
134 | } | ||
135 | |||
136 | static inline int paravirt_write_msr(unsigned msr, unsigned low, unsigned high) | 131 | static inline int paravirt_write_msr(unsigned msr, unsigned low, unsigned high) |
137 | { | 132 | { |
138 | return PVOP_CALL3(int, pv_cpu_ops.write_msr, msr, low, high); | 133 | return PVOP_CALL3(int, pv_cpu_ops.write_msr, msr, low, high); |
139 | } | 134 | } |
140 | 135 | ||
141 | static inline int paravirt_wrmsr_regs(u32 *regs) | ||
142 | { | ||
143 | return PVOP_CALL1(int, pv_cpu_ops.wrmsr_regs, regs); | ||
144 | } | ||
145 | |||
146 | /* These should all do BUG_ON(_err), but our headers are too tangled. */ | 136 | /* These should all do BUG_ON(_err), but our headers are too tangled. */ |
147 | #define rdmsr(msr, val1, val2) \ | 137 | #define rdmsr(msr, val1, val2) \ |
148 | do { \ | 138 | do { \ |
@@ -176,9 +166,6 @@ do { \ | |||
176 | _err; \ | 166 | _err; \ |
177 | }) | 167 | }) |
178 | 168 | ||
179 | #define rdmsr_safe_regs(regs) paravirt_rdmsr_regs(regs) | ||
180 | #define wrmsr_safe_regs(regs) paravirt_wrmsr_regs(regs) | ||
181 | |||
182 | static inline int rdmsrl_safe(unsigned msr, unsigned long long *p) | 169 | static inline int rdmsrl_safe(unsigned msr, unsigned long long *p) |
183 | { | 170 | { |
184 | int err; | 171 | int err; |
@@ -186,32 +173,6 @@ static inline int rdmsrl_safe(unsigned msr, unsigned long long *p) | |||
186 | *p = paravirt_read_msr(msr, &err); | 173 | *p = paravirt_read_msr(msr, &err); |
187 | return err; | 174 | return err; |
188 | } | 175 | } |
189 | static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p) | ||
190 | { | ||
191 | u32 gprs[8] = { 0 }; | ||
192 | int err; | ||
193 | |||
194 | gprs[1] = msr; | ||
195 | gprs[7] = 0x9c5a203a; | ||
196 | |||
197 | err = paravirt_rdmsr_regs(gprs); | ||
198 | |||
199 | *p = gprs[0] | ((u64)gprs[2] << 32); | ||
200 | |||
201 | return err; | ||
202 | } | ||
203 | |||
204 | static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val) | ||
205 | { | ||
206 | u32 gprs[8] = { 0 }; | ||
207 | |||
208 | gprs[0] = (u32)val; | ||
209 | gprs[1] = msr; | ||
210 | gprs[2] = val >> 32; | ||
211 | gprs[7] = 0x9c5a203a; | ||
212 | |||
213 | return paravirt_wrmsr_regs(gprs); | ||
214 | } | ||
215 | 176 | ||
216 | static inline u64 paravirt_read_tsc(void) | 177 | static inline u64 paravirt_read_tsc(void) |
217 | { | 178 | { |
@@ -252,6 +213,8 @@ do { \ | |||
252 | high = _l >> 32; \ | 213 | high = _l >> 32; \ |
253 | } while (0) | 214 | } while (0) |
254 | 215 | ||
216 | #define rdpmcl(counter, val) ((val) = paravirt_read_pmc(counter)) | ||
217 | |||
255 | static inline unsigned long long paravirt_rdtscp(unsigned int *aux) | 218 | static inline unsigned long long paravirt_rdtscp(unsigned int *aux) |
256 | { | 219 | { |
257 | return PVOP_CALL1(u64, pv_cpu_ops.read_tscp, aux); | 220 | return PVOP_CALL1(u64, pv_cpu_ops.read_tscp, aux); |
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index 8e8b9a4987ee..8613cbb7ba41 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h | |||
@@ -153,9 +153,7 @@ struct pv_cpu_ops { | |||
153 | /* MSR, PMC and TSR operations. | 153 | /* MSR, PMC and TSR operations. |
154 | err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */ | 154 | err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */ |
155 | u64 (*read_msr)(unsigned int msr, int *err); | 155 | u64 (*read_msr)(unsigned int msr, int *err); |
156 | int (*rdmsr_regs)(u32 *regs); | ||
157 | int (*write_msr)(unsigned int msr, unsigned low, unsigned high); | 156 | int (*write_msr)(unsigned int msr, unsigned low, unsigned high); |
158 | int (*wrmsr_regs)(u32 *regs); | ||
159 | 157 | ||
160 | u64 (*read_tsc)(void); | 158 | u64 (*read_tsc)(void); |
161 | u64 (*read_pmc)(int counter); | 159 | u64 (*read_pmc)(int counter); |
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index 588f52ea810e..c78f14a0df00 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h | |||
@@ -5,11 +5,10 @@ | |||
5 | * Performance event hw details: | 5 | * Performance event hw details: |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #define X86_PMC_MAX_GENERIC 32 | 8 | #define INTEL_PMC_MAX_GENERIC 32 |
9 | #define X86_PMC_MAX_FIXED 3 | 9 | #define INTEL_PMC_MAX_FIXED 3 |
10 | #define INTEL_PMC_IDX_FIXED 32 | ||
10 | 11 | ||
11 | #define X86_PMC_IDX_GENERIC 0 | ||
12 | #define X86_PMC_IDX_FIXED 32 | ||
13 | #define X86_PMC_IDX_MAX 64 | 12 | #define X86_PMC_IDX_MAX 64 |
14 | 13 | ||
15 | #define MSR_ARCH_PERFMON_PERFCTR0 0xc1 | 14 | #define MSR_ARCH_PERFMON_PERFCTR0 0xc1 |
@@ -48,8 +47,7 @@ | |||
48 | (X86_RAW_EVENT_MASK | \ | 47 | (X86_RAW_EVENT_MASK | \ |
49 | AMD64_EVENTSEL_EVENT) | 48 | AMD64_EVENTSEL_EVENT) |
50 | #define AMD64_NUM_COUNTERS 4 | 49 | #define AMD64_NUM_COUNTERS 4 |
51 | #define AMD64_NUM_COUNTERS_F15H 6 | 50 | #define AMD64_NUM_COUNTERS_CORE 6 |
52 | #define AMD64_NUM_COUNTERS_MAX AMD64_NUM_COUNTERS_F15H | ||
53 | 51 | ||
54 | #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c | 52 | #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL 0x3c |
55 | #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8) | 53 | #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK (0x00 << 8) |
@@ -121,16 +119,16 @@ struct x86_pmu_capability { | |||
121 | 119 | ||
122 | /* Instr_Retired.Any: */ | 120 | /* Instr_Retired.Any: */ |
123 | #define MSR_ARCH_PERFMON_FIXED_CTR0 0x309 | 121 | #define MSR_ARCH_PERFMON_FIXED_CTR0 0x309 |
124 | #define X86_PMC_IDX_FIXED_INSTRUCTIONS (X86_PMC_IDX_FIXED + 0) | 122 | #define INTEL_PMC_IDX_FIXED_INSTRUCTIONS (INTEL_PMC_IDX_FIXED + 0) |
125 | 123 | ||
126 | /* CPU_CLK_Unhalted.Core: */ | 124 | /* CPU_CLK_Unhalted.Core: */ |
127 | #define MSR_ARCH_PERFMON_FIXED_CTR1 0x30a | 125 | #define MSR_ARCH_PERFMON_FIXED_CTR1 0x30a |
128 | #define X86_PMC_IDX_FIXED_CPU_CYCLES (X86_PMC_IDX_FIXED + 1) | 126 | #define INTEL_PMC_IDX_FIXED_CPU_CYCLES (INTEL_PMC_IDX_FIXED + 1) |
129 | 127 | ||
130 | /* CPU_CLK_Unhalted.Ref: */ | 128 | /* CPU_CLK_Unhalted.Ref: */ |
131 | #define MSR_ARCH_PERFMON_FIXED_CTR2 0x30b | 129 | #define MSR_ARCH_PERFMON_FIXED_CTR2 0x30b |
132 | #define X86_PMC_IDX_FIXED_REF_CYCLES (X86_PMC_IDX_FIXED + 2) | 130 | #define INTEL_PMC_IDX_FIXED_REF_CYCLES (INTEL_PMC_IDX_FIXED + 2) |
133 | #define X86_PMC_MSK_FIXED_REF_CYCLES (1ULL << X86_PMC_IDX_FIXED_REF_CYCLES) | 131 | #define INTEL_PMC_MSK_FIXED_REF_CYCLES (1ULL << INTEL_PMC_IDX_FIXED_REF_CYCLES) |
134 | 132 | ||
135 | /* | 133 | /* |
136 | * We model BTS tracing as another fixed-mode PMC. | 134 | * We model BTS tracing as another fixed-mode PMC. |
@@ -139,7 +137,7 @@ struct x86_pmu_capability { | |||
139 | * values are used by actual fixed events and higher values are used | 137 | * values are used by actual fixed events and higher values are used |
140 | * to indicate other overflow conditions in the PERF_GLOBAL_STATUS msr. | 138 | * to indicate other overflow conditions in the PERF_GLOBAL_STATUS msr. |
141 | */ | 139 | */ |
142 | #define X86_PMC_IDX_FIXED_BTS (X86_PMC_IDX_FIXED + 16) | 140 | #define INTEL_PMC_IDX_FIXED_BTS (INTEL_PMC_IDX_FIXED + 16) |
143 | 141 | ||
144 | /* | 142 | /* |
145 | * IBS cpuid feature detection | 143 | * IBS cpuid feature detection |
@@ -234,6 +232,7 @@ struct perf_guest_switch_msr { | |||
234 | 232 | ||
235 | extern struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr); | 233 | extern struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr); |
236 | extern void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap); | 234 | extern void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap); |
235 | extern void perf_check_microcode(void); | ||
237 | #else | 236 | #else |
238 | static inline perf_guest_switch_msr *perf_guest_get_msrs(int *nr) | 237 | static inline perf_guest_switch_msr *perf_guest_get_msrs(int *nr) |
239 | { | 238 | { |
@@ -247,6 +246,7 @@ static inline void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) | |||
247 | } | 246 | } |
248 | 247 | ||
249 | static inline void perf_events_lapic_init(void) { } | 248 | static inline void perf_events_lapic_init(void) { } |
249 | static inline void perf_check_microcode(void) { } | ||
250 | #endif | 250 | #endif |
251 | 251 | ||
252 | #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD) | 252 | #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD) |
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h index 1e9bed14f7ae..f3971bbcd1de 100644 --- a/arch/x86/include/asm/uprobes.h +++ b/arch/x86/include/asm/uprobes.h | |||
@@ -48,7 +48,7 @@ struct arch_uprobe_task { | |||
48 | #endif | 48 | #endif |
49 | }; | 49 | }; |
50 | 50 | ||
51 | extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm); | 51 | extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); |
52 | extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs); | 52 | extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs); |
53 | extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs); | 53 | extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs); |
54 | extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); | 54 | extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); |
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 6ab6aa2fdfdd..bac4c3804cc7 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile | |||
@@ -32,7 +32,9 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o | |||
32 | 32 | ||
33 | ifdef CONFIG_PERF_EVENTS | 33 | ifdef CONFIG_PERF_EVENTS |
34 | obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o | 34 | obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o |
35 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_p4.o perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o | 35 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_p4.o |
36 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o | ||
37 | obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o | ||
36 | endif | 38 | endif |
37 | 39 | ||
38 | obj-$(CONFIG_X86_MCE) += mcheck/ | 40 | obj-$(CONFIG_X86_MCE) += mcheck/ |
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 146bb6218eec..9d92e19039f0 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c | |||
@@ -19,6 +19,39 @@ | |||
19 | 19 | ||
20 | #include "cpu.h" | 20 | #include "cpu.h" |
21 | 21 | ||
22 | static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p) | ||
23 | { | ||
24 | struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); | ||
25 | u32 gprs[8] = { 0 }; | ||
26 | int err; | ||
27 | |||
28 | WARN_ONCE((c->x86 != 0xf), "%s should only be used on K8!\n", __func__); | ||
29 | |||
30 | gprs[1] = msr; | ||
31 | gprs[7] = 0x9c5a203a; | ||
32 | |||
33 | err = rdmsr_safe_regs(gprs); | ||
34 | |||
35 | *p = gprs[0] | ((u64)gprs[2] << 32); | ||
36 | |||
37 | return err; | ||
38 | } | ||
39 | |||
40 | static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val) | ||
41 | { | ||
42 | struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); | ||
43 | u32 gprs[8] = { 0 }; | ||
44 | |||
45 | WARN_ONCE((c->x86 != 0xf), "%s should only be used on K8!\n", __func__); | ||
46 | |||
47 | gprs[0] = (u32)val; | ||
48 | gprs[1] = msr; | ||
49 | gprs[2] = val >> 32; | ||
50 | gprs[7] = 0x9c5a203a; | ||
51 | |||
52 | return wrmsr_safe_regs(gprs); | ||
53 | } | ||
54 | |||
22 | #ifdef CONFIG_X86_32 | 55 | #ifdef CONFIG_X86_32 |
23 | /* | 56 | /* |
24 | * B step AMD K6 before B 9730xxxx have hardware bugs that can cause | 57 | * B step AMD K6 before B 9730xxxx have hardware bugs that can cause |
@@ -586,9 +619,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) | |||
586 | !cpu_has(c, X86_FEATURE_TOPOEXT)) { | 619 | !cpu_has(c, X86_FEATURE_TOPOEXT)) { |
587 | u64 val; | 620 | u64 val; |
588 | 621 | ||
589 | if (!rdmsrl_amd_safe(0xc0011005, &val)) { | 622 | if (!rdmsrl_safe(0xc0011005, &val)) { |
590 | val |= 1ULL << 54; | 623 | val |= 1ULL << 54; |
591 | wrmsrl_amd_safe(0xc0011005, val); | 624 | wrmsrl_safe(0xc0011005, val); |
592 | rdmsrl(0xc0011005, val); | 625 | rdmsrl(0xc0011005, val); |
593 | if (val & (1ULL << 54)) { | 626 | if (val & (1ULL << 54)) { |
594 | set_cpu_cap(c, X86_FEATURE_TOPOEXT); | 627 | set_cpu_cap(c, X86_FEATURE_TOPOEXT); |
@@ -679,7 +712,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) | |||
679 | err = rdmsrl_safe(MSR_AMD64_MCx_MASK(4), &mask); | 712 | err = rdmsrl_safe(MSR_AMD64_MCx_MASK(4), &mask); |
680 | if (err == 0) { | 713 | if (err == 0) { |
681 | mask |= (1 << 10); | 714 | mask |= (1 << 10); |
682 | checking_wrmsrl(MSR_AMD64_MCx_MASK(4), mask); | 715 | wrmsrl_safe(MSR_AMD64_MCx_MASK(4), mask); |
683 | } | 716 | } |
684 | } | 717 | } |
685 | 718 | ||
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 6b9333b429ba..5bbc082c47ad 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -947,7 +947,7 @@ static void __cpuinit __print_cpu_msr(void) | |||
947 | index_max = msr_range_array[i].max; | 947 | index_max = msr_range_array[i].max; |
948 | 948 | ||
949 | for (index = index_min; index < index_max; index++) { | 949 | for (index = index_min; index < index_max; index++) { |
950 | if (rdmsrl_amd_safe(index, &val)) | 950 | if (rdmsrl_safe(index, &val)) |
951 | continue; | 951 | continue; |
952 | printk(KERN_INFO " MSR%08x: %016llx\n", index, val); | 952 | printk(KERN_INFO " MSR%08x: %016llx\n", index, val); |
953 | } | 953 | } |
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index c4706cf9c011..29557aa06dda 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
@@ -35,17 +35,6 @@ | |||
35 | 35 | ||
36 | #include "perf_event.h" | 36 | #include "perf_event.h" |
37 | 37 | ||
38 | #if 0 | ||
39 | #undef wrmsrl | ||
40 | #define wrmsrl(msr, val) \ | ||
41 | do { \ | ||
42 | trace_printk("wrmsrl(%lx, %lx)\n", (unsigned long)(msr),\ | ||
43 | (unsigned long)(val)); \ | ||
44 | native_write_msr((msr), (u32)((u64)(val)), \ | ||
45 | (u32)((u64)(val) >> 32)); \ | ||
46 | } while (0) | ||
47 | #endif | ||
48 | |||
49 | struct x86_pmu x86_pmu __read_mostly; | 38 | struct x86_pmu x86_pmu __read_mostly; |
50 | 39 | ||
51 | DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { | 40 | DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { |
@@ -74,7 +63,7 @@ u64 x86_perf_event_update(struct perf_event *event) | |||
74 | int idx = hwc->idx; | 63 | int idx = hwc->idx; |
75 | s64 delta; | 64 | s64 delta; |
76 | 65 | ||
77 | if (idx == X86_PMC_IDX_FIXED_BTS) | 66 | if (idx == INTEL_PMC_IDX_FIXED_BTS) |
78 | return 0; | 67 | return 0; |
79 | 68 | ||
80 | /* | 69 | /* |
@@ -86,7 +75,7 @@ u64 x86_perf_event_update(struct perf_event *event) | |||
86 | */ | 75 | */ |
87 | again: | 76 | again: |
88 | prev_raw_count = local64_read(&hwc->prev_count); | 77 | prev_raw_count = local64_read(&hwc->prev_count); |
89 | rdmsrl(hwc->event_base, new_raw_count); | 78 | rdpmcl(hwc->event_base_rdpmc, new_raw_count); |
90 | 79 | ||
91 | if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, | 80 | if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, |
92 | new_raw_count) != prev_raw_count) | 81 | new_raw_count) != prev_raw_count) |
@@ -189,7 +178,7 @@ static void release_pmc_hardware(void) {} | |||
189 | 178 | ||
190 | static bool check_hw_exists(void) | 179 | static bool check_hw_exists(void) |
191 | { | 180 | { |
192 | u64 val, val_new = 0; | 181 | u64 val, val_new = ~0; |
193 | int i, reg, ret = 0; | 182 | int i, reg, ret = 0; |
194 | 183 | ||
195 | /* | 184 | /* |
@@ -222,8 +211,9 @@ static bool check_hw_exists(void) | |||
222 | * that don't trap on the MSR access and always return 0s. | 211 | * that don't trap on the MSR access and always return 0s. |
223 | */ | 212 | */ |
224 | val = 0xabcdUL; | 213 | val = 0xabcdUL; |
225 | ret = checking_wrmsrl(x86_pmu_event_addr(0), val); | 214 | reg = x86_pmu_event_addr(0); |
226 | ret |= rdmsrl_safe(x86_pmu_event_addr(0), &val_new); | 215 | ret = wrmsrl_safe(reg, val); |
216 | ret |= rdmsrl_safe(reg, &val_new); | ||
227 | if (ret || val != val_new) | 217 | if (ret || val != val_new) |
228 | goto msr_fail; | 218 | goto msr_fail; |
229 | 219 | ||
@@ -240,6 +230,7 @@ bios_fail: | |||
240 | 230 | ||
241 | msr_fail: | 231 | msr_fail: |
242 | printk(KERN_CONT "Broken PMU hardware detected, using software events only.\n"); | 232 | printk(KERN_CONT "Broken PMU hardware detected, using software events only.\n"); |
233 | printk(KERN_ERR "Failed to access perfctr msr (MSR %x is %Lx)\n", reg, val_new); | ||
243 | 234 | ||
244 | return false; | 235 | return false; |
245 | } | 236 | } |
@@ -388,7 +379,7 @@ int x86_pmu_hw_config(struct perf_event *event) | |||
388 | int precise = 0; | 379 | int precise = 0; |
389 | 380 | ||
390 | /* Support for constant skid */ | 381 | /* Support for constant skid */ |
391 | if (x86_pmu.pebs_active) { | 382 | if (x86_pmu.pebs_active && !x86_pmu.pebs_broken) { |
392 | precise++; | 383 | precise++; |
393 | 384 | ||
394 | /* Support for IP fixup */ | 385 | /* Support for IP fixup */ |
@@ -637,8 +628,8 @@ static bool __perf_sched_find_counter(struct perf_sched *sched) | |||
637 | c = sched->constraints[sched->state.event]; | 628 | c = sched->constraints[sched->state.event]; |
638 | 629 | ||
639 | /* Prefer fixed purpose counters */ | 630 | /* Prefer fixed purpose counters */ |
640 | if (x86_pmu.num_counters_fixed) { | 631 | if (c->idxmsk64 & (~0ULL << INTEL_PMC_IDX_FIXED)) { |
641 | idx = X86_PMC_IDX_FIXED; | 632 | idx = INTEL_PMC_IDX_FIXED; |
642 | for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_MAX) { | 633 | for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_MAX) { |
643 | if (!__test_and_set_bit(idx, sched->state.used)) | 634 | if (!__test_and_set_bit(idx, sched->state.used)) |
644 | goto done; | 635 | goto done; |
@@ -646,7 +637,7 @@ static bool __perf_sched_find_counter(struct perf_sched *sched) | |||
646 | } | 637 | } |
647 | /* Grab the first unused counter starting with idx */ | 638 | /* Grab the first unused counter starting with idx */ |
648 | idx = sched->state.counter; | 639 | idx = sched->state.counter; |
649 | for_each_set_bit_from(idx, c->idxmsk, X86_PMC_IDX_FIXED) { | 640 | for_each_set_bit_from(idx, c->idxmsk, INTEL_PMC_IDX_FIXED) { |
650 | if (!__test_and_set_bit(idx, sched->state.used)) | 641 | if (!__test_and_set_bit(idx, sched->state.used)) |
651 | goto done; | 642 | goto done; |
652 | } | 643 | } |
@@ -704,8 +695,8 @@ static bool perf_sched_next_event(struct perf_sched *sched) | |||
704 | /* | 695 | /* |
705 | * Assign a counter for each event. | 696 | * Assign a counter for each event. |
706 | */ | 697 | */ |
707 | static int perf_assign_events(struct event_constraint **constraints, int n, | 698 | int perf_assign_events(struct event_constraint **constraints, int n, |
708 | int wmin, int wmax, int *assign) | 699 | int wmin, int wmax, int *assign) |
709 | { | 700 | { |
710 | struct perf_sched sched; | 701 | struct perf_sched sched; |
711 | 702 | ||
@@ -824,15 +815,17 @@ static inline void x86_assign_hw_event(struct perf_event *event, | |||
824 | hwc->last_cpu = smp_processor_id(); | 815 | hwc->last_cpu = smp_processor_id(); |
825 | hwc->last_tag = ++cpuc->tags[i]; | 816 | hwc->last_tag = ++cpuc->tags[i]; |
826 | 817 | ||
827 | if (hwc->idx == X86_PMC_IDX_FIXED_BTS) { | 818 | if (hwc->idx == INTEL_PMC_IDX_FIXED_BTS) { |
828 | hwc->config_base = 0; | 819 | hwc->config_base = 0; |
829 | hwc->event_base = 0; | 820 | hwc->event_base = 0; |
830 | } else if (hwc->idx >= X86_PMC_IDX_FIXED) { | 821 | } else if (hwc->idx >= INTEL_PMC_IDX_FIXED) { |
831 | hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL; | 822 | hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL; |
832 | hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0 + (hwc->idx - X86_PMC_IDX_FIXED); | 823 | hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0 + (hwc->idx - INTEL_PMC_IDX_FIXED); |
824 | hwc->event_base_rdpmc = (hwc->idx - INTEL_PMC_IDX_FIXED) | 1<<30; | ||
833 | } else { | 825 | } else { |
834 | hwc->config_base = x86_pmu_config_addr(hwc->idx); | 826 | hwc->config_base = x86_pmu_config_addr(hwc->idx); |
835 | hwc->event_base = x86_pmu_event_addr(hwc->idx); | 827 | hwc->event_base = x86_pmu_event_addr(hwc->idx); |
828 | hwc->event_base_rdpmc = hwc->idx; | ||
836 | } | 829 | } |
837 | } | 830 | } |
838 | 831 | ||
@@ -930,7 +923,7 @@ int x86_perf_event_set_period(struct perf_event *event) | |||
930 | s64 period = hwc->sample_period; | 923 | s64 period = hwc->sample_period; |
931 | int ret = 0, idx = hwc->idx; | 924 | int ret = 0, idx = hwc->idx; |
932 | 925 | ||
933 | if (idx == X86_PMC_IDX_FIXED_BTS) | 926 | if (idx == INTEL_PMC_IDX_FIXED_BTS) |
934 | return 0; | 927 | return 0; |
935 | 928 | ||
936 | /* | 929 | /* |
@@ -1316,7 +1309,6 @@ static struct attribute_group x86_pmu_format_group = { | |||
1316 | static int __init init_hw_perf_events(void) | 1309 | static int __init init_hw_perf_events(void) |
1317 | { | 1310 | { |
1318 | struct x86_pmu_quirk *quirk; | 1311 | struct x86_pmu_quirk *quirk; |
1319 | struct event_constraint *c; | ||
1320 | int err; | 1312 | int err; |
1321 | 1313 | ||
1322 | pr_info("Performance Events: "); | 1314 | pr_info("Performance Events: "); |
@@ -1347,21 +1339,8 @@ static int __init init_hw_perf_events(void) | |||
1347 | for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next) | 1339 | for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next) |
1348 | quirk->func(); | 1340 | quirk->func(); |
1349 | 1341 | ||
1350 | if (x86_pmu.num_counters > X86_PMC_MAX_GENERIC) { | 1342 | if (!x86_pmu.intel_ctrl) |
1351 | WARN(1, KERN_ERR "hw perf events %d > max(%d), clipping!", | 1343 | x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1; |
1352 | x86_pmu.num_counters, X86_PMC_MAX_GENERIC); | ||
1353 | x86_pmu.num_counters = X86_PMC_MAX_GENERIC; | ||
1354 | } | ||
1355 | x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1; | ||
1356 | |||
1357 | if (x86_pmu.num_counters_fixed > X86_PMC_MAX_FIXED) { | ||
1358 | WARN(1, KERN_ERR "hw perf events fixed %d > max(%d), clipping!", | ||
1359 | x86_pmu.num_counters_fixed, X86_PMC_MAX_FIXED); | ||
1360 | x86_pmu.num_counters_fixed = X86_PMC_MAX_FIXED; | ||
1361 | } | ||
1362 | |||
1363 | x86_pmu.intel_ctrl |= | ||
1364 | ((1LL << x86_pmu.num_counters_fixed)-1) << X86_PMC_IDX_FIXED; | ||
1365 | 1344 | ||
1366 | perf_events_lapic_init(); | 1345 | perf_events_lapic_init(); |
1367 | register_nmi_handler(NMI_LOCAL, perf_event_nmi_handler, 0, "PMI"); | 1346 | register_nmi_handler(NMI_LOCAL, perf_event_nmi_handler, 0, "PMI"); |
@@ -1370,22 +1349,6 @@ static int __init init_hw_perf_events(void) | |||
1370 | __EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1, | 1349 | __EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1, |
1371 | 0, x86_pmu.num_counters, 0); | 1350 | 0, x86_pmu.num_counters, 0); |
1372 | 1351 | ||
1373 | if (x86_pmu.event_constraints) { | ||
1374 | /* | ||
1375 | * event on fixed counter2 (REF_CYCLES) only works on this | ||
1376 | * counter, so do not extend mask to generic counters | ||
1377 | */ | ||
1378 | for_each_event_constraint(c, x86_pmu.event_constraints) { | ||
1379 | if (c->cmask != X86_RAW_EVENT_MASK | ||
1380 | || c->idxmsk64 == X86_PMC_MSK_FIXED_REF_CYCLES) { | ||
1381 | continue; | ||
1382 | } | ||
1383 | |||
1384 | c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1; | ||
1385 | c->weight += x86_pmu.num_counters; | ||
1386 | } | ||
1387 | } | ||
1388 | |||
1389 | x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */ | 1352 | x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */ |
1390 | x86_pmu_format_group.attrs = x86_pmu.format_attrs; | 1353 | x86_pmu_format_group.attrs = x86_pmu.format_attrs; |
1391 | 1354 | ||
@@ -1620,8 +1583,8 @@ static int x86_pmu_event_idx(struct perf_event *event) | |||
1620 | if (!x86_pmu.attr_rdpmc) | 1583 | if (!x86_pmu.attr_rdpmc) |
1621 | return 0; | 1584 | return 0; |
1622 | 1585 | ||
1623 | if (x86_pmu.num_counters_fixed && idx >= X86_PMC_IDX_FIXED) { | 1586 | if (x86_pmu.num_counters_fixed && idx >= INTEL_PMC_IDX_FIXED) { |
1624 | idx -= X86_PMC_IDX_FIXED; | 1587 | idx -= INTEL_PMC_IDX_FIXED; |
1625 | idx |= 1 << 30; | 1588 | idx |= 1 << 30; |
1626 | } | 1589 | } |
1627 | 1590 | ||
@@ -1649,7 +1612,12 @@ static ssize_t set_attr_rdpmc(struct device *cdev, | |||
1649 | struct device_attribute *attr, | 1612 | struct device_attribute *attr, |
1650 | const char *buf, size_t count) | 1613 | const char *buf, size_t count) |
1651 | { | 1614 | { |
1652 | unsigned long val = simple_strtoul(buf, NULL, 0); | 1615 | unsigned long val; |
1616 | ssize_t ret; | ||
1617 | |||
1618 | ret = kstrtoul(buf, 0, &val); | ||
1619 | if (ret) | ||
1620 | return ret; | ||
1653 | 1621 | ||
1654 | if (!!val != !!x86_pmu.attr_rdpmc) { | 1622 | if (!!val != !!x86_pmu.attr_rdpmc) { |
1655 | x86_pmu.attr_rdpmc = !!val; | 1623 | x86_pmu.attr_rdpmc = !!val; |
@@ -1682,13 +1650,20 @@ static void x86_pmu_flush_branch_stack(void) | |||
1682 | x86_pmu.flush_branch_stack(); | 1650 | x86_pmu.flush_branch_stack(); |
1683 | } | 1651 | } |
1684 | 1652 | ||
1653 | void perf_check_microcode(void) | ||
1654 | { | ||
1655 | if (x86_pmu.check_microcode) | ||
1656 | x86_pmu.check_microcode(); | ||
1657 | } | ||
1658 | EXPORT_SYMBOL_GPL(perf_check_microcode); | ||
1659 | |||
1685 | static struct pmu pmu = { | 1660 | static struct pmu pmu = { |
1686 | .pmu_enable = x86_pmu_enable, | 1661 | .pmu_enable = x86_pmu_enable, |
1687 | .pmu_disable = x86_pmu_disable, | 1662 | .pmu_disable = x86_pmu_disable, |
1688 | 1663 | ||
1689 | .attr_groups = x86_pmu_attr_groups, | 1664 | .attr_groups = x86_pmu_attr_groups, |
1690 | 1665 | ||
1691 | .event_init = x86_pmu_event_init, | 1666 | .event_init = x86_pmu_event_init, |
1692 | 1667 | ||
1693 | .add = x86_pmu_add, | 1668 | .add = x86_pmu_add, |
1694 | .del = x86_pmu_del, | 1669 | .del = x86_pmu_del, |
@@ -1696,11 +1671,11 @@ static struct pmu pmu = { | |||
1696 | .stop = x86_pmu_stop, | 1671 | .stop = x86_pmu_stop, |
1697 | .read = x86_pmu_read, | 1672 | .read = x86_pmu_read, |
1698 | 1673 | ||
1699 | .start_txn = x86_pmu_start_txn, | 1674 | .start_txn = x86_pmu_start_txn, |
1700 | .cancel_txn = x86_pmu_cancel_txn, | 1675 | .cancel_txn = x86_pmu_cancel_txn, |
1701 | .commit_txn = x86_pmu_commit_txn, | 1676 | .commit_txn = x86_pmu_commit_txn, |
1702 | 1677 | ||
1703 | .event_idx = x86_pmu_event_idx, | 1678 | .event_idx = x86_pmu_event_idx, |
1704 | .flush_branch_stack = x86_pmu_flush_branch_stack, | 1679 | .flush_branch_stack = x86_pmu_flush_branch_stack, |
1705 | }; | 1680 | }; |
1706 | 1681 | ||
@@ -1863,7 +1838,7 @@ unsigned long perf_misc_flags(struct pt_regs *regs) | |||
1863 | else | 1838 | else |
1864 | misc |= PERF_RECORD_MISC_GUEST_KERNEL; | 1839 | misc |= PERF_RECORD_MISC_GUEST_KERNEL; |
1865 | } else { | 1840 | } else { |
1866 | if (user_mode(regs)) | 1841 | if (!kernel_ip(regs->ip)) |
1867 | misc |= PERF_RECORD_MISC_USER; | 1842 | misc |= PERF_RECORD_MISC_USER; |
1868 | else | 1843 | else |
1869 | misc |= PERF_RECORD_MISC_KERNEL; | 1844 | misc |= PERF_RECORD_MISC_KERNEL; |
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 7241e2fc3c17..a15df4be151f 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h | |||
@@ -14,6 +14,18 @@ | |||
14 | 14 | ||
15 | #include <linux/perf_event.h> | 15 | #include <linux/perf_event.h> |
16 | 16 | ||
17 | #if 0 | ||
18 | #undef wrmsrl | ||
19 | #define wrmsrl(msr, val) \ | ||
20 | do { \ | ||
21 | unsigned int _msr = (msr); \ | ||
22 | u64 _val = (val); \ | ||
23 | trace_printk("wrmsrl(%x, %Lx)\n", (unsigned int)(_msr), \ | ||
24 | (unsigned long long)(_val)); \ | ||
25 | native_write_msr((_msr), (u32)(_val), (u32)(_val >> 32)); \ | ||
26 | } while (0) | ||
27 | #endif | ||
28 | |||
17 | /* | 29 | /* |
18 | * | NHM/WSM | SNB | | 30 | * | NHM/WSM | SNB | |
19 | * register ------------------------------- | 31 | * register ------------------------------- |
@@ -57,7 +69,7 @@ struct amd_nb { | |||
57 | }; | 69 | }; |
58 | 70 | ||
59 | /* The maximal number of PEBS events: */ | 71 | /* The maximal number of PEBS events: */ |
60 | #define MAX_PEBS_EVENTS 4 | 72 | #define MAX_PEBS_EVENTS 8 |
61 | 73 | ||
62 | /* | 74 | /* |
63 | * A debug store configuration. | 75 | * A debug store configuration. |
@@ -349,6 +361,8 @@ struct x86_pmu { | |||
349 | void (*cpu_starting)(int cpu); | 361 | void (*cpu_starting)(int cpu); |
350 | void (*cpu_dying)(int cpu); | 362 | void (*cpu_dying)(int cpu); |
351 | void (*cpu_dead)(int cpu); | 363 | void (*cpu_dead)(int cpu); |
364 | |||
365 | void (*check_microcode)(void); | ||
352 | void (*flush_branch_stack)(void); | 366 | void (*flush_branch_stack)(void); |
353 | 367 | ||
354 | /* | 368 | /* |
@@ -360,12 +374,16 @@ struct x86_pmu { | |||
360 | /* | 374 | /* |
361 | * Intel DebugStore bits | 375 | * Intel DebugStore bits |
362 | */ | 376 | */ |
363 | int bts, pebs; | 377 | int bts :1, |
364 | int bts_active, pebs_active; | 378 | bts_active :1, |
379 | pebs :1, | ||
380 | pebs_active :1, | ||
381 | pebs_broken :1; | ||
365 | int pebs_record_size; | 382 | int pebs_record_size; |
366 | void (*drain_pebs)(struct pt_regs *regs); | 383 | void (*drain_pebs)(struct pt_regs *regs); |
367 | struct event_constraint *pebs_constraints; | 384 | struct event_constraint *pebs_constraints; |
368 | void (*pebs_aliases)(struct perf_event *event); | 385 | void (*pebs_aliases)(struct perf_event *event); |
386 | int max_pebs_events; | ||
369 | 387 | ||
370 | /* | 388 | /* |
371 | * Intel LBR | 389 | * Intel LBR |
@@ -468,6 +486,8 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc, | |||
468 | 486 | ||
469 | void x86_pmu_enable_all(int added); | 487 | void x86_pmu_enable_all(int added); |
470 | 488 | ||
489 | int perf_assign_events(struct event_constraint **constraints, int n, | ||
490 | int wmin, int wmax, int *assign); | ||
471 | int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign); | 491 | int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign); |
472 | 492 | ||
473 | void x86_pmu_stop(struct perf_event *event, int flags); | 493 | void x86_pmu_stop(struct perf_event *event, int flags); |
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index 11a4eb9131d5..4528ae7b6ec4 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c | |||
@@ -366,7 +366,7 @@ static void amd_pmu_cpu_starting(int cpu) | |||
366 | 366 | ||
367 | cpuc->perf_ctr_virt_mask = AMD_PERFMON_EVENTSEL_HOSTONLY; | 367 | cpuc->perf_ctr_virt_mask = AMD_PERFMON_EVENTSEL_HOSTONLY; |
368 | 368 | ||
369 | if (boot_cpu_data.x86_max_cores < 2 || boot_cpu_data.x86 == 0x15) | 369 | if (boot_cpu_data.x86_max_cores < 2) |
370 | return; | 370 | return; |
371 | 371 | ||
372 | nb_id = amd_get_nb_id(cpu); | 372 | nb_id = amd_get_nb_id(cpu); |
@@ -422,35 +422,6 @@ static struct attribute *amd_format_attr[] = { | |||
422 | NULL, | 422 | NULL, |
423 | }; | 423 | }; |
424 | 424 | ||
425 | static __initconst const struct x86_pmu amd_pmu = { | ||
426 | .name = "AMD", | ||
427 | .handle_irq = x86_pmu_handle_irq, | ||
428 | .disable_all = x86_pmu_disable_all, | ||
429 | .enable_all = x86_pmu_enable_all, | ||
430 | .enable = x86_pmu_enable_event, | ||
431 | .disable = x86_pmu_disable_event, | ||
432 | .hw_config = amd_pmu_hw_config, | ||
433 | .schedule_events = x86_schedule_events, | ||
434 | .eventsel = MSR_K7_EVNTSEL0, | ||
435 | .perfctr = MSR_K7_PERFCTR0, | ||
436 | .event_map = amd_pmu_event_map, | ||
437 | .max_events = ARRAY_SIZE(amd_perfmon_event_map), | ||
438 | .num_counters = AMD64_NUM_COUNTERS, | ||
439 | .cntval_bits = 48, | ||
440 | .cntval_mask = (1ULL << 48) - 1, | ||
441 | .apic = 1, | ||
442 | /* use highest bit to detect overflow */ | ||
443 | .max_period = (1ULL << 47) - 1, | ||
444 | .get_event_constraints = amd_get_event_constraints, | ||
445 | .put_event_constraints = amd_put_event_constraints, | ||
446 | |||
447 | .format_attrs = amd_format_attr, | ||
448 | |||
449 | .cpu_prepare = amd_pmu_cpu_prepare, | ||
450 | .cpu_starting = amd_pmu_cpu_starting, | ||
451 | .cpu_dead = amd_pmu_cpu_dead, | ||
452 | }; | ||
453 | |||
454 | /* AMD Family 15h */ | 425 | /* AMD Family 15h */ |
455 | 426 | ||
456 | #define AMD_EVENT_TYPE_MASK 0x000000F0ULL | 427 | #define AMD_EVENT_TYPE_MASK 0x000000F0ULL |
@@ -597,8 +568,8 @@ amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *ev | |||
597 | } | 568 | } |
598 | } | 569 | } |
599 | 570 | ||
600 | static __initconst const struct x86_pmu amd_pmu_f15h = { | 571 | static __initconst const struct x86_pmu amd_pmu = { |
601 | .name = "AMD Family 15h", | 572 | .name = "AMD", |
602 | .handle_irq = x86_pmu_handle_irq, | 573 | .handle_irq = x86_pmu_handle_irq, |
603 | .disable_all = x86_pmu_disable_all, | 574 | .disable_all = x86_pmu_disable_all, |
604 | .enable_all = x86_pmu_enable_all, | 575 | .enable_all = x86_pmu_enable_all, |
@@ -606,50 +577,68 @@ static __initconst const struct x86_pmu amd_pmu_f15h = { | |||
606 | .disable = x86_pmu_disable_event, | 577 | .disable = x86_pmu_disable_event, |
607 | .hw_config = amd_pmu_hw_config, | 578 | .hw_config = amd_pmu_hw_config, |
608 | .schedule_events = x86_schedule_events, | 579 | .schedule_events = x86_schedule_events, |
609 | .eventsel = MSR_F15H_PERF_CTL, | 580 | .eventsel = MSR_K7_EVNTSEL0, |
610 | .perfctr = MSR_F15H_PERF_CTR, | 581 | .perfctr = MSR_K7_PERFCTR0, |
611 | .event_map = amd_pmu_event_map, | 582 | .event_map = amd_pmu_event_map, |
612 | .max_events = ARRAY_SIZE(amd_perfmon_event_map), | 583 | .max_events = ARRAY_SIZE(amd_perfmon_event_map), |
613 | .num_counters = AMD64_NUM_COUNTERS_F15H, | 584 | .num_counters = AMD64_NUM_COUNTERS, |
614 | .cntval_bits = 48, | 585 | .cntval_bits = 48, |
615 | .cntval_mask = (1ULL << 48) - 1, | 586 | .cntval_mask = (1ULL << 48) - 1, |
616 | .apic = 1, | 587 | .apic = 1, |
617 | /* use highest bit to detect overflow */ | 588 | /* use highest bit to detect overflow */ |
618 | .max_period = (1ULL << 47) - 1, | 589 | .max_period = (1ULL << 47) - 1, |
619 | .get_event_constraints = amd_get_event_constraints_f15h, | 590 | .get_event_constraints = amd_get_event_constraints, |
620 | /* nortbridge counters not yet implemented: */ | ||
621 | #if 0 | ||
622 | .put_event_constraints = amd_put_event_constraints, | 591 | .put_event_constraints = amd_put_event_constraints, |
623 | 592 | ||
593 | .format_attrs = amd_format_attr, | ||
594 | |||
624 | .cpu_prepare = amd_pmu_cpu_prepare, | 595 | .cpu_prepare = amd_pmu_cpu_prepare, |
625 | .cpu_dead = amd_pmu_cpu_dead, | ||
626 | #endif | ||
627 | .cpu_starting = amd_pmu_cpu_starting, | 596 | .cpu_starting = amd_pmu_cpu_starting, |
628 | .format_attrs = amd_format_attr, | 597 | .cpu_dead = amd_pmu_cpu_dead, |
629 | }; | 598 | }; |
630 | 599 | ||
600 | static int setup_event_constraints(void) | ||
601 | { | ||
602 | if (boot_cpu_data.x86 >= 0x15) | ||
603 | x86_pmu.get_event_constraints = amd_get_event_constraints_f15h; | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | static int setup_perfctr_core(void) | ||
608 | { | ||
609 | if (!cpu_has_perfctr_core) { | ||
610 | WARN(x86_pmu.get_event_constraints == amd_get_event_constraints_f15h, | ||
611 | KERN_ERR "Odd, counter constraints enabled but no core perfctrs detected!"); | ||
612 | return -ENODEV; | ||
613 | } | ||
614 | |||
615 | WARN(x86_pmu.get_event_constraints == amd_get_event_constraints, | ||
616 | KERN_ERR "hw perf events core counters need constraints handler!"); | ||
617 | |||
618 | /* | ||
619 | * If core performance counter extensions exists, we must use | ||
620 | * MSR_F15H_PERF_CTL/MSR_F15H_PERF_CTR msrs. See also | ||
621 | * x86_pmu_addr_offset(). | ||
622 | */ | ||
623 | x86_pmu.eventsel = MSR_F15H_PERF_CTL; | ||
624 | x86_pmu.perfctr = MSR_F15H_PERF_CTR; | ||
625 | x86_pmu.num_counters = AMD64_NUM_COUNTERS_CORE; | ||
626 | |||
627 | printk(KERN_INFO "perf: AMD core performance counters detected\n"); | ||
628 | |||
629 | return 0; | ||
630 | } | ||
631 | |||
631 | __init int amd_pmu_init(void) | 632 | __init int amd_pmu_init(void) |
632 | { | 633 | { |
633 | /* Performance-monitoring supported from K7 and later: */ | 634 | /* Performance-monitoring supported from K7 and later: */ |
634 | if (boot_cpu_data.x86 < 6) | 635 | if (boot_cpu_data.x86 < 6) |
635 | return -ENODEV; | 636 | return -ENODEV; |
636 | 637 | ||
637 | /* | 638 | x86_pmu = amd_pmu; |
638 | * If core performance counter extensions exists, it must be | 639 | |
639 | * family 15h, otherwise fail. See x86_pmu_addr_offset(). | 640 | setup_event_constraints(); |
640 | */ | 641 | setup_perfctr_core(); |
641 | switch (boot_cpu_data.x86) { | ||
642 | case 0x15: | ||
643 | if (!cpu_has_perfctr_core) | ||
644 | return -ENODEV; | ||
645 | x86_pmu = amd_pmu_f15h; | ||
646 | break; | ||
647 | default: | ||
648 | if (cpu_has_perfctr_core) | ||
649 | return -ENODEV; | ||
650 | x86_pmu = amd_pmu; | ||
651 | break; | ||
652 | } | ||
653 | 642 | ||
654 | /* Events are common for all AMDs */ | 643 | /* Events are common for all AMDs */ |
655 | memcpy(hw_cache_event_ids, amd_hw_cache_event_ids, | 644 | memcpy(hw_cache_event_ids, amd_hw_cache_event_ids, |
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 187c294bc658..1f4c8add6759 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c | |||
@@ -21,14 +21,14 @@ | |||
21 | */ | 21 | */ |
22 | static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly = | 22 | static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly = |
23 | { | 23 | { |
24 | [PERF_COUNT_HW_CPU_CYCLES] = 0x003c, | 24 | [PERF_COUNT_HW_CPU_CYCLES] = 0x003c, |
25 | [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, | 25 | [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0, |
26 | [PERF_COUNT_HW_CACHE_REFERENCES] = 0x4f2e, | 26 | [PERF_COUNT_HW_CACHE_REFERENCES] = 0x4f2e, |
27 | [PERF_COUNT_HW_CACHE_MISSES] = 0x412e, | 27 | [PERF_COUNT_HW_CACHE_MISSES] = 0x412e, |
28 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c4, | 28 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c4, |
29 | [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c5, | 29 | [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c5, |
30 | [PERF_COUNT_HW_BUS_CYCLES] = 0x013c, | 30 | [PERF_COUNT_HW_BUS_CYCLES] = 0x013c, |
31 | [PERF_COUNT_HW_REF_CPU_CYCLES] = 0x0300, /* pseudo-encoding */ | 31 | [PERF_COUNT_HW_REF_CPU_CYCLES] = 0x0300, /* pseudo-encoding */ |
32 | }; | 32 | }; |
33 | 33 | ||
34 | static struct event_constraint intel_core_event_constraints[] __read_mostly = | 34 | static struct event_constraint intel_core_event_constraints[] __read_mostly = |
@@ -747,7 +747,7 @@ static void intel_pmu_disable_all(void) | |||
747 | 747 | ||
748 | wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0); | 748 | wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0); |
749 | 749 | ||
750 | if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask)) | 750 | if (test_bit(INTEL_PMC_IDX_FIXED_BTS, cpuc->active_mask)) |
751 | intel_pmu_disable_bts(); | 751 | intel_pmu_disable_bts(); |
752 | 752 | ||
753 | intel_pmu_pebs_disable_all(); | 753 | intel_pmu_pebs_disable_all(); |
@@ -763,9 +763,9 @@ static void intel_pmu_enable_all(int added) | |||
763 | wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, | 763 | wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, |
764 | x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_guest_mask); | 764 | x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_guest_mask); |
765 | 765 | ||
766 | if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask)) { | 766 | if (test_bit(INTEL_PMC_IDX_FIXED_BTS, cpuc->active_mask)) { |
767 | struct perf_event *event = | 767 | struct perf_event *event = |
768 | cpuc->events[X86_PMC_IDX_FIXED_BTS]; | 768 | cpuc->events[INTEL_PMC_IDX_FIXED_BTS]; |
769 | 769 | ||
770 | if (WARN_ON_ONCE(!event)) | 770 | if (WARN_ON_ONCE(!event)) |
771 | return; | 771 | return; |
@@ -871,7 +871,7 @@ static inline void intel_pmu_ack_status(u64 ack) | |||
871 | 871 | ||
872 | static void intel_pmu_disable_fixed(struct hw_perf_event *hwc) | 872 | static void intel_pmu_disable_fixed(struct hw_perf_event *hwc) |
873 | { | 873 | { |
874 | int idx = hwc->idx - X86_PMC_IDX_FIXED; | 874 | int idx = hwc->idx - INTEL_PMC_IDX_FIXED; |
875 | u64 ctrl_val, mask; | 875 | u64 ctrl_val, mask; |
876 | 876 | ||
877 | mask = 0xfULL << (idx * 4); | 877 | mask = 0xfULL << (idx * 4); |
@@ -886,7 +886,7 @@ static void intel_pmu_disable_event(struct perf_event *event) | |||
886 | struct hw_perf_event *hwc = &event->hw; | 886 | struct hw_perf_event *hwc = &event->hw; |
887 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 887 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
888 | 888 | ||
889 | if (unlikely(hwc->idx == X86_PMC_IDX_FIXED_BTS)) { | 889 | if (unlikely(hwc->idx == INTEL_PMC_IDX_FIXED_BTS)) { |
890 | intel_pmu_disable_bts(); | 890 | intel_pmu_disable_bts(); |
891 | intel_pmu_drain_bts_buffer(); | 891 | intel_pmu_drain_bts_buffer(); |
892 | return; | 892 | return; |
@@ -915,7 +915,7 @@ static void intel_pmu_disable_event(struct perf_event *event) | |||
915 | 915 | ||
916 | static void intel_pmu_enable_fixed(struct hw_perf_event *hwc) | 916 | static void intel_pmu_enable_fixed(struct hw_perf_event *hwc) |
917 | { | 917 | { |
918 | int idx = hwc->idx - X86_PMC_IDX_FIXED; | 918 | int idx = hwc->idx - INTEL_PMC_IDX_FIXED; |
919 | u64 ctrl_val, bits, mask; | 919 | u64 ctrl_val, bits, mask; |
920 | 920 | ||
921 | /* | 921 | /* |
@@ -949,7 +949,7 @@ static void intel_pmu_enable_event(struct perf_event *event) | |||
949 | struct hw_perf_event *hwc = &event->hw; | 949 | struct hw_perf_event *hwc = &event->hw; |
950 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 950 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
951 | 951 | ||
952 | if (unlikely(hwc->idx == X86_PMC_IDX_FIXED_BTS)) { | 952 | if (unlikely(hwc->idx == INTEL_PMC_IDX_FIXED_BTS)) { |
953 | if (!__this_cpu_read(cpu_hw_events.enabled)) | 953 | if (!__this_cpu_read(cpu_hw_events.enabled)) |
954 | return; | 954 | return; |
955 | 955 | ||
@@ -1003,11 +1003,11 @@ static void intel_pmu_reset(void) | |||
1003 | printk("clearing PMU state on CPU#%d\n", smp_processor_id()); | 1003 | printk("clearing PMU state on CPU#%d\n", smp_processor_id()); |
1004 | 1004 | ||
1005 | for (idx = 0; idx < x86_pmu.num_counters; idx++) { | 1005 | for (idx = 0; idx < x86_pmu.num_counters; idx++) { |
1006 | checking_wrmsrl(x86_pmu_config_addr(idx), 0ull); | 1006 | wrmsrl_safe(x86_pmu_config_addr(idx), 0ull); |
1007 | checking_wrmsrl(x86_pmu_event_addr(idx), 0ull); | 1007 | wrmsrl_safe(x86_pmu_event_addr(idx), 0ull); |
1008 | } | 1008 | } |
1009 | for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) | 1009 | for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) |
1010 | checking_wrmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull); | 1010 | wrmsrl_safe(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull); |
1011 | 1011 | ||
1012 | if (ds) | 1012 | if (ds) |
1013 | ds->bts_index = ds->bts_buffer_base; | 1013 | ds->bts_index = ds->bts_buffer_base; |
@@ -1712,11 +1712,56 @@ static __init void intel_clovertown_quirk(void) | |||
1712 | x86_pmu.pebs_constraints = NULL; | 1712 | x86_pmu.pebs_constraints = NULL; |
1713 | } | 1713 | } |
1714 | 1714 | ||
1715 | static int intel_snb_pebs_broken(int cpu) | ||
1716 | { | ||
1717 | u32 rev = UINT_MAX; /* default to broken for unknown models */ | ||
1718 | |||
1719 | switch (cpu_data(cpu).x86_model) { | ||
1720 | case 42: /* SNB */ | ||
1721 | rev = 0x28; | ||
1722 | break; | ||
1723 | |||
1724 | case 45: /* SNB-EP */ | ||
1725 | switch (cpu_data(cpu).x86_mask) { | ||
1726 | case 6: rev = 0x618; break; | ||
1727 | case 7: rev = 0x70c; break; | ||
1728 | } | ||
1729 | } | ||
1730 | |||
1731 | return (cpu_data(cpu).microcode < rev); | ||
1732 | } | ||
1733 | |||
1734 | static void intel_snb_check_microcode(void) | ||
1735 | { | ||
1736 | int pebs_broken = 0; | ||
1737 | int cpu; | ||
1738 | |||
1739 | get_online_cpus(); | ||
1740 | for_each_online_cpu(cpu) { | ||
1741 | if ((pebs_broken = intel_snb_pebs_broken(cpu))) | ||
1742 | break; | ||
1743 | } | ||
1744 | put_online_cpus(); | ||
1745 | |||
1746 | if (pebs_broken == x86_pmu.pebs_broken) | ||
1747 | return; | ||
1748 | |||
1749 | /* | ||
1750 | * Serialized by the microcode lock.. | ||
1751 | */ | ||
1752 | if (x86_pmu.pebs_broken) { | ||
1753 | pr_info("PEBS enabled due to microcode update\n"); | ||
1754 | x86_pmu.pebs_broken = 0; | ||
1755 | } else { | ||
1756 | pr_info("PEBS disabled due to CPU errata, please upgrade microcode\n"); | ||
1757 | x86_pmu.pebs_broken = 1; | ||
1758 | } | ||
1759 | } | ||
1760 | |||
1715 | static __init void intel_sandybridge_quirk(void) | 1761 | static __init void intel_sandybridge_quirk(void) |
1716 | { | 1762 | { |
1717 | printk(KERN_WARNING "PEBS disabled due to CPU errata.\n"); | 1763 | x86_pmu.check_microcode = intel_snb_check_microcode; |
1718 | x86_pmu.pebs = 0; | 1764 | intel_snb_check_microcode(); |
1719 | x86_pmu.pebs_constraints = NULL; | ||
1720 | } | 1765 | } |
1721 | 1766 | ||
1722 | static const struct { int id; char *name; } intel_arch_events_map[] __initconst = { | 1767 | static const struct { int id; char *name; } intel_arch_events_map[] __initconst = { |
@@ -1765,6 +1810,7 @@ __init int intel_pmu_init(void) | |||
1765 | union cpuid10_edx edx; | 1810 | union cpuid10_edx edx; |
1766 | union cpuid10_eax eax; | 1811 | union cpuid10_eax eax; |
1767 | union cpuid10_ebx ebx; | 1812 | union cpuid10_ebx ebx; |
1813 | struct event_constraint *c; | ||
1768 | unsigned int unused; | 1814 | unsigned int unused; |
1769 | int version; | 1815 | int version; |
1770 | 1816 | ||
@@ -1800,6 +1846,8 @@ __init int intel_pmu_init(void) | |||
1800 | x86_pmu.events_maskl = ebx.full; | 1846 | x86_pmu.events_maskl = ebx.full; |
1801 | x86_pmu.events_mask_len = eax.split.mask_length; | 1847 | x86_pmu.events_mask_len = eax.split.mask_length; |
1802 | 1848 | ||
1849 | x86_pmu.max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, x86_pmu.num_counters); | ||
1850 | |||
1803 | /* | 1851 | /* |
1804 | * Quirk: v2 perfmon does not report fixed-purpose events, so | 1852 | * Quirk: v2 perfmon does not report fixed-purpose events, so |
1805 | * assume at least 3 events: | 1853 | * assume at least 3 events: |
@@ -1951,5 +1999,37 @@ __init int intel_pmu_init(void) | |||
1951 | } | 1999 | } |
1952 | } | 2000 | } |
1953 | 2001 | ||
2002 | if (x86_pmu.num_counters > INTEL_PMC_MAX_GENERIC) { | ||
2003 | WARN(1, KERN_ERR "hw perf events %d > max(%d), clipping!", | ||
2004 | x86_pmu.num_counters, INTEL_PMC_MAX_GENERIC); | ||
2005 | x86_pmu.num_counters = INTEL_PMC_MAX_GENERIC; | ||
2006 | } | ||
2007 | x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1; | ||
2008 | |||
2009 | if (x86_pmu.num_counters_fixed > INTEL_PMC_MAX_FIXED) { | ||
2010 | WARN(1, KERN_ERR "hw perf events fixed %d > max(%d), clipping!", | ||
2011 | x86_pmu.num_counters_fixed, INTEL_PMC_MAX_FIXED); | ||
2012 | x86_pmu.num_counters_fixed = INTEL_PMC_MAX_FIXED; | ||
2013 | } | ||
2014 | |||
2015 | x86_pmu.intel_ctrl |= | ||
2016 | ((1LL << x86_pmu.num_counters_fixed)-1) << INTEL_PMC_IDX_FIXED; | ||
2017 | |||
2018 | if (x86_pmu.event_constraints) { | ||
2019 | /* | ||
2020 | * event on fixed counter2 (REF_CYCLES) only works on this | ||
2021 | * counter, so do not extend mask to generic counters | ||
2022 | */ | ||
2023 | for_each_event_constraint(c, x86_pmu.event_constraints) { | ||
2024 | if (c->cmask != X86_RAW_EVENT_MASK | ||
2025 | || c->idxmsk64 == INTEL_PMC_MSK_FIXED_REF_CYCLES) { | ||
2026 | continue; | ||
2027 | } | ||
2028 | |||
2029 | c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1; | ||
2030 | c->weight += x86_pmu.num_counters; | ||
2031 | } | ||
2032 | } | ||
2033 | |||
1954 | return 0; | 2034 | return 0; |
1955 | } | 2035 | } |
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 35e2192df9f4..629ae0b7ad90 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c | |||
@@ -248,7 +248,7 @@ void reserve_ds_buffers(void) | |||
248 | */ | 248 | */ |
249 | 249 | ||
250 | struct event_constraint bts_constraint = | 250 | struct event_constraint bts_constraint = |
251 | EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_FIXED_BTS, 0); | 251 | EVENT_CONSTRAINT(0, 1ULL << INTEL_PMC_IDX_FIXED_BTS, 0); |
252 | 252 | ||
253 | void intel_pmu_enable_bts(u64 config) | 253 | void intel_pmu_enable_bts(u64 config) |
254 | { | 254 | { |
@@ -295,7 +295,7 @@ int intel_pmu_drain_bts_buffer(void) | |||
295 | u64 to; | 295 | u64 to; |
296 | u64 flags; | 296 | u64 flags; |
297 | }; | 297 | }; |
298 | struct perf_event *event = cpuc->events[X86_PMC_IDX_FIXED_BTS]; | 298 | struct perf_event *event = cpuc->events[INTEL_PMC_IDX_FIXED_BTS]; |
299 | struct bts_record *at, *top; | 299 | struct bts_record *at, *top; |
300 | struct perf_output_handle handle; | 300 | struct perf_output_handle handle; |
301 | struct perf_event_header header; | 301 | struct perf_event_header header; |
@@ -620,7 +620,7 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs) | |||
620 | * Should not happen, we program the threshold at 1 and do not | 620 | * Should not happen, we program the threshold at 1 and do not |
621 | * set a reset value. | 621 | * set a reset value. |
622 | */ | 622 | */ |
623 | WARN_ON_ONCE(n > 1); | 623 | WARN_ONCE(n > 1, "bad leftover pebs %d\n", n); |
624 | at += n - 1; | 624 | at += n - 1; |
625 | 625 | ||
626 | __intel_pmu_pebs_event(event, iregs, at); | 626 | __intel_pmu_pebs_event(event, iregs, at); |
@@ -651,10 +651,10 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) | |||
651 | * Should not happen, we program the threshold at 1 and do not | 651 | * Should not happen, we program the threshold at 1 and do not |
652 | * set a reset value. | 652 | * set a reset value. |
653 | */ | 653 | */ |
654 | WARN_ON_ONCE(n > MAX_PEBS_EVENTS); | 654 | WARN_ONCE(n > x86_pmu.max_pebs_events, "Unexpected number of pebs records %d\n", n); |
655 | 655 | ||
656 | for ( ; at < top; at++) { | 656 | for ( ; at < top; at++) { |
657 | for_each_set_bit(bit, (unsigned long *)&at->status, MAX_PEBS_EVENTS) { | 657 | for_each_set_bit(bit, (unsigned long *)&at->status, x86_pmu.max_pebs_events) { |
658 | event = cpuc->events[bit]; | 658 | event = cpuc->events[bit]; |
659 | if (!test_bit(bit, cpuc->active_mask)) | 659 | if (!test_bit(bit, cpuc->active_mask)) |
660 | continue; | 660 | continue; |
@@ -670,7 +670,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs) | |||
670 | break; | 670 | break; |
671 | } | 671 | } |
672 | 672 | ||
673 | if (!event || bit >= MAX_PEBS_EVENTS) | 673 | if (!event || bit >= x86_pmu.max_pebs_events) |
674 | continue; | 674 | continue; |
675 | 675 | ||
676 | __intel_pmu_pebs_event(event, iregs, at); | 676 | __intel_pmu_pebs_event(event, iregs, at); |
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c new file mode 100644 index 000000000000..19faffc60886 --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c | |||
@@ -0,0 +1,1850 @@ | |||
1 | #include "perf_event_intel_uncore.h" | ||
2 | |||
3 | static struct intel_uncore_type *empty_uncore[] = { NULL, }; | ||
4 | static struct intel_uncore_type **msr_uncores = empty_uncore; | ||
5 | static struct intel_uncore_type **pci_uncores = empty_uncore; | ||
6 | /* pci bus to socket mapping */ | ||
7 | static int pcibus_to_physid[256] = { [0 ... 255] = -1, }; | ||
8 | |||
9 | static DEFINE_RAW_SPINLOCK(uncore_box_lock); | ||
10 | |||
11 | /* mask of cpus that collect uncore events */ | ||
12 | static cpumask_t uncore_cpu_mask; | ||
13 | |||
14 | /* constraint for the fixed counter */ | ||
15 | static struct event_constraint constraint_fixed = | ||
16 | EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL); | ||
17 | static struct event_constraint constraint_empty = | ||
18 | EVENT_CONSTRAINT(0, 0, 0); | ||
19 | |||
20 | DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); | ||
21 | DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); | ||
22 | DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); | ||
23 | DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19"); | ||
24 | DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); | ||
25 | DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28"); | ||
26 | DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31"); | ||
27 | DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31"); | ||
28 | DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28"); | ||
29 | DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15"); | ||
30 | DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30"); | ||
31 | DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51"); | ||
32 | DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4"); | ||
33 | DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17"); | ||
34 | DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22"); | ||
35 | DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31"); | ||
36 | DEFINE_UNCORE_FORMAT_ATTR(filter_brand0, filter_brand0, "config1:0-7"); | ||
37 | DEFINE_UNCORE_FORMAT_ATTR(filter_brand1, filter_brand1, "config1:8-15"); | ||
38 | DEFINE_UNCORE_FORMAT_ATTR(filter_brand2, filter_brand2, "config1:16-23"); | ||
39 | DEFINE_UNCORE_FORMAT_ATTR(filter_brand3, filter_brand3, "config1:24-31"); | ||
40 | |||
41 | /* Sandy Bridge-EP uncore support */ | ||
42 | static struct intel_uncore_type snbep_uncore_cbox; | ||
43 | static struct intel_uncore_type snbep_uncore_pcu; | ||
44 | |||
45 | static void snbep_uncore_pci_disable_box(struct intel_uncore_box *box) | ||
46 | { | ||
47 | struct pci_dev *pdev = box->pci_dev; | ||
48 | int box_ctl = uncore_pci_box_ctl(box); | ||
49 | u32 config; | ||
50 | |||
51 | pci_read_config_dword(pdev, box_ctl, &config); | ||
52 | config |= SNBEP_PMON_BOX_CTL_FRZ; | ||
53 | pci_write_config_dword(pdev, box_ctl, config); | ||
54 | } | ||
55 | |||
56 | static void snbep_uncore_pci_enable_box(struct intel_uncore_box *box) | ||
57 | { | ||
58 | struct pci_dev *pdev = box->pci_dev; | ||
59 | int box_ctl = uncore_pci_box_ctl(box); | ||
60 | u32 config; | ||
61 | |||
62 | pci_read_config_dword(pdev, box_ctl, &config); | ||
63 | config &= ~SNBEP_PMON_BOX_CTL_FRZ; | ||
64 | pci_write_config_dword(pdev, box_ctl, config); | ||
65 | } | ||
66 | |||
67 | static void snbep_uncore_pci_enable_event(struct intel_uncore_box *box, | ||
68 | struct perf_event *event) | ||
69 | { | ||
70 | struct pci_dev *pdev = box->pci_dev; | ||
71 | struct hw_perf_event *hwc = &event->hw; | ||
72 | |||
73 | pci_write_config_dword(pdev, hwc->config_base, hwc->config | | ||
74 | SNBEP_PMON_CTL_EN); | ||
75 | } | ||
76 | |||
77 | static void snbep_uncore_pci_disable_event(struct intel_uncore_box *box, | ||
78 | struct perf_event *event) | ||
79 | { | ||
80 | struct pci_dev *pdev = box->pci_dev; | ||
81 | struct hw_perf_event *hwc = &event->hw; | ||
82 | |||
83 | pci_write_config_dword(pdev, hwc->config_base, hwc->config); | ||
84 | } | ||
85 | |||
86 | static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box, | ||
87 | struct perf_event *event) | ||
88 | { | ||
89 | struct pci_dev *pdev = box->pci_dev; | ||
90 | struct hw_perf_event *hwc = &event->hw; | ||
91 | u64 count; | ||
92 | |||
93 | pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count); | ||
94 | pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1); | ||
95 | return count; | ||
96 | } | ||
97 | |||
98 | static void snbep_uncore_pci_init_box(struct intel_uncore_box *box) | ||
99 | { | ||
100 | struct pci_dev *pdev = box->pci_dev; | ||
101 | pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, | ||
102 | SNBEP_PMON_BOX_CTL_INT); | ||
103 | } | ||
104 | |||
105 | static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box) | ||
106 | { | ||
107 | u64 config; | ||
108 | unsigned msr; | ||
109 | |||
110 | msr = uncore_msr_box_ctl(box); | ||
111 | if (msr) { | ||
112 | rdmsrl(msr, config); | ||
113 | config |= SNBEP_PMON_BOX_CTL_FRZ; | ||
114 | wrmsrl(msr, config); | ||
115 | return; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static void snbep_uncore_msr_enable_box(struct intel_uncore_box *box) | ||
120 | { | ||
121 | u64 config; | ||
122 | unsigned msr; | ||
123 | |||
124 | msr = uncore_msr_box_ctl(box); | ||
125 | if (msr) { | ||
126 | rdmsrl(msr, config); | ||
127 | config &= ~SNBEP_PMON_BOX_CTL_FRZ; | ||
128 | wrmsrl(msr, config); | ||
129 | return; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box, | ||
134 | struct perf_event *event) | ||
135 | { | ||
136 | struct hw_perf_event *hwc = &event->hw; | ||
137 | struct hw_perf_event_extra *reg1 = &hwc->extra_reg; | ||
138 | |||
139 | if (reg1->idx != EXTRA_REG_NONE) | ||
140 | wrmsrl(reg1->reg, reg1->config); | ||
141 | |||
142 | wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); | ||
143 | } | ||
144 | |||
145 | static void snbep_uncore_msr_disable_event(struct intel_uncore_box *box, | ||
146 | struct perf_event *event) | ||
147 | { | ||
148 | struct hw_perf_event *hwc = &event->hw; | ||
149 | |||
150 | wrmsrl(hwc->config_base, hwc->config); | ||
151 | } | ||
152 | |||
153 | static u64 snbep_uncore_msr_read_counter(struct intel_uncore_box *box, | ||
154 | struct perf_event *event) | ||
155 | { | ||
156 | struct hw_perf_event *hwc = &event->hw; | ||
157 | u64 count; | ||
158 | |||
159 | rdmsrl(hwc->event_base, count); | ||
160 | return count; | ||
161 | } | ||
162 | |||
163 | static void snbep_uncore_msr_init_box(struct intel_uncore_box *box) | ||
164 | { | ||
165 | unsigned msr = uncore_msr_box_ctl(box); | ||
166 | if (msr) | ||
167 | wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT); | ||
168 | } | ||
169 | |||
170 | static struct event_constraint * | ||
171 | snbep_uncore_get_constraint(struct intel_uncore_box *box, | ||
172 | struct perf_event *event) | ||
173 | { | ||
174 | struct intel_uncore_extra_reg *er; | ||
175 | struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; | ||
176 | unsigned long flags; | ||
177 | bool ok = false; | ||
178 | |||
179 | if (reg1->idx == EXTRA_REG_NONE || (box->phys_id >= 0 && reg1->alloc)) | ||
180 | return NULL; | ||
181 | |||
182 | er = &box->shared_regs[reg1->idx]; | ||
183 | raw_spin_lock_irqsave(&er->lock, flags); | ||
184 | if (!atomic_read(&er->ref) || er->config1 == reg1->config) { | ||
185 | atomic_inc(&er->ref); | ||
186 | er->config1 = reg1->config; | ||
187 | ok = true; | ||
188 | } | ||
189 | raw_spin_unlock_irqrestore(&er->lock, flags); | ||
190 | |||
191 | if (ok) { | ||
192 | if (box->phys_id >= 0) | ||
193 | reg1->alloc = 1; | ||
194 | return NULL; | ||
195 | } | ||
196 | return &constraint_empty; | ||
197 | } | ||
198 | |||
199 | static void snbep_uncore_put_constraint(struct intel_uncore_box *box, | ||
200 | struct perf_event *event) | ||
201 | { | ||
202 | struct intel_uncore_extra_reg *er; | ||
203 | struct hw_perf_event_extra *reg1 = &event->hw.extra_reg; | ||
204 | |||
205 | if (box->phys_id < 0 || !reg1->alloc) | ||
206 | return; | ||
207 | |||
208 | er = &box->shared_regs[reg1->idx]; | ||
209 | atomic_dec(&er->ref); | ||
210 | reg1->alloc = 0; | ||
211 | } | ||
212 | |||
213 | static int snbep_uncore_hw_config(struct intel_uncore_box *box, | ||
214 | struct perf_event *event) | ||
215 | { | ||
216 | struct hw_perf_event *hwc = &event->hw; | ||
217 | struct hw_perf_event_extra *reg1 = &hwc->extra_reg; | ||
218 | |||
219 | if (box->pmu->type == &snbep_uncore_cbox) { | ||
220 | reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER + | ||
221 | SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx; | ||
222 | reg1->config = event->attr.config1 & | ||
223 | SNBEP_CB0_MSR_PMON_BOX_FILTER_MASK; | ||
224 | } else if (box->pmu->type == &snbep_uncore_pcu) { | ||
225 | reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER; | ||
226 | reg1->config = event->attr.config1 & | ||
227 | SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK; | ||
228 | } else { | ||
229 | return 0; | ||
230 | } | ||
231 | reg1->idx = 0; | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static struct attribute *snbep_uncore_formats_attr[] = { | ||
236 | &format_attr_event.attr, | ||
237 | &format_attr_umask.attr, | ||
238 | &format_attr_edge.attr, | ||
239 | &format_attr_inv.attr, | ||
240 | &format_attr_thresh8.attr, | ||
241 | NULL, | ||
242 | }; | ||
243 | |||
244 | static struct attribute *snbep_uncore_ubox_formats_attr[] = { | ||
245 | &format_attr_event.attr, | ||
246 | &format_attr_umask.attr, | ||
247 | &format_attr_edge.attr, | ||
248 | &format_attr_inv.attr, | ||
249 | &format_attr_thresh5.attr, | ||
250 | NULL, | ||
251 | }; | ||
252 | |||
253 | static struct attribute *snbep_uncore_cbox_formats_attr[] = { | ||
254 | &format_attr_event.attr, | ||
255 | &format_attr_umask.attr, | ||
256 | &format_attr_edge.attr, | ||
257 | &format_attr_tid_en.attr, | ||
258 | &format_attr_inv.attr, | ||
259 | &format_attr_thresh8.attr, | ||
260 | &format_attr_filter_tid.attr, | ||
261 | &format_attr_filter_nid.attr, | ||
262 | &format_attr_filter_state.attr, | ||
263 | &format_attr_filter_opc.attr, | ||
264 | NULL, | ||
265 | }; | ||
266 | |||
267 | static struct attribute *snbep_uncore_pcu_formats_attr[] = { | ||
268 | &format_attr_event.attr, | ||
269 | &format_attr_occ_sel.attr, | ||
270 | &format_attr_edge.attr, | ||
271 | &format_attr_inv.attr, | ||
272 | &format_attr_thresh5.attr, | ||
273 | &format_attr_occ_invert.attr, | ||
274 | &format_attr_occ_edge.attr, | ||
275 | &format_attr_filter_brand0.attr, | ||
276 | &format_attr_filter_brand1.attr, | ||
277 | &format_attr_filter_brand2.attr, | ||
278 | &format_attr_filter_brand3.attr, | ||
279 | NULL, | ||
280 | }; | ||
281 | |||
282 | static struct uncore_event_desc snbep_uncore_imc_events[] = { | ||
283 | INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"), | ||
284 | INTEL_UNCORE_EVENT_DESC(cas_count_read, "event=0x04,umask=0x03"), | ||
285 | INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"), | ||
286 | { /* end: all zeroes */ }, | ||
287 | }; | ||
288 | |||
289 | static struct uncore_event_desc snbep_uncore_qpi_events[] = { | ||
290 | INTEL_UNCORE_EVENT_DESC(clockticks, "event=0x14"), | ||
291 | INTEL_UNCORE_EVENT_DESC(txl_flits_active, "event=0x00,umask=0x06"), | ||
292 | INTEL_UNCORE_EVENT_DESC(drs_data, "event=0x02,umask=0x08"), | ||
293 | INTEL_UNCORE_EVENT_DESC(ncb_data, "event=0x03,umask=0x04"), | ||
294 | { /* end: all zeroes */ }, | ||
295 | }; | ||
296 | |||
297 | static struct attribute_group snbep_uncore_format_group = { | ||
298 | .name = "format", | ||
299 | .attrs = snbep_uncore_formats_attr, | ||
300 | }; | ||
301 | |||
302 | static struct attribute_group snbep_uncore_ubox_format_group = { | ||
303 | .name = "format", | ||
304 | .attrs = snbep_uncore_ubox_formats_attr, | ||
305 | }; | ||
306 | |||
307 | static struct attribute_group snbep_uncore_cbox_format_group = { | ||
308 | .name = "format", | ||
309 | .attrs = snbep_uncore_cbox_formats_attr, | ||
310 | }; | ||
311 | |||
312 | static struct attribute_group snbep_uncore_pcu_format_group = { | ||
313 | .name = "format", | ||
314 | .attrs = snbep_uncore_pcu_formats_attr, | ||
315 | }; | ||
316 | |||
317 | static struct intel_uncore_ops snbep_uncore_msr_ops = { | ||
318 | .init_box = snbep_uncore_msr_init_box, | ||
319 | .disable_box = snbep_uncore_msr_disable_box, | ||
320 | .enable_box = snbep_uncore_msr_enable_box, | ||
321 | .disable_event = snbep_uncore_msr_disable_event, | ||
322 | .enable_event = snbep_uncore_msr_enable_event, | ||
323 | .read_counter = snbep_uncore_msr_read_counter, | ||
324 | .get_constraint = snbep_uncore_get_constraint, | ||
325 | .put_constraint = snbep_uncore_put_constraint, | ||
326 | .hw_config = snbep_uncore_hw_config, | ||
327 | }; | ||
328 | |||
329 | static struct intel_uncore_ops snbep_uncore_pci_ops = { | ||
330 | .init_box = snbep_uncore_pci_init_box, | ||
331 | .disable_box = snbep_uncore_pci_disable_box, | ||
332 | .enable_box = snbep_uncore_pci_enable_box, | ||
333 | .disable_event = snbep_uncore_pci_disable_event, | ||
334 | .enable_event = snbep_uncore_pci_enable_event, | ||
335 | .read_counter = snbep_uncore_pci_read_counter, | ||
336 | }; | ||
337 | |||
338 | static struct event_constraint snbep_uncore_cbox_constraints[] = { | ||
339 | UNCORE_EVENT_CONSTRAINT(0x01, 0x1), | ||
340 | UNCORE_EVENT_CONSTRAINT(0x02, 0x3), | ||
341 | UNCORE_EVENT_CONSTRAINT(0x04, 0x3), | ||
342 | UNCORE_EVENT_CONSTRAINT(0x05, 0x3), | ||
343 | UNCORE_EVENT_CONSTRAINT(0x07, 0x3), | ||
344 | UNCORE_EVENT_CONSTRAINT(0x11, 0x1), | ||
345 | UNCORE_EVENT_CONSTRAINT(0x12, 0x3), | ||
346 | UNCORE_EVENT_CONSTRAINT(0x13, 0x3), | ||
347 | UNCORE_EVENT_CONSTRAINT(0x1b, 0xc), | ||
348 | UNCORE_EVENT_CONSTRAINT(0x1c, 0xc), | ||
349 | UNCORE_EVENT_CONSTRAINT(0x1d, 0xc), | ||
350 | UNCORE_EVENT_CONSTRAINT(0x1e, 0xc), | ||
351 | EVENT_CONSTRAINT_OVERLAP(0x1f, 0xe, 0xff), | ||
352 | UNCORE_EVENT_CONSTRAINT(0x21, 0x3), | ||
353 | UNCORE_EVENT_CONSTRAINT(0x23, 0x3), | ||
354 | UNCORE_EVENT_CONSTRAINT(0x31, 0x3), | ||
355 | UNCORE_EVENT_CONSTRAINT(0x32, 0x3), | ||
356 | UNCORE_EVENT_CONSTRAINT(0x33, 0x3), | ||
357 | UNCORE_EVENT_CONSTRAINT(0x34, 0x3), | ||
358 | UNCORE_EVENT_CONSTRAINT(0x35, 0x3), | ||
359 | UNCORE_EVENT_CONSTRAINT(0x36, 0x1), | ||
360 | UNCORE_EVENT_CONSTRAINT(0x37, 0x3), | ||
361 | UNCORE_EVENT_CONSTRAINT(0x38, 0x3), | ||
362 | UNCORE_EVENT_CONSTRAINT(0x39, 0x3), | ||
363 | UNCORE_EVENT_CONSTRAINT(0x3b, 0x1), | ||
364 | EVENT_CONSTRAINT_END | ||
365 | }; | ||
366 | |||
367 | static struct event_constraint snbep_uncore_r2pcie_constraints[] = { | ||
368 | UNCORE_EVENT_CONSTRAINT(0x10, 0x3), | ||
369 | UNCORE_EVENT_CONSTRAINT(0x11, 0x3), | ||
370 | UNCORE_EVENT_CONSTRAINT(0x12, 0x1), | ||
371 | UNCORE_EVENT_CONSTRAINT(0x23, 0x3), | ||
372 | UNCORE_EVENT_CONSTRAINT(0x24, 0x3), | ||
373 | UNCORE_EVENT_CONSTRAINT(0x25, 0x3), | ||
374 | UNCORE_EVENT_CONSTRAINT(0x26, 0x3), | ||
375 | UNCORE_EVENT_CONSTRAINT(0x32, 0x3), | ||
376 | UNCORE_EVENT_CONSTRAINT(0x33, 0x3), | ||
377 | UNCORE_EVENT_CONSTRAINT(0x34, 0x3), | ||
378 | EVENT_CONSTRAINT_END | ||
379 | }; | ||
380 | |||
381 | static struct event_constraint snbep_uncore_r3qpi_constraints[] = { | ||
382 | UNCORE_EVENT_CONSTRAINT(0x10, 0x3), | ||
383 | UNCORE_EVENT_CONSTRAINT(0x11, 0x3), | ||
384 | UNCORE_EVENT_CONSTRAINT(0x12, 0x3), | ||
385 | UNCORE_EVENT_CONSTRAINT(0x13, 0x1), | ||
386 | UNCORE_EVENT_CONSTRAINT(0x20, 0x3), | ||
387 | UNCORE_EVENT_CONSTRAINT(0x21, 0x3), | ||
388 | UNCORE_EVENT_CONSTRAINT(0x22, 0x3), | ||
389 | UNCORE_EVENT_CONSTRAINT(0x23, 0x3), | ||
390 | UNCORE_EVENT_CONSTRAINT(0x24, 0x3), | ||
391 | UNCORE_EVENT_CONSTRAINT(0x25, 0x3), | ||
392 | UNCORE_EVENT_CONSTRAINT(0x26, 0x3), | ||
393 | UNCORE_EVENT_CONSTRAINT(0x30, 0x3), | ||
394 | UNCORE_EVENT_CONSTRAINT(0x31, 0x3), | ||
395 | UNCORE_EVENT_CONSTRAINT(0x32, 0x3), | ||
396 | UNCORE_EVENT_CONSTRAINT(0x33, 0x3), | ||
397 | UNCORE_EVENT_CONSTRAINT(0x34, 0x3), | ||
398 | UNCORE_EVENT_CONSTRAINT(0x36, 0x3), | ||
399 | UNCORE_EVENT_CONSTRAINT(0x37, 0x3), | ||
400 | EVENT_CONSTRAINT_END | ||
401 | }; | ||
402 | |||
403 | static struct intel_uncore_type snbep_uncore_ubox = { | ||
404 | .name = "ubox", | ||
405 | .num_counters = 2, | ||
406 | .num_boxes = 1, | ||
407 | .perf_ctr_bits = 44, | ||
408 | .fixed_ctr_bits = 48, | ||
409 | .perf_ctr = SNBEP_U_MSR_PMON_CTR0, | ||
410 | .event_ctl = SNBEP_U_MSR_PMON_CTL0, | ||
411 | .event_mask = SNBEP_U_MSR_PMON_RAW_EVENT_MASK, | ||
412 | .fixed_ctr = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR, | ||
413 | .fixed_ctl = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL, | ||
414 | .ops = &snbep_uncore_msr_ops, | ||
415 | .format_group = &snbep_uncore_ubox_format_group, | ||
416 | }; | ||
417 | |||
418 | static struct intel_uncore_type snbep_uncore_cbox = { | ||
419 | .name = "cbox", | ||
420 | .num_counters = 4, | ||
421 | .num_boxes = 8, | ||
422 | .perf_ctr_bits = 44, | ||
423 | .event_ctl = SNBEP_C0_MSR_PMON_CTL0, | ||
424 | .perf_ctr = SNBEP_C0_MSR_PMON_CTR0, | ||
425 | .event_mask = SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK, | ||
426 | .box_ctl = SNBEP_C0_MSR_PMON_BOX_CTL, | ||
427 | .msr_offset = SNBEP_CBO_MSR_OFFSET, | ||
428 | .num_shared_regs = 1, | ||
429 | .constraints = snbep_uncore_cbox_constraints, | ||
430 | .ops = &snbep_uncore_msr_ops, | ||
431 | .format_group = &snbep_uncore_cbox_format_group, | ||
432 | }; | ||
433 | |||
434 | static struct intel_uncore_type snbep_uncore_pcu = { | ||
435 | .name = "pcu", | ||
436 | .num_counters = 4, | ||
437 | .num_boxes = 1, | ||
438 | .perf_ctr_bits = 48, | ||
439 | .perf_ctr = SNBEP_PCU_MSR_PMON_CTR0, | ||
440 | .event_ctl = SNBEP_PCU_MSR_PMON_CTL0, | ||
441 | .event_mask = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK, | ||
442 | .box_ctl = SNBEP_PCU_MSR_PMON_BOX_CTL, | ||
443 | .num_shared_regs = 1, | ||
444 | .ops = &snbep_uncore_msr_ops, | ||
445 | .format_group = &snbep_uncore_pcu_format_group, | ||
446 | }; | ||
447 | |||
448 | static struct intel_uncore_type *snbep_msr_uncores[] = { | ||
449 | &snbep_uncore_ubox, | ||
450 | &snbep_uncore_cbox, | ||
451 | &snbep_uncore_pcu, | ||
452 | NULL, | ||
453 | }; | ||
454 | |||
455 | #define SNBEP_UNCORE_PCI_COMMON_INIT() \ | ||
456 | .perf_ctr = SNBEP_PCI_PMON_CTR0, \ | ||
457 | .event_ctl = SNBEP_PCI_PMON_CTL0, \ | ||
458 | .event_mask = SNBEP_PMON_RAW_EVENT_MASK, \ | ||
459 | .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \ | ||
460 | .ops = &snbep_uncore_pci_ops, \ | ||
461 | .format_group = &snbep_uncore_format_group | ||
462 | |||
463 | static struct intel_uncore_type snbep_uncore_ha = { | ||
464 | .name = "ha", | ||
465 | .num_counters = 4, | ||
466 | .num_boxes = 1, | ||
467 | .perf_ctr_bits = 48, | ||
468 | SNBEP_UNCORE_PCI_COMMON_INIT(), | ||
469 | }; | ||
470 | |||
471 | static struct intel_uncore_type snbep_uncore_imc = { | ||
472 | .name = "imc", | ||
473 | .num_counters = 4, | ||
474 | .num_boxes = 4, | ||
475 | .perf_ctr_bits = 48, | ||
476 | .fixed_ctr_bits = 48, | ||
477 | .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, | ||
478 | .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, | ||
479 | .event_descs = snbep_uncore_imc_events, | ||
480 | SNBEP_UNCORE_PCI_COMMON_INIT(), | ||
481 | }; | ||
482 | |||
483 | static struct intel_uncore_type snbep_uncore_qpi = { | ||
484 | .name = "qpi", | ||
485 | .num_counters = 4, | ||
486 | .num_boxes = 2, | ||
487 | .perf_ctr_bits = 48, | ||
488 | .event_descs = snbep_uncore_qpi_events, | ||
489 | SNBEP_UNCORE_PCI_COMMON_INIT(), | ||
490 | }; | ||
491 | |||
492 | |||
493 | static struct intel_uncore_type snbep_uncore_r2pcie = { | ||
494 | .name = "r2pcie", | ||
495 | .num_counters = 4, | ||
496 | .num_boxes = 1, | ||
497 | .perf_ctr_bits = 44, | ||
498 | .constraints = snbep_uncore_r2pcie_constraints, | ||
499 | SNBEP_UNCORE_PCI_COMMON_INIT(), | ||
500 | }; | ||
501 | |||
502 | static struct intel_uncore_type snbep_uncore_r3qpi = { | ||
503 | .name = "r3qpi", | ||
504 | .num_counters = 3, | ||
505 | .num_boxes = 2, | ||
506 | .perf_ctr_bits = 44, | ||
507 | .constraints = snbep_uncore_r3qpi_constraints, | ||
508 | SNBEP_UNCORE_PCI_COMMON_INIT(), | ||
509 | }; | ||
510 | |||
511 | static struct intel_uncore_type *snbep_pci_uncores[] = { | ||
512 | &snbep_uncore_ha, | ||
513 | &snbep_uncore_imc, | ||
514 | &snbep_uncore_qpi, | ||
515 | &snbep_uncore_r2pcie, | ||
516 | &snbep_uncore_r3qpi, | ||
517 | NULL, | ||
518 | }; | ||
519 | |||
520 | static DEFINE_PCI_DEVICE_TABLE(snbep_uncore_pci_ids) = { | ||
521 | { /* Home Agent */ | ||
522 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA), | ||
523 | .driver_data = (unsigned long)&snbep_uncore_ha, | ||
524 | }, | ||
525 | { /* MC Channel 0 */ | ||
526 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0), | ||
527 | .driver_data = (unsigned long)&snbep_uncore_imc, | ||
528 | }, | ||
529 | { /* MC Channel 1 */ | ||
530 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1), | ||
531 | .driver_data = (unsigned long)&snbep_uncore_imc, | ||
532 | }, | ||
533 | { /* MC Channel 2 */ | ||
534 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2), | ||
535 | .driver_data = (unsigned long)&snbep_uncore_imc, | ||
536 | }, | ||
537 | { /* MC Channel 3 */ | ||
538 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3), | ||
539 | .driver_data = (unsigned long)&snbep_uncore_imc, | ||
540 | }, | ||
541 | { /* QPI Port 0 */ | ||
542 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0), | ||
543 | .driver_data = (unsigned long)&snbep_uncore_qpi, | ||
544 | }, | ||
545 | { /* QPI Port 1 */ | ||
546 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1), | ||
547 | .driver_data = (unsigned long)&snbep_uncore_qpi, | ||
548 | }, | ||
549 | { /* P2PCIe */ | ||
550 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE), | ||
551 | .driver_data = (unsigned long)&snbep_uncore_r2pcie, | ||
552 | }, | ||
553 | { /* R3QPI Link 0 */ | ||
554 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0), | ||
555 | .driver_data = (unsigned long)&snbep_uncore_r3qpi, | ||
556 | }, | ||
557 | { /* R3QPI Link 1 */ | ||
558 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1), | ||
559 | .driver_data = (unsigned long)&snbep_uncore_r3qpi, | ||
560 | }, | ||
561 | { /* end: all zeroes */ } | ||
562 | }; | ||
563 | |||
564 | static struct pci_driver snbep_uncore_pci_driver = { | ||
565 | .name = "snbep_uncore", | ||
566 | .id_table = snbep_uncore_pci_ids, | ||
567 | }; | ||
568 | |||
569 | /* | ||
570 | * build pci bus to socket mapping | ||
571 | */ | ||
572 | static void snbep_pci2phy_map_init(void) | ||
573 | { | ||
574 | struct pci_dev *ubox_dev = NULL; | ||
575 | int i, bus, nodeid; | ||
576 | u32 config; | ||
577 | |||
578 | while (1) { | ||
579 | /* find the UBOX device */ | ||
580 | ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
581 | PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX, | ||
582 | ubox_dev); | ||
583 | if (!ubox_dev) | ||
584 | break; | ||
585 | bus = ubox_dev->bus->number; | ||
586 | /* get the Node ID of the local register */ | ||
587 | pci_read_config_dword(ubox_dev, 0x40, &config); | ||
588 | nodeid = config; | ||
589 | /* get the Node ID mapping */ | ||
590 | pci_read_config_dword(ubox_dev, 0x54, &config); | ||
591 | /* | ||
592 | * every three bits in the Node ID mapping register maps | ||
593 | * to a particular node. | ||
594 | */ | ||
595 | for (i = 0; i < 8; i++) { | ||
596 | if (nodeid == ((config >> (3 * i)) & 0x7)) { | ||
597 | pcibus_to_physid[bus] = i; | ||
598 | break; | ||
599 | } | ||
600 | } | ||
601 | }; | ||
602 | return; | ||
603 | } | ||
604 | /* end of Sandy Bridge-EP uncore support */ | ||
605 | |||
606 | |||
607 | /* Sandy Bridge uncore support */ | ||
608 | static void snb_uncore_msr_enable_event(struct intel_uncore_box *box, | ||
609 | struct perf_event *event) | ||
610 | { | ||
611 | struct hw_perf_event *hwc = &event->hw; | ||
612 | |||
613 | if (hwc->idx < UNCORE_PMC_IDX_FIXED) | ||
614 | wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN); | ||
615 | else | ||
616 | wrmsrl(hwc->config_base, SNB_UNC_CTL_EN); | ||
617 | } | ||
618 | |||
619 | static void snb_uncore_msr_disable_event(struct intel_uncore_box *box, | ||
620 | struct perf_event *event) | ||
621 | { | ||
622 | wrmsrl(event->hw.config_base, 0); | ||
623 | } | ||
624 | |||
625 | static u64 snb_uncore_msr_read_counter(struct intel_uncore_box *box, | ||
626 | struct perf_event *event) | ||
627 | { | ||
628 | u64 count; | ||
629 | rdmsrl(event->hw.event_base, count); | ||
630 | return count; | ||
631 | } | ||
632 | |||
633 | static void snb_uncore_msr_init_box(struct intel_uncore_box *box) | ||
634 | { | ||
635 | if (box->pmu->pmu_idx == 0) { | ||
636 | wrmsrl(SNB_UNC_PERF_GLOBAL_CTL, | ||
637 | SNB_UNC_GLOBAL_CTL_EN | SNB_UNC_GLOBAL_CTL_CORE_ALL); | ||
638 | } | ||
639 | } | ||
640 | |||
641 | static struct attribute *snb_uncore_formats_attr[] = { | ||
642 | &format_attr_event.attr, | ||
643 | &format_attr_umask.attr, | ||
644 | &format_attr_edge.attr, | ||
645 | &format_attr_inv.attr, | ||
646 | &format_attr_cmask5.attr, | ||
647 | NULL, | ||
648 | }; | ||
649 | |||
650 | static struct attribute_group snb_uncore_format_group = { | ||
651 | .name = "format", | ||
652 | .attrs = snb_uncore_formats_attr, | ||
653 | }; | ||
654 | |||
655 | static struct intel_uncore_ops snb_uncore_msr_ops = { | ||
656 | .init_box = snb_uncore_msr_init_box, | ||
657 | .disable_event = snb_uncore_msr_disable_event, | ||
658 | .enable_event = snb_uncore_msr_enable_event, | ||
659 | .read_counter = snb_uncore_msr_read_counter, | ||
660 | }; | ||
661 | |||
662 | static struct event_constraint snb_uncore_cbox_constraints[] = { | ||
663 | UNCORE_EVENT_CONSTRAINT(0x80, 0x1), | ||
664 | UNCORE_EVENT_CONSTRAINT(0x83, 0x1), | ||
665 | EVENT_CONSTRAINT_END | ||
666 | }; | ||
667 | |||
668 | static struct intel_uncore_type snb_uncore_cbox = { | ||
669 | .name = "cbox", | ||
670 | .num_counters = 2, | ||
671 | .num_boxes = 4, | ||
672 | .perf_ctr_bits = 44, | ||
673 | .fixed_ctr_bits = 48, | ||
674 | .perf_ctr = SNB_UNC_CBO_0_PER_CTR0, | ||
675 | .event_ctl = SNB_UNC_CBO_0_PERFEVTSEL0, | ||
676 | .fixed_ctr = SNB_UNC_FIXED_CTR, | ||
677 | .fixed_ctl = SNB_UNC_FIXED_CTR_CTRL, | ||
678 | .single_fixed = 1, | ||
679 | .event_mask = SNB_UNC_RAW_EVENT_MASK, | ||
680 | .msr_offset = SNB_UNC_CBO_MSR_OFFSET, | ||
681 | .constraints = snb_uncore_cbox_constraints, | ||
682 | .ops = &snb_uncore_msr_ops, | ||
683 | .format_group = &snb_uncore_format_group, | ||
684 | }; | ||
685 | |||
686 | static struct intel_uncore_type *snb_msr_uncores[] = { | ||
687 | &snb_uncore_cbox, | ||
688 | NULL, | ||
689 | }; | ||
690 | /* end of Sandy Bridge uncore support */ | ||
691 | |||
692 | /* Nehalem uncore support */ | ||
693 | static void nhm_uncore_msr_disable_box(struct intel_uncore_box *box) | ||
694 | { | ||
695 | wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, 0); | ||
696 | } | ||
697 | |||
698 | static void nhm_uncore_msr_enable_box(struct intel_uncore_box *box) | ||
699 | { | ||
700 | wrmsrl(NHM_UNC_PERF_GLOBAL_CTL, | ||
701 | NHM_UNC_GLOBAL_CTL_EN_PC_ALL | NHM_UNC_GLOBAL_CTL_EN_FC); | ||
702 | } | ||
703 | |||
704 | static void nhm_uncore_msr_enable_event(struct intel_uncore_box *box, | ||
705 | struct perf_event *event) | ||
706 | { | ||
707 | struct hw_perf_event *hwc = &event->hw; | ||
708 | |||
709 | if (hwc->idx < UNCORE_PMC_IDX_FIXED) | ||
710 | wrmsrl(hwc->config_base, hwc->config | SNB_UNC_CTL_EN); | ||
711 | else | ||
712 | wrmsrl(hwc->config_base, NHM_UNC_FIXED_CTR_CTL_EN); | ||
713 | } | ||
714 | |||
715 | static struct attribute *nhm_uncore_formats_attr[] = { | ||
716 | &format_attr_event.attr, | ||
717 | &format_attr_umask.attr, | ||
718 | &format_attr_edge.attr, | ||
719 | &format_attr_inv.attr, | ||
720 | &format_attr_cmask8.attr, | ||
721 | NULL, | ||
722 | }; | ||
723 | |||
724 | static struct attribute_group nhm_uncore_format_group = { | ||
725 | .name = "format", | ||
726 | .attrs = nhm_uncore_formats_attr, | ||
727 | }; | ||
728 | |||
729 | static struct uncore_event_desc nhm_uncore_events[] = { | ||
730 | INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"), | ||
731 | INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any, "event=0x2f,umask=0x0f"), | ||
732 | INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any, "event=0x2c,umask=0x0f"), | ||
733 | INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads, "event=0x20,umask=0x01"), | ||
734 | INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes, "event=0x20,umask=0x02"), | ||
735 | INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads, "event=0x20,umask=0x04"), | ||
736 | INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"), | ||
737 | INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads, "event=0x20,umask=0x10"), | ||
738 | INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes, "event=0x20,umask=0x20"), | ||
739 | { /* end: all zeroes */ }, | ||
740 | }; | ||
741 | |||
742 | static struct intel_uncore_ops nhm_uncore_msr_ops = { | ||
743 | .disable_box = nhm_uncore_msr_disable_box, | ||
744 | .enable_box = nhm_uncore_msr_enable_box, | ||
745 | .disable_event = snb_uncore_msr_disable_event, | ||
746 | .enable_event = nhm_uncore_msr_enable_event, | ||
747 | .read_counter = snb_uncore_msr_read_counter, | ||
748 | }; | ||
749 | |||
750 | static struct intel_uncore_type nhm_uncore = { | ||
751 | .name = "", | ||
752 | .num_counters = 8, | ||
753 | .num_boxes = 1, | ||
754 | .perf_ctr_bits = 48, | ||
755 | .fixed_ctr_bits = 48, | ||
756 | .event_ctl = NHM_UNC_PERFEVTSEL0, | ||
757 | .perf_ctr = NHM_UNC_UNCORE_PMC0, | ||
758 | .fixed_ctr = NHM_UNC_FIXED_CTR, | ||
759 | .fixed_ctl = NHM_UNC_FIXED_CTR_CTRL, | ||
760 | .event_mask = NHM_UNC_RAW_EVENT_MASK, | ||
761 | .event_descs = nhm_uncore_events, | ||
762 | .ops = &nhm_uncore_msr_ops, | ||
763 | .format_group = &nhm_uncore_format_group, | ||
764 | }; | ||
765 | |||
766 | static struct intel_uncore_type *nhm_msr_uncores[] = { | ||
767 | &nhm_uncore, | ||
768 | NULL, | ||
769 | }; | ||
770 | /* end of Nehalem uncore support */ | ||
771 | |||
772 | static void uncore_assign_hw_event(struct intel_uncore_box *box, | ||
773 | struct perf_event *event, int idx) | ||
774 | { | ||
775 | struct hw_perf_event *hwc = &event->hw; | ||
776 | |||
777 | hwc->idx = idx; | ||
778 | hwc->last_tag = ++box->tags[idx]; | ||
779 | |||
780 | if (hwc->idx == UNCORE_PMC_IDX_FIXED) { | ||
781 | hwc->event_base = uncore_fixed_ctr(box); | ||
782 | hwc->config_base = uncore_fixed_ctl(box); | ||
783 | return; | ||
784 | } | ||
785 | |||
786 | hwc->config_base = uncore_event_ctl(box, hwc->idx); | ||
787 | hwc->event_base = uncore_perf_ctr(box, hwc->idx); | ||
788 | } | ||
789 | |||
790 | static void uncore_perf_event_update(struct intel_uncore_box *box, | ||
791 | struct perf_event *event) | ||
792 | { | ||
793 | u64 prev_count, new_count, delta; | ||
794 | int shift; | ||
795 | |||
796 | if (event->hw.idx >= UNCORE_PMC_IDX_FIXED) | ||
797 | shift = 64 - uncore_fixed_ctr_bits(box); | ||
798 | else | ||
799 | shift = 64 - uncore_perf_ctr_bits(box); | ||
800 | |||
801 | /* the hrtimer might modify the previous event value */ | ||
802 | again: | ||
803 | prev_count = local64_read(&event->hw.prev_count); | ||
804 | new_count = uncore_read_counter(box, event); | ||
805 | if (local64_xchg(&event->hw.prev_count, new_count) != prev_count) | ||
806 | goto again; | ||
807 | |||
808 | delta = (new_count << shift) - (prev_count << shift); | ||
809 | delta >>= shift; | ||
810 | |||
811 | local64_add(delta, &event->count); | ||
812 | } | ||
813 | |||
814 | /* | ||
815 | * The overflow interrupt is unavailable for SandyBridge-EP, is broken | ||
816 | * for SandyBridge. So we use hrtimer to periodically poll the counter | ||
817 | * to avoid overflow. | ||
818 | */ | ||
819 | static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer) | ||
820 | { | ||
821 | struct intel_uncore_box *box; | ||
822 | unsigned long flags; | ||
823 | int bit; | ||
824 | |||
825 | box = container_of(hrtimer, struct intel_uncore_box, hrtimer); | ||
826 | if (!box->n_active || box->cpu != smp_processor_id()) | ||
827 | return HRTIMER_NORESTART; | ||
828 | /* | ||
829 | * disable local interrupt to prevent uncore_pmu_event_start/stop | ||
830 | * to interrupt the update process | ||
831 | */ | ||
832 | local_irq_save(flags); | ||
833 | |||
834 | for_each_set_bit(bit, box->active_mask, UNCORE_PMC_IDX_MAX) | ||
835 | uncore_perf_event_update(box, box->events[bit]); | ||
836 | |||
837 | local_irq_restore(flags); | ||
838 | |||
839 | hrtimer_forward_now(hrtimer, ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL)); | ||
840 | return HRTIMER_RESTART; | ||
841 | } | ||
842 | |||
843 | static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box) | ||
844 | { | ||
845 | __hrtimer_start_range_ns(&box->hrtimer, | ||
846 | ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL), 0, | ||
847 | HRTIMER_MODE_REL_PINNED, 0); | ||
848 | } | ||
849 | |||
850 | static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box) | ||
851 | { | ||
852 | hrtimer_cancel(&box->hrtimer); | ||
853 | } | ||
854 | |||
855 | static void uncore_pmu_init_hrtimer(struct intel_uncore_box *box) | ||
856 | { | ||
857 | hrtimer_init(&box->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
858 | box->hrtimer.function = uncore_pmu_hrtimer; | ||
859 | } | ||
860 | |||
861 | struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type, | ||
862 | int cpu) | ||
863 | { | ||
864 | struct intel_uncore_box *box; | ||
865 | int i, size; | ||
866 | |||
867 | size = sizeof(*box) + type->num_shared_regs * | ||
868 | sizeof(struct intel_uncore_extra_reg); | ||
869 | |||
870 | box = kmalloc_node(size, GFP_KERNEL | __GFP_ZERO, cpu_to_node(cpu)); | ||
871 | if (!box) | ||
872 | return NULL; | ||
873 | |||
874 | for (i = 0; i < type->num_shared_regs; i++) | ||
875 | raw_spin_lock_init(&box->shared_regs[i].lock); | ||
876 | |||
877 | uncore_pmu_init_hrtimer(box); | ||
878 | atomic_set(&box->refcnt, 1); | ||
879 | box->cpu = -1; | ||
880 | box->phys_id = -1; | ||
881 | |||
882 | return box; | ||
883 | } | ||
884 | |||
885 | static struct intel_uncore_box * | ||
886 | uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu) | ||
887 | { | ||
888 | static struct intel_uncore_box *box; | ||
889 | |||
890 | box = *per_cpu_ptr(pmu->box, cpu); | ||
891 | if (box) | ||
892 | return box; | ||
893 | |||
894 | raw_spin_lock(&uncore_box_lock); | ||
895 | list_for_each_entry(box, &pmu->box_list, list) { | ||
896 | if (box->phys_id == topology_physical_package_id(cpu)) { | ||
897 | atomic_inc(&box->refcnt); | ||
898 | *per_cpu_ptr(pmu->box, cpu) = box; | ||
899 | break; | ||
900 | } | ||
901 | } | ||
902 | raw_spin_unlock(&uncore_box_lock); | ||
903 | |||
904 | return *per_cpu_ptr(pmu->box, cpu); | ||
905 | } | ||
906 | |||
907 | static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event) | ||
908 | { | ||
909 | return container_of(event->pmu, struct intel_uncore_pmu, pmu); | ||
910 | } | ||
911 | |||
912 | static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event) | ||
913 | { | ||
914 | /* | ||
915 | * perf core schedules event on the basis of cpu, uncore events are | ||
916 | * collected by one of the cpus inside a physical package. | ||
917 | */ | ||
918 | return uncore_pmu_to_box(uncore_event_to_pmu(event), | ||
919 | smp_processor_id()); | ||
920 | } | ||
921 | |||
922 | static int uncore_collect_events(struct intel_uncore_box *box, | ||
923 | struct perf_event *leader, bool dogrp) | ||
924 | { | ||
925 | struct perf_event *event; | ||
926 | int n, max_count; | ||
927 | |||
928 | max_count = box->pmu->type->num_counters; | ||
929 | if (box->pmu->type->fixed_ctl) | ||
930 | max_count++; | ||
931 | |||
932 | if (box->n_events >= max_count) | ||
933 | return -EINVAL; | ||
934 | |||
935 | n = box->n_events; | ||
936 | box->event_list[n] = leader; | ||
937 | n++; | ||
938 | if (!dogrp) | ||
939 | return n; | ||
940 | |||
941 | list_for_each_entry(event, &leader->sibling_list, group_entry) { | ||
942 | if (event->state <= PERF_EVENT_STATE_OFF) | ||
943 | continue; | ||
944 | |||
945 | if (n >= max_count) | ||
946 | return -EINVAL; | ||
947 | |||
948 | box->event_list[n] = event; | ||
949 | n++; | ||
950 | } | ||
951 | return n; | ||
952 | } | ||
953 | |||
954 | static struct event_constraint * | ||
955 | uncore_get_event_constraint(struct intel_uncore_box *box, | ||
956 | struct perf_event *event) | ||
957 | { | ||
958 | struct intel_uncore_type *type = box->pmu->type; | ||
959 | struct event_constraint *c; | ||
960 | |||
961 | if (type->ops->get_constraint) { | ||
962 | c = type->ops->get_constraint(box, event); | ||
963 | if (c) | ||
964 | return c; | ||
965 | } | ||
966 | |||
967 | if (event->hw.config == ~0ULL) | ||
968 | return &constraint_fixed; | ||
969 | |||
970 | if (type->constraints) { | ||
971 | for_each_event_constraint(c, type->constraints) { | ||
972 | if ((event->hw.config & c->cmask) == c->code) | ||
973 | return c; | ||
974 | } | ||
975 | } | ||
976 | |||
977 | return &type->unconstrainted; | ||
978 | } | ||
979 | |||
980 | static void uncore_put_event_constraint(struct intel_uncore_box *box, | ||
981 | struct perf_event *event) | ||
982 | { | ||
983 | if (box->pmu->type->ops->put_constraint) | ||
984 | box->pmu->type->ops->put_constraint(box, event); | ||
985 | } | ||
986 | |||
987 | static int uncore_assign_events(struct intel_uncore_box *box, | ||
988 | int assign[], int n) | ||
989 | { | ||
990 | unsigned long used_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)]; | ||
991 | struct event_constraint *c, *constraints[UNCORE_PMC_IDX_MAX]; | ||
992 | int i, wmin, wmax, ret = 0; | ||
993 | struct hw_perf_event *hwc; | ||
994 | |||
995 | bitmap_zero(used_mask, UNCORE_PMC_IDX_MAX); | ||
996 | |||
997 | for (i = 0, wmin = UNCORE_PMC_IDX_MAX, wmax = 0; i < n; i++) { | ||
998 | c = uncore_get_event_constraint(box, box->event_list[i]); | ||
999 | constraints[i] = c; | ||
1000 | wmin = min(wmin, c->weight); | ||
1001 | wmax = max(wmax, c->weight); | ||
1002 | } | ||
1003 | |||
1004 | /* fastpath, try to reuse previous register */ | ||
1005 | for (i = 0; i < n; i++) { | ||
1006 | hwc = &box->event_list[i]->hw; | ||
1007 | c = constraints[i]; | ||
1008 | |||
1009 | /* never assigned */ | ||
1010 | if (hwc->idx == -1) | ||
1011 | break; | ||
1012 | |||
1013 | /* constraint still honored */ | ||
1014 | if (!test_bit(hwc->idx, c->idxmsk)) | ||
1015 | break; | ||
1016 | |||
1017 | /* not already used */ | ||
1018 | if (test_bit(hwc->idx, used_mask)) | ||
1019 | break; | ||
1020 | |||
1021 | __set_bit(hwc->idx, used_mask); | ||
1022 | if (assign) | ||
1023 | assign[i] = hwc->idx; | ||
1024 | } | ||
1025 | /* slow path */ | ||
1026 | if (i != n) | ||
1027 | ret = perf_assign_events(constraints, n, wmin, wmax, assign); | ||
1028 | |||
1029 | if (!assign || ret) { | ||
1030 | for (i = 0; i < n; i++) | ||
1031 | uncore_put_event_constraint(box, box->event_list[i]); | ||
1032 | } | ||
1033 | return ret ? -EINVAL : 0; | ||
1034 | } | ||
1035 | |||
1036 | static void uncore_pmu_event_start(struct perf_event *event, int flags) | ||
1037 | { | ||
1038 | struct intel_uncore_box *box = uncore_event_to_box(event); | ||
1039 | int idx = event->hw.idx; | ||
1040 | |||
1041 | if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) | ||
1042 | return; | ||
1043 | |||
1044 | if (WARN_ON_ONCE(idx == -1 || idx >= UNCORE_PMC_IDX_MAX)) | ||
1045 | return; | ||
1046 | |||
1047 | event->hw.state = 0; | ||
1048 | box->events[idx] = event; | ||
1049 | box->n_active++; | ||
1050 | __set_bit(idx, box->active_mask); | ||
1051 | |||
1052 | local64_set(&event->hw.prev_count, uncore_read_counter(box, event)); | ||
1053 | uncore_enable_event(box, event); | ||
1054 | |||
1055 | if (box->n_active == 1) { | ||
1056 | uncore_enable_box(box); | ||
1057 | uncore_pmu_start_hrtimer(box); | ||
1058 | } | ||
1059 | } | ||
1060 | |||
1061 | static void uncore_pmu_event_stop(struct perf_event *event, int flags) | ||
1062 | { | ||
1063 | struct intel_uncore_box *box = uncore_event_to_box(event); | ||
1064 | struct hw_perf_event *hwc = &event->hw; | ||
1065 | |||
1066 | if (__test_and_clear_bit(hwc->idx, box->active_mask)) { | ||
1067 | uncore_disable_event(box, event); | ||
1068 | box->n_active--; | ||
1069 | box->events[hwc->idx] = NULL; | ||
1070 | WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); | ||
1071 | hwc->state |= PERF_HES_STOPPED; | ||
1072 | |||
1073 | if (box->n_active == 0) { | ||
1074 | uncore_disable_box(box); | ||
1075 | uncore_pmu_cancel_hrtimer(box); | ||
1076 | } | ||
1077 | } | ||
1078 | |||
1079 | if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { | ||
1080 | /* | ||
1081 | * Drain the remaining delta count out of a event | ||
1082 | * that we are disabling: | ||
1083 | */ | ||
1084 | uncore_perf_event_update(box, event); | ||
1085 | hwc->state |= PERF_HES_UPTODATE; | ||
1086 | } | ||
1087 | } | ||
1088 | |||
1089 | static int uncore_pmu_event_add(struct perf_event *event, int flags) | ||
1090 | { | ||
1091 | struct intel_uncore_box *box = uncore_event_to_box(event); | ||
1092 | struct hw_perf_event *hwc = &event->hw; | ||
1093 | int assign[UNCORE_PMC_IDX_MAX]; | ||
1094 | int i, n, ret; | ||
1095 | |||
1096 | if (!box) | ||
1097 | return -ENODEV; | ||
1098 | |||
1099 | ret = n = uncore_collect_events(box, event, false); | ||
1100 | if (ret < 0) | ||
1101 | return ret; | ||
1102 | |||
1103 | hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; | ||
1104 | if (!(flags & PERF_EF_START)) | ||
1105 | hwc->state |= PERF_HES_ARCH; | ||
1106 | |||
1107 | ret = uncore_assign_events(box, assign, n); | ||
1108 | if (ret) | ||
1109 | return ret; | ||
1110 | |||
1111 | /* save events moving to new counters */ | ||
1112 | for (i = 0; i < box->n_events; i++) { | ||
1113 | event = box->event_list[i]; | ||
1114 | hwc = &event->hw; | ||
1115 | |||
1116 | if (hwc->idx == assign[i] && | ||
1117 | hwc->last_tag == box->tags[assign[i]]) | ||
1118 | continue; | ||
1119 | /* | ||
1120 | * Ensure we don't accidentally enable a stopped | ||
1121 | * counter simply because we rescheduled. | ||
1122 | */ | ||
1123 | if (hwc->state & PERF_HES_STOPPED) | ||
1124 | hwc->state |= PERF_HES_ARCH; | ||
1125 | |||
1126 | uncore_pmu_event_stop(event, PERF_EF_UPDATE); | ||
1127 | } | ||
1128 | |||
1129 | /* reprogram moved events into new counters */ | ||
1130 | for (i = 0; i < n; i++) { | ||
1131 | event = box->event_list[i]; | ||
1132 | hwc = &event->hw; | ||
1133 | |||
1134 | if (hwc->idx != assign[i] || | ||
1135 | hwc->last_tag != box->tags[assign[i]]) | ||
1136 | uncore_assign_hw_event(box, event, assign[i]); | ||
1137 | else if (i < box->n_events) | ||
1138 | continue; | ||
1139 | |||
1140 | if (hwc->state & PERF_HES_ARCH) | ||
1141 | continue; | ||
1142 | |||
1143 | uncore_pmu_event_start(event, 0); | ||
1144 | } | ||
1145 | box->n_events = n; | ||
1146 | |||
1147 | return 0; | ||
1148 | } | ||
1149 | |||
1150 | static void uncore_pmu_event_del(struct perf_event *event, int flags) | ||
1151 | { | ||
1152 | struct intel_uncore_box *box = uncore_event_to_box(event); | ||
1153 | int i; | ||
1154 | |||
1155 | uncore_pmu_event_stop(event, PERF_EF_UPDATE); | ||
1156 | |||
1157 | for (i = 0; i < box->n_events; i++) { | ||
1158 | if (event == box->event_list[i]) { | ||
1159 | uncore_put_event_constraint(box, event); | ||
1160 | |||
1161 | while (++i < box->n_events) | ||
1162 | box->event_list[i - 1] = box->event_list[i]; | ||
1163 | |||
1164 | --box->n_events; | ||
1165 | break; | ||
1166 | } | ||
1167 | } | ||
1168 | |||
1169 | event->hw.idx = -1; | ||
1170 | event->hw.last_tag = ~0ULL; | ||
1171 | } | ||
1172 | |||
1173 | static void uncore_pmu_event_read(struct perf_event *event) | ||
1174 | { | ||
1175 | struct intel_uncore_box *box = uncore_event_to_box(event); | ||
1176 | uncore_perf_event_update(box, event); | ||
1177 | } | ||
1178 | |||
1179 | /* | ||
1180 | * validation ensures the group can be loaded onto the | ||
1181 | * PMU if it was the only group available. | ||
1182 | */ | ||
1183 | static int uncore_validate_group(struct intel_uncore_pmu *pmu, | ||
1184 | struct perf_event *event) | ||
1185 | { | ||
1186 | struct perf_event *leader = event->group_leader; | ||
1187 | struct intel_uncore_box *fake_box; | ||
1188 | int ret = -EINVAL, n; | ||
1189 | |||
1190 | fake_box = uncore_alloc_box(pmu->type, smp_processor_id()); | ||
1191 | if (!fake_box) | ||
1192 | return -ENOMEM; | ||
1193 | |||
1194 | fake_box->pmu = pmu; | ||
1195 | /* | ||
1196 | * the event is not yet connected with its | ||
1197 | * siblings therefore we must first collect | ||
1198 | * existing siblings, then add the new event | ||
1199 | * before we can simulate the scheduling | ||
1200 | */ | ||
1201 | n = uncore_collect_events(fake_box, leader, true); | ||
1202 | if (n < 0) | ||
1203 | goto out; | ||
1204 | |||
1205 | fake_box->n_events = n; | ||
1206 | n = uncore_collect_events(fake_box, event, false); | ||
1207 | if (n < 0) | ||
1208 | goto out; | ||
1209 | |||
1210 | fake_box->n_events = n; | ||
1211 | |||
1212 | ret = uncore_assign_events(fake_box, NULL, n); | ||
1213 | out: | ||
1214 | kfree(fake_box); | ||
1215 | return ret; | ||
1216 | } | ||
1217 | |||
1218 | int uncore_pmu_event_init(struct perf_event *event) | ||
1219 | { | ||
1220 | struct intel_uncore_pmu *pmu; | ||
1221 | struct intel_uncore_box *box; | ||
1222 | struct hw_perf_event *hwc = &event->hw; | ||
1223 | int ret; | ||
1224 | |||
1225 | if (event->attr.type != event->pmu->type) | ||
1226 | return -ENOENT; | ||
1227 | |||
1228 | pmu = uncore_event_to_pmu(event); | ||
1229 | /* no device found for this pmu */ | ||
1230 | if (pmu->func_id < 0) | ||
1231 | return -ENOENT; | ||
1232 | |||
1233 | /* | ||
1234 | * Uncore PMU does measure at all privilege level all the time. | ||
1235 | * So it doesn't make sense to specify any exclude bits. | ||
1236 | */ | ||
1237 | if (event->attr.exclude_user || event->attr.exclude_kernel || | ||
1238 | event->attr.exclude_hv || event->attr.exclude_idle) | ||
1239 | return -EINVAL; | ||
1240 | |||
1241 | /* Sampling not supported yet */ | ||
1242 | if (hwc->sample_period) | ||
1243 | return -EINVAL; | ||
1244 | |||
1245 | /* | ||
1246 | * Place all uncore events for a particular physical package | ||
1247 | * onto a single cpu | ||
1248 | */ | ||
1249 | if (event->cpu < 0) | ||
1250 | return -EINVAL; | ||
1251 | box = uncore_pmu_to_box(pmu, event->cpu); | ||
1252 | if (!box || box->cpu < 0) | ||
1253 | return -EINVAL; | ||
1254 | event->cpu = box->cpu; | ||
1255 | |||
1256 | event->hw.idx = -1; | ||
1257 | event->hw.last_tag = ~0ULL; | ||
1258 | event->hw.extra_reg.idx = EXTRA_REG_NONE; | ||
1259 | |||
1260 | if (event->attr.config == UNCORE_FIXED_EVENT) { | ||
1261 | /* no fixed counter */ | ||
1262 | if (!pmu->type->fixed_ctl) | ||
1263 | return -EINVAL; | ||
1264 | /* | ||
1265 | * if there is only one fixed counter, only the first pmu | ||
1266 | * can access the fixed counter | ||
1267 | */ | ||
1268 | if (pmu->type->single_fixed && pmu->pmu_idx > 0) | ||
1269 | return -EINVAL; | ||
1270 | hwc->config = ~0ULL; | ||
1271 | } else { | ||
1272 | hwc->config = event->attr.config & pmu->type->event_mask; | ||
1273 | if (pmu->type->ops->hw_config) { | ||
1274 | ret = pmu->type->ops->hw_config(box, event); | ||
1275 | if (ret) | ||
1276 | return ret; | ||
1277 | } | ||
1278 | } | ||
1279 | |||
1280 | if (event->group_leader != event) | ||
1281 | ret = uncore_validate_group(pmu, event); | ||
1282 | else | ||
1283 | ret = 0; | ||
1284 | |||
1285 | return ret; | ||
1286 | } | ||
1287 | |||
1288 | static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu) | ||
1289 | { | ||
1290 | int ret; | ||
1291 | |||
1292 | pmu->pmu = (struct pmu) { | ||
1293 | .attr_groups = pmu->type->attr_groups, | ||
1294 | .task_ctx_nr = perf_invalid_context, | ||
1295 | .event_init = uncore_pmu_event_init, | ||
1296 | .add = uncore_pmu_event_add, | ||
1297 | .del = uncore_pmu_event_del, | ||
1298 | .start = uncore_pmu_event_start, | ||
1299 | .stop = uncore_pmu_event_stop, | ||
1300 | .read = uncore_pmu_event_read, | ||
1301 | }; | ||
1302 | |||
1303 | if (pmu->type->num_boxes == 1) { | ||
1304 | if (strlen(pmu->type->name) > 0) | ||
1305 | sprintf(pmu->name, "uncore_%s", pmu->type->name); | ||
1306 | else | ||
1307 | sprintf(pmu->name, "uncore"); | ||
1308 | } else { | ||
1309 | sprintf(pmu->name, "uncore_%s_%d", pmu->type->name, | ||
1310 | pmu->pmu_idx); | ||
1311 | } | ||
1312 | |||
1313 | ret = perf_pmu_register(&pmu->pmu, pmu->name, -1); | ||
1314 | return ret; | ||
1315 | } | ||
1316 | |||
1317 | static void __init uncore_type_exit(struct intel_uncore_type *type) | ||
1318 | { | ||
1319 | int i; | ||
1320 | |||
1321 | for (i = 0; i < type->num_boxes; i++) | ||
1322 | free_percpu(type->pmus[i].box); | ||
1323 | kfree(type->pmus); | ||
1324 | type->pmus = NULL; | ||
1325 | kfree(type->attr_groups[1]); | ||
1326 | type->attr_groups[1] = NULL; | ||
1327 | } | ||
1328 | |||
1329 | static void uncore_types_exit(struct intel_uncore_type **types) | ||
1330 | { | ||
1331 | int i; | ||
1332 | for (i = 0; types[i]; i++) | ||
1333 | uncore_type_exit(types[i]); | ||
1334 | } | ||
1335 | |||
1336 | static int __init uncore_type_init(struct intel_uncore_type *type) | ||
1337 | { | ||
1338 | struct intel_uncore_pmu *pmus; | ||
1339 | struct attribute_group *events_group; | ||
1340 | struct attribute **attrs; | ||
1341 | int i, j; | ||
1342 | |||
1343 | pmus = kzalloc(sizeof(*pmus) * type->num_boxes, GFP_KERNEL); | ||
1344 | if (!pmus) | ||
1345 | return -ENOMEM; | ||
1346 | |||
1347 | type->unconstrainted = (struct event_constraint) | ||
1348 | __EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1, | ||
1349 | 0, type->num_counters, 0); | ||
1350 | |||
1351 | for (i = 0; i < type->num_boxes; i++) { | ||
1352 | pmus[i].func_id = -1; | ||
1353 | pmus[i].pmu_idx = i; | ||
1354 | pmus[i].type = type; | ||
1355 | INIT_LIST_HEAD(&pmus[i].box_list); | ||
1356 | pmus[i].box = alloc_percpu(struct intel_uncore_box *); | ||
1357 | if (!pmus[i].box) | ||
1358 | goto fail; | ||
1359 | } | ||
1360 | |||
1361 | if (type->event_descs) { | ||
1362 | i = 0; | ||
1363 | while (type->event_descs[i].attr.attr.name) | ||
1364 | i++; | ||
1365 | |||
1366 | events_group = kzalloc(sizeof(struct attribute *) * (i + 1) + | ||
1367 | sizeof(*events_group), GFP_KERNEL); | ||
1368 | if (!events_group) | ||
1369 | goto fail; | ||
1370 | |||
1371 | attrs = (struct attribute **)(events_group + 1); | ||
1372 | events_group->name = "events"; | ||
1373 | events_group->attrs = attrs; | ||
1374 | |||
1375 | for (j = 0; j < i; j++) | ||
1376 | attrs[j] = &type->event_descs[j].attr.attr; | ||
1377 | |||
1378 | type->attr_groups[1] = events_group; | ||
1379 | } | ||
1380 | |||
1381 | type->pmus = pmus; | ||
1382 | return 0; | ||
1383 | fail: | ||
1384 | uncore_type_exit(type); | ||
1385 | return -ENOMEM; | ||
1386 | } | ||
1387 | |||
1388 | static int __init uncore_types_init(struct intel_uncore_type **types) | ||
1389 | { | ||
1390 | int i, ret; | ||
1391 | |||
1392 | for (i = 0; types[i]; i++) { | ||
1393 | ret = uncore_type_init(types[i]); | ||
1394 | if (ret) | ||
1395 | goto fail; | ||
1396 | } | ||
1397 | return 0; | ||
1398 | fail: | ||
1399 | while (--i >= 0) | ||
1400 | uncore_type_exit(types[i]); | ||
1401 | return ret; | ||
1402 | } | ||
1403 | |||
1404 | static struct pci_driver *uncore_pci_driver; | ||
1405 | static bool pcidrv_registered; | ||
1406 | |||
1407 | /* | ||
1408 | * add a pci uncore device | ||
1409 | */ | ||
1410 | static int __devinit uncore_pci_add(struct intel_uncore_type *type, | ||
1411 | struct pci_dev *pdev) | ||
1412 | { | ||
1413 | struct intel_uncore_pmu *pmu; | ||
1414 | struct intel_uncore_box *box; | ||
1415 | int i, phys_id; | ||
1416 | |||
1417 | phys_id = pcibus_to_physid[pdev->bus->number]; | ||
1418 | if (phys_id < 0) | ||
1419 | return -ENODEV; | ||
1420 | |||
1421 | box = uncore_alloc_box(type, 0); | ||
1422 | if (!box) | ||
1423 | return -ENOMEM; | ||
1424 | |||
1425 | /* | ||
1426 | * for performance monitoring unit with multiple boxes, | ||
1427 | * each box has a different function id. | ||
1428 | */ | ||
1429 | for (i = 0; i < type->num_boxes; i++) { | ||
1430 | pmu = &type->pmus[i]; | ||
1431 | if (pmu->func_id == pdev->devfn) | ||
1432 | break; | ||
1433 | if (pmu->func_id < 0) { | ||
1434 | pmu->func_id = pdev->devfn; | ||
1435 | break; | ||
1436 | } | ||
1437 | pmu = NULL; | ||
1438 | } | ||
1439 | |||
1440 | if (!pmu) { | ||
1441 | kfree(box); | ||
1442 | return -EINVAL; | ||
1443 | } | ||
1444 | |||
1445 | box->phys_id = phys_id; | ||
1446 | box->pci_dev = pdev; | ||
1447 | box->pmu = pmu; | ||
1448 | uncore_box_init(box); | ||
1449 | pci_set_drvdata(pdev, box); | ||
1450 | |||
1451 | raw_spin_lock(&uncore_box_lock); | ||
1452 | list_add_tail(&box->list, &pmu->box_list); | ||
1453 | raw_spin_unlock(&uncore_box_lock); | ||
1454 | |||
1455 | return 0; | ||
1456 | } | ||
1457 | |||
1458 | static void uncore_pci_remove(struct pci_dev *pdev) | ||
1459 | { | ||
1460 | struct intel_uncore_box *box = pci_get_drvdata(pdev); | ||
1461 | struct intel_uncore_pmu *pmu = box->pmu; | ||
1462 | int cpu, phys_id = pcibus_to_physid[pdev->bus->number]; | ||
1463 | |||
1464 | if (WARN_ON_ONCE(phys_id != box->phys_id)) | ||
1465 | return; | ||
1466 | |||
1467 | raw_spin_lock(&uncore_box_lock); | ||
1468 | list_del(&box->list); | ||
1469 | raw_spin_unlock(&uncore_box_lock); | ||
1470 | |||
1471 | for_each_possible_cpu(cpu) { | ||
1472 | if (*per_cpu_ptr(pmu->box, cpu) == box) { | ||
1473 | *per_cpu_ptr(pmu->box, cpu) = NULL; | ||
1474 | atomic_dec(&box->refcnt); | ||
1475 | } | ||
1476 | } | ||
1477 | |||
1478 | WARN_ON_ONCE(atomic_read(&box->refcnt) != 1); | ||
1479 | kfree(box); | ||
1480 | } | ||
1481 | |||
1482 | static int __devinit uncore_pci_probe(struct pci_dev *pdev, | ||
1483 | const struct pci_device_id *id) | ||
1484 | { | ||
1485 | struct intel_uncore_type *type; | ||
1486 | |||
1487 | type = (struct intel_uncore_type *)id->driver_data; | ||
1488 | return uncore_pci_add(type, pdev); | ||
1489 | } | ||
1490 | |||
1491 | static int __init uncore_pci_init(void) | ||
1492 | { | ||
1493 | int ret; | ||
1494 | |||
1495 | switch (boot_cpu_data.x86_model) { | ||
1496 | case 45: /* Sandy Bridge-EP */ | ||
1497 | pci_uncores = snbep_pci_uncores; | ||
1498 | uncore_pci_driver = &snbep_uncore_pci_driver; | ||
1499 | snbep_pci2phy_map_init(); | ||
1500 | break; | ||
1501 | default: | ||
1502 | return 0; | ||
1503 | } | ||
1504 | |||
1505 | ret = uncore_types_init(pci_uncores); | ||
1506 | if (ret) | ||
1507 | return ret; | ||
1508 | |||
1509 | uncore_pci_driver->probe = uncore_pci_probe; | ||
1510 | uncore_pci_driver->remove = uncore_pci_remove; | ||
1511 | |||
1512 | ret = pci_register_driver(uncore_pci_driver); | ||
1513 | if (ret == 0) | ||
1514 | pcidrv_registered = true; | ||
1515 | else | ||
1516 | uncore_types_exit(pci_uncores); | ||
1517 | |||
1518 | return ret; | ||
1519 | } | ||
1520 | |||
1521 | static void __init uncore_pci_exit(void) | ||
1522 | { | ||
1523 | if (pcidrv_registered) { | ||
1524 | pcidrv_registered = false; | ||
1525 | pci_unregister_driver(uncore_pci_driver); | ||
1526 | uncore_types_exit(pci_uncores); | ||
1527 | } | ||
1528 | } | ||
1529 | |||
1530 | static void __cpuinit uncore_cpu_dying(int cpu) | ||
1531 | { | ||
1532 | struct intel_uncore_type *type; | ||
1533 | struct intel_uncore_pmu *pmu; | ||
1534 | struct intel_uncore_box *box; | ||
1535 | int i, j; | ||
1536 | |||
1537 | for (i = 0; msr_uncores[i]; i++) { | ||
1538 | type = msr_uncores[i]; | ||
1539 | for (j = 0; j < type->num_boxes; j++) { | ||
1540 | pmu = &type->pmus[j]; | ||
1541 | box = *per_cpu_ptr(pmu->box, cpu); | ||
1542 | *per_cpu_ptr(pmu->box, cpu) = NULL; | ||
1543 | if (box && atomic_dec_and_test(&box->refcnt)) | ||
1544 | kfree(box); | ||
1545 | } | ||
1546 | } | ||
1547 | } | ||
1548 | |||
1549 | static int __cpuinit uncore_cpu_starting(int cpu) | ||
1550 | { | ||
1551 | struct intel_uncore_type *type; | ||
1552 | struct intel_uncore_pmu *pmu; | ||
1553 | struct intel_uncore_box *box, *exist; | ||
1554 | int i, j, k, phys_id; | ||
1555 | |||
1556 | phys_id = topology_physical_package_id(cpu); | ||
1557 | |||
1558 | for (i = 0; msr_uncores[i]; i++) { | ||
1559 | type = msr_uncores[i]; | ||
1560 | for (j = 0; j < type->num_boxes; j++) { | ||
1561 | pmu = &type->pmus[j]; | ||
1562 | box = *per_cpu_ptr(pmu->box, cpu); | ||
1563 | /* called by uncore_cpu_init? */ | ||
1564 | if (box && box->phys_id >= 0) { | ||
1565 | uncore_box_init(box); | ||
1566 | continue; | ||
1567 | } | ||
1568 | |||
1569 | for_each_online_cpu(k) { | ||
1570 | exist = *per_cpu_ptr(pmu->box, k); | ||
1571 | if (exist && exist->phys_id == phys_id) { | ||
1572 | atomic_inc(&exist->refcnt); | ||
1573 | *per_cpu_ptr(pmu->box, cpu) = exist; | ||
1574 | kfree(box); | ||
1575 | box = NULL; | ||
1576 | break; | ||
1577 | } | ||
1578 | } | ||
1579 | |||
1580 | if (box) { | ||
1581 | box->phys_id = phys_id; | ||
1582 | uncore_box_init(box); | ||
1583 | } | ||
1584 | } | ||
1585 | } | ||
1586 | return 0; | ||
1587 | } | ||
1588 | |||
1589 | static int __cpuinit uncore_cpu_prepare(int cpu, int phys_id) | ||
1590 | { | ||
1591 | struct intel_uncore_type *type; | ||
1592 | struct intel_uncore_pmu *pmu; | ||
1593 | struct intel_uncore_box *box; | ||
1594 | int i, j; | ||
1595 | |||
1596 | for (i = 0; msr_uncores[i]; i++) { | ||
1597 | type = msr_uncores[i]; | ||
1598 | for (j = 0; j < type->num_boxes; j++) { | ||
1599 | pmu = &type->pmus[j]; | ||
1600 | if (pmu->func_id < 0) | ||
1601 | pmu->func_id = j; | ||
1602 | |||
1603 | box = uncore_alloc_box(type, cpu); | ||
1604 | if (!box) | ||
1605 | return -ENOMEM; | ||
1606 | |||
1607 | box->pmu = pmu; | ||
1608 | box->phys_id = phys_id; | ||
1609 | *per_cpu_ptr(pmu->box, cpu) = box; | ||
1610 | } | ||
1611 | } | ||
1612 | return 0; | ||
1613 | } | ||
1614 | |||
1615 | static void __cpuinit uncore_change_context(struct intel_uncore_type **uncores, | ||
1616 | int old_cpu, int new_cpu) | ||
1617 | { | ||
1618 | struct intel_uncore_type *type; | ||
1619 | struct intel_uncore_pmu *pmu; | ||
1620 | struct intel_uncore_box *box; | ||
1621 | int i, j; | ||
1622 | |||
1623 | for (i = 0; uncores[i]; i++) { | ||
1624 | type = uncores[i]; | ||
1625 | for (j = 0; j < type->num_boxes; j++) { | ||
1626 | pmu = &type->pmus[j]; | ||
1627 | if (old_cpu < 0) | ||
1628 | box = uncore_pmu_to_box(pmu, new_cpu); | ||
1629 | else | ||
1630 | box = uncore_pmu_to_box(pmu, old_cpu); | ||
1631 | if (!box) | ||
1632 | continue; | ||
1633 | |||
1634 | if (old_cpu < 0) { | ||
1635 | WARN_ON_ONCE(box->cpu != -1); | ||
1636 | box->cpu = new_cpu; | ||
1637 | continue; | ||
1638 | } | ||
1639 | |||
1640 | WARN_ON_ONCE(box->cpu != old_cpu); | ||
1641 | if (new_cpu >= 0) { | ||
1642 | uncore_pmu_cancel_hrtimer(box); | ||
1643 | perf_pmu_migrate_context(&pmu->pmu, | ||
1644 | old_cpu, new_cpu); | ||
1645 | box->cpu = new_cpu; | ||
1646 | } else { | ||
1647 | box->cpu = -1; | ||
1648 | } | ||
1649 | } | ||
1650 | } | ||
1651 | } | ||
1652 | |||
1653 | static void __cpuinit uncore_event_exit_cpu(int cpu) | ||
1654 | { | ||
1655 | int i, phys_id, target; | ||
1656 | |||
1657 | /* if exiting cpu is used for collecting uncore events */ | ||
1658 | if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask)) | ||
1659 | return; | ||
1660 | |||
1661 | /* find a new cpu to collect uncore events */ | ||
1662 | phys_id = topology_physical_package_id(cpu); | ||
1663 | target = -1; | ||
1664 | for_each_online_cpu(i) { | ||
1665 | if (i == cpu) | ||
1666 | continue; | ||
1667 | if (phys_id == topology_physical_package_id(i)) { | ||
1668 | target = i; | ||
1669 | break; | ||
1670 | } | ||
1671 | } | ||
1672 | |||
1673 | /* migrate uncore events to the new cpu */ | ||
1674 | if (target >= 0) | ||
1675 | cpumask_set_cpu(target, &uncore_cpu_mask); | ||
1676 | |||
1677 | uncore_change_context(msr_uncores, cpu, target); | ||
1678 | uncore_change_context(pci_uncores, cpu, target); | ||
1679 | } | ||
1680 | |||
1681 | static void __cpuinit uncore_event_init_cpu(int cpu) | ||
1682 | { | ||
1683 | int i, phys_id; | ||
1684 | |||
1685 | phys_id = topology_physical_package_id(cpu); | ||
1686 | for_each_cpu(i, &uncore_cpu_mask) { | ||
1687 | if (phys_id == topology_physical_package_id(i)) | ||
1688 | return; | ||
1689 | } | ||
1690 | |||
1691 | cpumask_set_cpu(cpu, &uncore_cpu_mask); | ||
1692 | |||
1693 | uncore_change_context(msr_uncores, -1, cpu); | ||
1694 | uncore_change_context(pci_uncores, -1, cpu); | ||
1695 | } | ||
1696 | |||
1697 | static int __cpuinit uncore_cpu_notifier(struct notifier_block *self, | ||
1698 | unsigned long action, void *hcpu) | ||
1699 | { | ||
1700 | unsigned int cpu = (long)hcpu; | ||
1701 | |||
1702 | /* allocate/free data structure for uncore box */ | ||
1703 | switch (action & ~CPU_TASKS_FROZEN) { | ||
1704 | case CPU_UP_PREPARE: | ||
1705 | uncore_cpu_prepare(cpu, -1); | ||
1706 | break; | ||
1707 | case CPU_STARTING: | ||
1708 | uncore_cpu_starting(cpu); | ||
1709 | break; | ||
1710 | case CPU_UP_CANCELED: | ||
1711 | case CPU_DYING: | ||
1712 | uncore_cpu_dying(cpu); | ||
1713 | break; | ||
1714 | default: | ||
1715 | break; | ||
1716 | } | ||
1717 | |||
1718 | /* select the cpu that collects uncore events */ | ||
1719 | switch (action & ~CPU_TASKS_FROZEN) { | ||
1720 | case CPU_DOWN_FAILED: | ||
1721 | case CPU_STARTING: | ||
1722 | uncore_event_init_cpu(cpu); | ||
1723 | break; | ||
1724 | case CPU_DOWN_PREPARE: | ||
1725 | uncore_event_exit_cpu(cpu); | ||
1726 | break; | ||
1727 | default: | ||
1728 | break; | ||
1729 | } | ||
1730 | |||
1731 | return NOTIFY_OK; | ||
1732 | } | ||
1733 | |||
1734 | static struct notifier_block uncore_cpu_nb __cpuinitdata = { | ||
1735 | .notifier_call = uncore_cpu_notifier, | ||
1736 | /* | ||
1737 | * to migrate uncore events, our notifier should be executed | ||
1738 | * before perf core's notifier. | ||
1739 | */ | ||
1740 | .priority = CPU_PRI_PERF + 1, | ||
1741 | }; | ||
1742 | |||
1743 | static void __init uncore_cpu_setup(void *dummy) | ||
1744 | { | ||
1745 | uncore_cpu_starting(smp_processor_id()); | ||
1746 | } | ||
1747 | |||
1748 | static int __init uncore_cpu_init(void) | ||
1749 | { | ||
1750 | int ret, cpu, max_cores; | ||
1751 | |||
1752 | max_cores = boot_cpu_data.x86_max_cores; | ||
1753 | switch (boot_cpu_data.x86_model) { | ||
1754 | case 26: /* Nehalem */ | ||
1755 | case 30: | ||
1756 | case 37: /* Westmere */ | ||
1757 | case 44: | ||
1758 | msr_uncores = nhm_msr_uncores; | ||
1759 | break; | ||
1760 | case 42: /* Sandy Bridge */ | ||
1761 | if (snb_uncore_cbox.num_boxes > max_cores) | ||
1762 | snb_uncore_cbox.num_boxes = max_cores; | ||
1763 | msr_uncores = snb_msr_uncores; | ||
1764 | break; | ||
1765 | case 45: /* Sandy Birdge-EP */ | ||
1766 | if (snbep_uncore_cbox.num_boxes > max_cores) | ||
1767 | snbep_uncore_cbox.num_boxes = max_cores; | ||
1768 | msr_uncores = snbep_msr_uncores; | ||
1769 | break; | ||
1770 | default: | ||
1771 | return 0; | ||
1772 | } | ||
1773 | |||
1774 | ret = uncore_types_init(msr_uncores); | ||
1775 | if (ret) | ||
1776 | return ret; | ||
1777 | |||
1778 | get_online_cpus(); | ||
1779 | |||
1780 | for_each_online_cpu(cpu) { | ||
1781 | int i, phys_id = topology_physical_package_id(cpu); | ||
1782 | |||
1783 | for_each_cpu(i, &uncore_cpu_mask) { | ||
1784 | if (phys_id == topology_physical_package_id(i)) { | ||
1785 | phys_id = -1; | ||
1786 | break; | ||
1787 | } | ||
1788 | } | ||
1789 | if (phys_id < 0) | ||
1790 | continue; | ||
1791 | |||
1792 | uncore_cpu_prepare(cpu, phys_id); | ||
1793 | uncore_event_init_cpu(cpu); | ||
1794 | } | ||
1795 | on_each_cpu(uncore_cpu_setup, NULL, 1); | ||
1796 | |||
1797 | register_cpu_notifier(&uncore_cpu_nb); | ||
1798 | |||
1799 | put_online_cpus(); | ||
1800 | |||
1801 | return 0; | ||
1802 | } | ||
1803 | |||
1804 | static int __init uncore_pmus_register(void) | ||
1805 | { | ||
1806 | struct intel_uncore_pmu *pmu; | ||
1807 | struct intel_uncore_type *type; | ||
1808 | int i, j; | ||
1809 | |||
1810 | for (i = 0; msr_uncores[i]; i++) { | ||
1811 | type = msr_uncores[i]; | ||
1812 | for (j = 0; j < type->num_boxes; j++) { | ||
1813 | pmu = &type->pmus[j]; | ||
1814 | uncore_pmu_register(pmu); | ||
1815 | } | ||
1816 | } | ||
1817 | |||
1818 | for (i = 0; pci_uncores[i]; i++) { | ||
1819 | type = pci_uncores[i]; | ||
1820 | for (j = 0; j < type->num_boxes; j++) { | ||
1821 | pmu = &type->pmus[j]; | ||
1822 | uncore_pmu_register(pmu); | ||
1823 | } | ||
1824 | } | ||
1825 | |||
1826 | return 0; | ||
1827 | } | ||
1828 | |||
1829 | static int __init intel_uncore_init(void) | ||
1830 | { | ||
1831 | int ret; | ||
1832 | |||
1833 | if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) | ||
1834 | return -ENODEV; | ||
1835 | |||
1836 | ret = uncore_pci_init(); | ||
1837 | if (ret) | ||
1838 | goto fail; | ||
1839 | ret = uncore_cpu_init(); | ||
1840 | if (ret) { | ||
1841 | uncore_pci_exit(); | ||
1842 | goto fail; | ||
1843 | } | ||
1844 | |||
1845 | uncore_pmus_register(); | ||
1846 | return 0; | ||
1847 | fail: | ||
1848 | return ret; | ||
1849 | } | ||
1850 | device_initcall(intel_uncore_init); | ||
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h new file mode 100644 index 000000000000..b13e9ea81def --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h | |||
@@ -0,0 +1,424 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/slab.h> | ||
3 | #include <linux/pci.h> | ||
4 | #include <linux/perf_event.h> | ||
5 | #include "perf_event.h" | ||
6 | |||
7 | #define UNCORE_PMU_NAME_LEN 32 | ||
8 | #define UNCORE_BOX_HASH_SIZE 8 | ||
9 | |||
10 | #define UNCORE_PMU_HRTIMER_INTERVAL (60 * NSEC_PER_SEC) | ||
11 | |||
12 | #define UNCORE_FIXED_EVENT 0xff | ||
13 | #define UNCORE_PMC_IDX_MAX_GENERIC 8 | ||
14 | #define UNCORE_PMC_IDX_FIXED UNCORE_PMC_IDX_MAX_GENERIC | ||
15 | #define UNCORE_PMC_IDX_MAX (UNCORE_PMC_IDX_FIXED + 1) | ||
16 | |||
17 | #define UNCORE_EVENT_CONSTRAINT(c, n) EVENT_CONSTRAINT(c, n, 0xff) | ||
18 | |||
19 | /* SNB event control */ | ||
20 | #define SNB_UNC_CTL_EV_SEL_MASK 0x000000ff | ||
21 | #define SNB_UNC_CTL_UMASK_MASK 0x0000ff00 | ||
22 | #define SNB_UNC_CTL_EDGE_DET (1 << 18) | ||
23 | #define SNB_UNC_CTL_EN (1 << 22) | ||
24 | #define SNB_UNC_CTL_INVERT (1 << 23) | ||
25 | #define SNB_UNC_CTL_CMASK_MASK 0x1f000000 | ||
26 | #define NHM_UNC_CTL_CMASK_MASK 0xff000000 | ||
27 | #define NHM_UNC_FIXED_CTR_CTL_EN (1 << 0) | ||
28 | |||
29 | #define SNB_UNC_RAW_EVENT_MASK (SNB_UNC_CTL_EV_SEL_MASK | \ | ||
30 | SNB_UNC_CTL_UMASK_MASK | \ | ||
31 | SNB_UNC_CTL_EDGE_DET | \ | ||
32 | SNB_UNC_CTL_INVERT | \ | ||
33 | SNB_UNC_CTL_CMASK_MASK) | ||
34 | |||
35 | #define NHM_UNC_RAW_EVENT_MASK (SNB_UNC_CTL_EV_SEL_MASK | \ | ||
36 | SNB_UNC_CTL_UMASK_MASK | \ | ||
37 | SNB_UNC_CTL_EDGE_DET | \ | ||
38 | SNB_UNC_CTL_INVERT | \ | ||
39 | NHM_UNC_CTL_CMASK_MASK) | ||
40 | |||
41 | /* SNB global control register */ | ||
42 | #define SNB_UNC_PERF_GLOBAL_CTL 0x391 | ||
43 | #define SNB_UNC_FIXED_CTR_CTRL 0x394 | ||
44 | #define SNB_UNC_FIXED_CTR 0x395 | ||
45 | |||
46 | /* SNB uncore global control */ | ||
47 | #define SNB_UNC_GLOBAL_CTL_CORE_ALL ((1 << 4) - 1) | ||
48 | #define SNB_UNC_GLOBAL_CTL_EN (1 << 29) | ||
49 | |||
50 | /* SNB Cbo register */ | ||
51 | #define SNB_UNC_CBO_0_PERFEVTSEL0 0x700 | ||
52 | #define SNB_UNC_CBO_0_PER_CTR0 0x706 | ||
53 | #define SNB_UNC_CBO_MSR_OFFSET 0x10 | ||
54 | |||
55 | /* NHM global control register */ | ||
56 | #define NHM_UNC_PERF_GLOBAL_CTL 0x391 | ||
57 | #define NHM_UNC_FIXED_CTR 0x394 | ||
58 | #define NHM_UNC_FIXED_CTR_CTRL 0x395 | ||
59 | |||
60 | /* NHM uncore global control */ | ||
61 | #define NHM_UNC_GLOBAL_CTL_EN_PC_ALL ((1ULL << 8) - 1) | ||
62 | #define NHM_UNC_GLOBAL_CTL_EN_FC (1ULL << 32) | ||
63 | |||
64 | /* NHM uncore register */ | ||
65 | #define NHM_UNC_PERFEVTSEL0 0x3c0 | ||
66 | #define NHM_UNC_UNCORE_PMC0 0x3b0 | ||
67 | |||
68 | /* SNB-EP Box level control */ | ||
69 | #define SNBEP_PMON_BOX_CTL_RST_CTRL (1 << 0) | ||
70 | #define SNBEP_PMON_BOX_CTL_RST_CTRS (1 << 1) | ||
71 | #define SNBEP_PMON_BOX_CTL_FRZ (1 << 8) | ||
72 | #define SNBEP_PMON_BOX_CTL_FRZ_EN (1 << 16) | ||
73 | #define SNBEP_PMON_BOX_CTL_INT (SNBEP_PMON_BOX_CTL_RST_CTRL | \ | ||
74 | SNBEP_PMON_BOX_CTL_RST_CTRS | \ | ||
75 | SNBEP_PMON_BOX_CTL_FRZ_EN) | ||
76 | /* SNB-EP event control */ | ||
77 | #define SNBEP_PMON_CTL_EV_SEL_MASK 0x000000ff | ||
78 | #define SNBEP_PMON_CTL_UMASK_MASK 0x0000ff00 | ||
79 | #define SNBEP_PMON_CTL_RST (1 << 17) | ||
80 | #define SNBEP_PMON_CTL_EDGE_DET (1 << 18) | ||
81 | #define SNBEP_PMON_CTL_EV_SEL_EXT (1 << 21) /* only for QPI */ | ||
82 | #define SNBEP_PMON_CTL_EN (1 << 22) | ||
83 | #define SNBEP_PMON_CTL_INVERT (1 << 23) | ||
84 | #define SNBEP_PMON_CTL_TRESH_MASK 0xff000000 | ||
85 | #define SNBEP_PMON_RAW_EVENT_MASK (SNBEP_PMON_CTL_EV_SEL_MASK | \ | ||
86 | SNBEP_PMON_CTL_UMASK_MASK | \ | ||
87 | SNBEP_PMON_CTL_EDGE_DET | \ | ||
88 | SNBEP_PMON_CTL_INVERT | \ | ||
89 | SNBEP_PMON_CTL_TRESH_MASK) | ||
90 | |||
91 | /* SNB-EP Ubox event control */ | ||
92 | #define SNBEP_U_MSR_PMON_CTL_TRESH_MASK 0x1f000000 | ||
93 | #define SNBEP_U_MSR_PMON_RAW_EVENT_MASK \ | ||
94 | (SNBEP_PMON_CTL_EV_SEL_MASK | \ | ||
95 | SNBEP_PMON_CTL_UMASK_MASK | \ | ||
96 | SNBEP_PMON_CTL_EDGE_DET | \ | ||
97 | SNBEP_PMON_CTL_INVERT | \ | ||
98 | SNBEP_U_MSR_PMON_CTL_TRESH_MASK) | ||
99 | |||
100 | #define SNBEP_CBO_PMON_CTL_TID_EN (1 << 19) | ||
101 | #define SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK (SNBEP_PMON_RAW_EVENT_MASK | \ | ||
102 | SNBEP_CBO_PMON_CTL_TID_EN) | ||
103 | |||
104 | /* SNB-EP PCU event control */ | ||
105 | #define SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK 0x0000c000 | ||
106 | #define SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK 0x1f000000 | ||
107 | #define SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT (1 << 30) | ||
108 | #define SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET (1 << 31) | ||
109 | #define SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK \ | ||
110 | (SNBEP_PMON_CTL_EV_SEL_MASK | \ | ||
111 | SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \ | ||
112 | SNBEP_PMON_CTL_EDGE_DET | \ | ||
113 | SNBEP_PMON_CTL_INVERT | \ | ||
114 | SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \ | ||
115 | SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \ | ||
116 | SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET) | ||
117 | |||
118 | /* SNB-EP pci control register */ | ||
119 | #define SNBEP_PCI_PMON_BOX_CTL 0xf4 | ||
120 | #define SNBEP_PCI_PMON_CTL0 0xd8 | ||
121 | /* SNB-EP pci counter register */ | ||
122 | #define SNBEP_PCI_PMON_CTR0 0xa0 | ||
123 | |||
124 | /* SNB-EP home agent register */ | ||
125 | #define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH0 0x40 | ||
126 | #define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH1 0x44 | ||
127 | #define SNBEP_HA_PCI_PMON_BOX_OPCODEMATCH 0x48 | ||
128 | /* SNB-EP memory controller register */ | ||
129 | #define SNBEP_MC_CHy_PCI_PMON_FIXED_CTL 0xf0 | ||
130 | #define SNBEP_MC_CHy_PCI_PMON_FIXED_CTR 0xd0 | ||
131 | /* SNB-EP QPI register */ | ||
132 | #define SNBEP_Q_Py_PCI_PMON_PKT_MATCH0 0x228 | ||
133 | #define SNBEP_Q_Py_PCI_PMON_PKT_MATCH1 0x22c | ||
134 | #define SNBEP_Q_Py_PCI_PMON_PKT_MASK0 0x238 | ||
135 | #define SNBEP_Q_Py_PCI_PMON_PKT_MASK1 0x23c | ||
136 | |||
137 | /* SNB-EP Ubox register */ | ||
138 | #define SNBEP_U_MSR_PMON_CTR0 0xc16 | ||
139 | #define SNBEP_U_MSR_PMON_CTL0 0xc10 | ||
140 | |||
141 | #define SNBEP_U_MSR_PMON_UCLK_FIXED_CTL 0xc08 | ||
142 | #define SNBEP_U_MSR_PMON_UCLK_FIXED_CTR 0xc09 | ||
143 | |||
144 | /* SNB-EP Cbo register */ | ||
145 | #define SNBEP_C0_MSR_PMON_CTR0 0xd16 | ||
146 | #define SNBEP_C0_MSR_PMON_CTL0 0xd10 | ||
147 | #define SNBEP_C0_MSR_PMON_BOX_CTL 0xd04 | ||
148 | #define SNBEP_C0_MSR_PMON_BOX_FILTER 0xd14 | ||
149 | #define SNBEP_CB0_MSR_PMON_BOX_FILTER_MASK 0xfffffc1f | ||
150 | #define SNBEP_CBO_MSR_OFFSET 0x20 | ||
151 | |||
152 | /* SNB-EP PCU register */ | ||
153 | #define SNBEP_PCU_MSR_PMON_CTR0 0xc36 | ||
154 | #define SNBEP_PCU_MSR_PMON_CTL0 0xc30 | ||
155 | #define SNBEP_PCU_MSR_PMON_BOX_CTL 0xc24 | ||
156 | #define SNBEP_PCU_MSR_PMON_BOX_FILTER 0xc34 | ||
157 | #define SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK 0xffffffff | ||
158 | #define SNBEP_PCU_MSR_CORE_C3_CTR 0x3fc | ||
159 | #define SNBEP_PCU_MSR_CORE_C6_CTR 0x3fd | ||
160 | |||
161 | struct intel_uncore_ops; | ||
162 | struct intel_uncore_pmu; | ||
163 | struct intel_uncore_box; | ||
164 | struct uncore_event_desc; | ||
165 | |||
166 | struct intel_uncore_type { | ||
167 | const char *name; | ||
168 | int num_counters; | ||
169 | int num_boxes; | ||
170 | int perf_ctr_bits; | ||
171 | int fixed_ctr_bits; | ||
172 | unsigned perf_ctr; | ||
173 | unsigned event_ctl; | ||
174 | unsigned event_mask; | ||
175 | unsigned fixed_ctr; | ||
176 | unsigned fixed_ctl; | ||
177 | unsigned box_ctl; | ||
178 | unsigned msr_offset; | ||
179 | unsigned num_shared_regs:8; | ||
180 | unsigned single_fixed:1; | ||
181 | struct event_constraint unconstrainted; | ||
182 | struct event_constraint *constraints; | ||
183 | struct intel_uncore_pmu *pmus; | ||
184 | struct intel_uncore_ops *ops; | ||
185 | struct uncore_event_desc *event_descs; | ||
186 | const struct attribute_group *attr_groups[3]; | ||
187 | }; | ||
188 | |||
189 | #define format_group attr_groups[0] | ||
190 | |||
191 | struct intel_uncore_ops { | ||
192 | void (*init_box)(struct intel_uncore_box *); | ||
193 | void (*disable_box)(struct intel_uncore_box *); | ||
194 | void (*enable_box)(struct intel_uncore_box *); | ||
195 | void (*disable_event)(struct intel_uncore_box *, struct perf_event *); | ||
196 | void (*enable_event)(struct intel_uncore_box *, struct perf_event *); | ||
197 | u64 (*read_counter)(struct intel_uncore_box *, struct perf_event *); | ||
198 | int (*hw_config)(struct intel_uncore_box *, struct perf_event *); | ||
199 | struct event_constraint *(*get_constraint)(struct intel_uncore_box *, | ||
200 | struct perf_event *); | ||
201 | void (*put_constraint)(struct intel_uncore_box *, struct perf_event *); | ||
202 | }; | ||
203 | |||
204 | struct intel_uncore_pmu { | ||
205 | struct pmu pmu; | ||
206 | char name[UNCORE_PMU_NAME_LEN]; | ||
207 | int pmu_idx; | ||
208 | int func_id; | ||
209 | struct intel_uncore_type *type; | ||
210 | struct intel_uncore_box ** __percpu box; | ||
211 | struct list_head box_list; | ||
212 | }; | ||
213 | |||
214 | struct intel_uncore_extra_reg { | ||
215 | raw_spinlock_t lock; | ||
216 | u64 config1; | ||
217 | atomic_t ref; | ||
218 | }; | ||
219 | |||
220 | struct intel_uncore_box { | ||
221 | int phys_id; | ||
222 | int n_active; /* number of active events */ | ||
223 | int n_events; | ||
224 | int cpu; /* cpu to collect events */ | ||
225 | unsigned long flags; | ||
226 | atomic_t refcnt; | ||
227 | struct perf_event *events[UNCORE_PMC_IDX_MAX]; | ||
228 | struct perf_event *event_list[UNCORE_PMC_IDX_MAX]; | ||
229 | unsigned long active_mask[BITS_TO_LONGS(UNCORE_PMC_IDX_MAX)]; | ||
230 | u64 tags[UNCORE_PMC_IDX_MAX]; | ||
231 | struct pci_dev *pci_dev; | ||
232 | struct intel_uncore_pmu *pmu; | ||
233 | struct hrtimer hrtimer; | ||
234 | struct list_head list; | ||
235 | struct intel_uncore_extra_reg shared_regs[0]; | ||
236 | }; | ||
237 | |||
238 | #define UNCORE_BOX_FLAG_INITIATED 0 | ||
239 | |||
240 | struct uncore_event_desc { | ||
241 | struct kobj_attribute attr; | ||
242 | const char *config; | ||
243 | }; | ||
244 | |||
245 | #define INTEL_UNCORE_EVENT_DESC(_name, _config) \ | ||
246 | { \ | ||
247 | .attr = __ATTR(_name, 0444, uncore_event_show, NULL), \ | ||
248 | .config = _config, \ | ||
249 | } | ||
250 | |||
251 | #define DEFINE_UNCORE_FORMAT_ATTR(_var, _name, _format) \ | ||
252 | static ssize_t __uncore_##_var##_show(struct kobject *kobj, \ | ||
253 | struct kobj_attribute *attr, \ | ||
254 | char *page) \ | ||
255 | { \ | ||
256 | BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ | ||
257 | return sprintf(page, _format "\n"); \ | ||
258 | } \ | ||
259 | static struct kobj_attribute format_attr_##_var = \ | ||
260 | __ATTR(_name, 0444, __uncore_##_var##_show, NULL) | ||
261 | |||
262 | |||
263 | static ssize_t uncore_event_show(struct kobject *kobj, | ||
264 | struct kobj_attribute *attr, char *buf) | ||
265 | { | ||
266 | struct uncore_event_desc *event = | ||
267 | container_of(attr, struct uncore_event_desc, attr); | ||
268 | return sprintf(buf, "%s", event->config); | ||
269 | } | ||
270 | |||
271 | static inline unsigned uncore_pci_box_ctl(struct intel_uncore_box *box) | ||
272 | { | ||
273 | return box->pmu->type->box_ctl; | ||
274 | } | ||
275 | |||
276 | static inline unsigned uncore_pci_fixed_ctl(struct intel_uncore_box *box) | ||
277 | { | ||
278 | return box->pmu->type->fixed_ctl; | ||
279 | } | ||
280 | |||
281 | static inline unsigned uncore_pci_fixed_ctr(struct intel_uncore_box *box) | ||
282 | { | ||
283 | return box->pmu->type->fixed_ctr; | ||
284 | } | ||
285 | |||
286 | static inline | ||
287 | unsigned uncore_pci_event_ctl(struct intel_uncore_box *box, int idx) | ||
288 | { | ||
289 | return idx * 4 + box->pmu->type->event_ctl; | ||
290 | } | ||
291 | |||
292 | static inline | ||
293 | unsigned uncore_pci_perf_ctr(struct intel_uncore_box *box, int idx) | ||
294 | { | ||
295 | return idx * 8 + box->pmu->type->perf_ctr; | ||
296 | } | ||
297 | |||
298 | static inline | ||
299 | unsigned uncore_msr_box_ctl(struct intel_uncore_box *box) | ||
300 | { | ||
301 | if (!box->pmu->type->box_ctl) | ||
302 | return 0; | ||
303 | return box->pmu->type->box_ctl + | ||
304 | box->pmu->type->msr_offset * box->pmu->pmu_idx; | ||
305 | } | ||
306 | |||
307 | static inline | ||
308 | unsigned uncore_msr_fixed_ctl(struct intel_uncore_box *box) | ||
309 | { | ||
310 | if (!box->pmu->type->fixed_ctl) | ||
311 | return 0; | ||
312 | return box->pmu->type->fixed_ctl + | ||
313 | box->pmu->type->msr_offset * box->pmu->pmu_idx; | ||
314 | } | ||
315 | |||
316 | static inline | ||
317 | unsigned uncore_msr_fixed_ctr(struct intel_uncore_box *box) | ||
318 | { | ||
319 | return box->pmu->type->fixed_ctr + | ||
320 | box->pmu->type->msr_offset * box->pmu->pmu_idx; | ||
321 | } | ||
322 | |||
323 | static inline | ||
324 | unsigned uncore_msr_event_ctl(struct intel_uncore_box *box, int idx) | ||
325 | { | ||
326 | return idx + box->pmu->type->event_ctl + | ||
327 | box->pmu->type->msr_offset * box->pmu->pmu_idx; | ||
328 | } | ||
329 | |||
330 | static inline | ||
331 | unsigned uncore_msr_perf_ctr(struct intel_uncore_box *box, int idx) | ||
332 | { | ||
333 | return idx + box->pmu->type->perf_ctr + | ||
334 | box->pmu->type->msr_offset * box->pmu->pmu_idx; | ||
335 | } | ||
336 | |||
337 | static inline | ||
338 | unsigned uncore_fixed_ctl(struct intel_uncore_box *box) | ||
339 | { | ||
340 | if (box->pci_dev) | ||
341 | return uncore_pci_fixed_ctl(box); | ||
342 | else | ||
343 | return uncore_msr_fixed_ctl(box); | ||
344 | } | ||
345 | |||
346 | static inline | ||
347 | unsigned uncore_fixed_ctr(struct intel_uncore_box *box) | ||
348 | { | ||
349 | if (box->pci_dev) | ||
350 | return uncore_pci_fixed_ctr(box); | ||
351 | else | ||
352 | return uncore_msr_fixed_ctr(box); | ||
353 | } | ||
354 | |||
355 | static inline | ||
356 | unsigned uncore_event_ctl(struct intel_uncore_box *box, int idx) | ||
357 | { | ||
358 | if (box->pci_dev) | ||
359 | return uncore_pci_event_ctl(box, idx); | ||
360 | else | ||
361 | return uncore_msr_event_ctl(box, idx); | ||
362 | } | ||
363 | |||
364 | static inline | ||
365 | unsigned uncore_perf_ctr(struct intel_uncore_box *box, int idx) | ||
366 | { | ||
367 | if (box->pci_dev) | ||
368 | return uncore_pci_perf_ctr(box, idx); | ||
369 | else | ||
370 | return uncore_msr_perf_ctr(box, idx); | ||
371 | } | ||
372 | |||
373 | static inline int uncore_perf_ctr_bits(struct intel_uncore_box *box) | ||
374 | { | ||
375 | return box->pmu->type->perf_ctr_bits; | ||
376 | } | ||
377 | |||
378 | static inline int uncore_fixed_ctr_bits(struct intel_uncore_box *box) | ||
379 | { | ||
380 | return box->pmu->type->fixed_ctr_bits; | ||
381 | } | ||
382 | |||
383 | static inline int uncore_num_counters(struct intel_uncore_box *box) | ||
384 | { | ||
385 | return box->pmu->type->num_counters; | ||
386 | } | ||
387 | |||
388 | static inline void uncore_disable_box(struct intel_uncore_box *box) | ||
389 | { | ||
390 | if (box->pmu->type->ops->disable_box) | ||
391 | box->pmu->type->ops->disable_box(box); | ||
392 | } | ||
393 | |||
394 | static inline void uncore_enable_box(struct intel_uncore_box *box) | ||
395 | { | ||
396 | if (box->pmu->type->ops->enable_box) | ||
397 | box->pmu->type->ops->enable_box(box); | ||
398 | } | ||
399 | |||
400 | static inline void uncore_disable_event(struct intel_uncore_box *box, | ||
401 | struct perf_event *event) | ||
402 | { | ||
403 | box->pmu->type->ops->disable_event(box, event); | ||
404 | } | ||
405 | |||
406 | static inline void uncore_enable_event(struct intel_uncore_box *box, | ||
407 | struct perf_event *event) | ||
408 | { | ||
409 | box->pmu->type->ops->enable_event(box, event); | ||
410 | } | ||
411 | |||
412 | static inline u64 uncore_read_counter(struct intel_uncore_box *box, | ||
413 | struct perf_event *event) | ||
414 | { | ||
415 | return box->pmu->type->ops->read_counter(box, event); | ||
416 | } | ||
417 | |||
418 | static inline void uncore_box_init(struct intel_uncore_box *box) | ||
419 | { | ||
420 | if (!test_and_set_bit(UNCORE_BOX_FLAG_INITIATED, &box->flags)) { | ||
421 | if (box->pmu->type->ops->init_box) | ||
422 | box->pmu->type->ops->init_box(box); | ||
423 | } | ||
424 | } | ||
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c index 47124a73dd73..92c7e39a079f 100644 --- a/arch/x86/kernel/cpu/perf_event_p4.c +++ b/arch/x86/kernel/cpu/perf_event_p4.c | |||
@@ -895,8 +895,8 @@ static void p4_pmu_disable_pebs(void) | |||
895 | * So at moment let leave metrics turned on forever -- it's | 895 | * So at moment let leave metrics turned on forever -- it's |
896 | * ok for now but need to be revisited! | 896 | * ok for now but need to be revisited! |
897 | * | 897 | * |
898 | * (void)checking_wrmsrl(MSR_IA32_PEBS_ENABLE, (u64)0); | 898 | * (void)wrmsrl_safe(MSR_IA32_PEBS_ENABLE, (u64)0); |
899 | * (void)checking_wrmsrl(MSR_P4_PEBS_MATRIX_VERT, (u64)0); | 899 | * (void)wrmsrl_safe(MSR_P4_PEBS_MATRIX_VERT, (u64)0); |
900 | */ | 900 | */ |
901 | } | 901 | } |
902 | 902 | ||
@@ -909,7 +909,7 @@ static inline void p4_pmu_disable_event(struct perf_event *event) | |||
909 | * state we need to clear P4_CCCR_OVF, otherwise interrupt get | 909 | * state we need to clear P4_CCCR_OVF, otherwise interrupt get |
910 | * asserted again and again | 910 | * asserted again and again |
911 | */ | 911 | */ |
912 | (void)checking_wrmsrl(hwc->config_base, | 912 | (void)wrmsrl_safe(hwc->config_base, |
913 | (u64)(p4_config_unpack_cccr(hwc->config)) & | 913 | (u64)(p4_config_unpack_cccr(hwc->config)) & |
914 | ~P4_CCCR_ENABLE & ~P4_CCCR_OVF & ~P4_CCCR_RESERVED); | 914 | ~P4_CCCR_ENABLE & ~P4_CCCR_OVF & ~P4_CCCR_RESERVED); |
915 | } | 915 | } |
@@ -943,8 +943,8 @@ static void p4_pmu_enable_pebs(u64 config) | |||
943 | 943 | ||
944 | bind = &p4_pebs_bind_map[idx]; | 944 | bind = &p4_pebs_bind_map[idx]; |
945 | 945 | ||
946 | (void)checking_wrmsrl(MSR_IA32_PEBS_ENABLE, (u64)bind->metric_pebs); | 946 | (void)wrmsrl_safe(MSR_IA32_PEBS_ENABLE, (u64)bind->metric_pebs); |
947 | (void)checking_wrmsrl(MSR_P4_PEBS_MATRIX_VERT, (u64)bind->metric_vert); | 947 | (void)wrmsrl_safe(MSR_P4_PEBS_MATRIX_VERT, (u64)bind->metric_vert); |
948 | } | 948 | } |
949 | 949 | ||
950 | static void p4_pmu_enable_event(struct perf_event *event) | 950 | static void p4_pmu_enable_event(struct perf_event *event) |
@@ -978,8 +978,8 @@ static void p4_pmu_enable_event(struct perf_event *event) | |||
978 | */ | 978 | */ |
979 | p4_pmu_enable_pebs(hwc->config); | 979 | p4_pmu_enable_pebs(hwc->config); |
980 | 980 | ||
981 | (void)checking_wrmsrl(escr_addr, escr_conf); | 981 | (void)wrmsrl_safe(escr_addr, escr_conf); |
982 | (void)checking_wrmsrl(hwc->config_base, | 982 | (void)wrmsrl_safe(hwc->config_base, |
983 | (cccr & ~P4_CCCR_RESERVED) | P4_CCCR_ENABLE); | 983 | (cccr & ~P4_CCCR_RESERVED) | P4_CCCR_ENABLE); |
984 | } | 984 | } |
985 | 985 | ||
@@ -1325,7 +1325,7 @@ __init int p4_pmu_init(void) | |||
1325 | unsigned int low, high; | 1325 | unsigned int low, high; |
1326 | 1326 | ||
1327 | /* If we get stripped -- indexing fails */ | 1327 | /* If we get stripped -- indexing fails */ |
1328 | BUILD_BUG_ON(ARCH_P4_MAX_CCCR > X86_PMC_MAX_GENERIC); | 1328 | BUILD_BUG_ON(ARCH_P4_MAX_CCCR > INTEL_PMC_MAX_GENERIC); |
1329 | 1329 | ||
1330 | rdmsr(MSR_IA32_MISC_ENABLE, low, high); | 1330 | rdmsr(MSR_IA32_MISC_ENABLE, low, high); |
1331 | if (!(low & (1 << 7))) { | 1331 | if (!(low & (1 << 7))) { |
diff --git a/arch/x86/kernel/cpu/perf_event_p6.c b/arch/x86/kernel/cpu/perf_event_p6.c index 32bcfc7dd230..e4dd0f7a0453 100644 --- a/arch/x86/kernel/cpu/perf_event_p6.c +++ b/arch/x86/kernel/cpu/perf_event_p6.c | |||
@@ -71,7 +71,7 @@ p6_pmu_disable_event(struct perf_event *event) | |||
71 | if (cpuc->enabled) | 71 | if (cpuc->enabled) |
72 | val |= ARCH_PERFMON_EVENTSEL_ENABLE; | 72 | val |= ARCH_PERFMON_EVENTSEL_ENABLE; |
73 | 73 | ||
74 | (void)checking_wrmsrl(hwc->config_base, val); | 74 | (void)wrmsrl_safe(hwc->config_base, val); |
75 | } | 75 | } |
76 | 76 | ||
77 | static void p6_pmu_enable_event(struct perf_event *event) | 77 | static void p6_pmu_enable_event(struct perf_event *event) |
@@ -84,7 +84,7 @@ static void p6_pmu_enable_event(struct perf_event *event) | |||
84 | if (cpuc->enabled) | 84 | if (cpuc->enabled) |
85 | val |= ARCH_PERFMON_EVENTSEL_ENABLE; | 85 | val |= ARCH_PERFMON_EVENTSEL_ENABLE; |
86 | 86 | ||
87 | (void)checking_wrmsrl(hwc->config_base, val); | 87 | (void)wrmsrl_safe(hwc->config_base, val); |
88 | } | 88 | } |
89 | 89 | ||
90 | PMU_FORMAT_ATTR(event, "config:0-7" ); | 90 | PMU_FORMAT_ATTR(event, "config:0-7" ); |
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index fbdfc6917180..1649cf899ad6 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c | |||
@@ -87,6 +87,7 @@ | |||
87 | #include <asm/microcode.h> | 87 | #include <asm/microcode.h> |
88 | #include <asm/processor.h> | 88 | #include <asm/processor.h> |
89 | #include <asm/cpu_device_id.h> | 89 | #include <asm/cpu_device_id.h> |
90 | #include <asm/perf_event.h> | ||
90 | 91 | ||
91 | MODULE_DESCRIPTION("Microcode Update Driver"); | 92 | MODULE_DESCRIPTION("Microcode Update Driver"); |
92 | MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); | 93 | MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); |
@@ -277,7 +278,6 @@ static int reload_for_cpu(int cpu) | |||
277 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 278 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
278 | int err = 0; | 279 | int err = 0; |
279 | 280 | ||
280 | mutex_lock(µcode_mutex); | ||
281 | if (uci->valid) { | 281 | if (uci->valid) { |
282 | enum ucode_state ustate; | 282 | enum ucode_state ustate; |
283 | 283 | ||
@@ -288,7 +288,6 @@ static int reload_for_cpu(int cpu) | |||
288 | if (ustate == UCODE_ERROR) | 288 | if (ustate == UCODE_ERROR) |
289 | err = -EINVAL; | 289 | err = -EINVAL; |
290 | } | 290 | } |
291 | mutex_unlock(µcode_mutex); | ||
292 | 291 | ||
293 | return err; | 292 | return err; |
294 | } | 293 | } |
@@ -298,19 +297,31 @@ static ssize_t reload_store(struct device *dev, | |||
298 | const char *buf, size_t size) | 297 | const char *buf, size_t size) |
299 | { | 298 | { |
300 | unsigned long val; | 299 | unsigned long val; |
301 | int cpu = dev->id; | 300 | int cpu; |
302 | ssize_t ret = 0; | 301 | ssize_t ret = 0, tmp_ret; |
303 | 302 | ||
304 | ret = kstrtoul(buf, 0, &val); | 303 | ret = kstrtoul(buf, 0, &val); |
305 | if (ret) | 304 | if (ret) |
306 | return ret; | 305 | return ret; |
307 | 306 | ||
308 | if (val == 1) { | 307 | if (val != 1) |
309 | get_online_cpus(); | 308 | return size; |
310 | if (cpu_online(cpu)) | 309 | |
311 | ret = reload_for_cpu(cpu); | 310 | get_online_cpus(); |
312 | put_online_cpus(); | 311 | mutex_lock(µcode_mutex); |
312 | for_each_online_cpu(cpu) { | ||
313 | tmp_ret = reload_for_cpu(cpu); | ||
314 | if (tmp_ret != 0) | ||
315 | pr_warn("Error reloading microcode on CPU %d\n", cpu); | ||
316 | |||
317 | /* save retval of the first encountered reload error */ | ||
318 | if (!ret) | ||
319 | ret = tmp_ret; | ||
313 | } | 320 | } |
321 | if (!ret) | ||
322 | perf_check_microcode(); | ||
323 | mutex_unlock(µcode_mutex); | ||
324 | put_online_cpus(); | ||
314 | 325 | ||
315 | if (!ret) | 326 | if (!ret) |
316 | ret = size; | 327 | ret = size; |
@@ -339,7 +350,6 @@ static DEVICE_ATTR(version, 0400, version_show, NULL); | |||
339 | static DEVICE_ATTR(processor_flags, 0400, pf_show, NULL); | 350 | static DEVICE_ATTR(processor_flags, 0400, pf_show, NULL); |
340 | 351 | ||
341 | static struct attribute *mc_default_attrs[] = { | 352 | static struct attribute *mc_default_attrs[] = { |
342 | &dev_attr_reload.attr, | ||
343 | &dev_attr_version.attr, | 353 | &dev_attr_version.attr, |
344 | &dev_attr_processor_flags.attr, | 354 | &dev_attr_processor_flags.attr, |
345 | NULL | 355 | NULL |
@@ -516,6 +526,16 @@ static const struct x86_cpu_id microcode_id[] = { | |||
516 | MODULE_DEVICE_TABLE(x86cpu, microcode_id); | 526 | MODULE_DEVICE_TABLE(x86cpu, microcode_id); |
517 | #endif | 527 | #endif |
518 | 528 | ||
529 | static struct attribute *cpu_root_microcode_attrs[] = { | ||
530 | &dev_attr_reload.attr, | ||
531 | NULL | ||
532 | }; | ||
533 | |||
534 | static struct attribute_group cpu_root_microcode_group = { | ||
535 | .name = "microcode", | ||
536 | .attrs = cpu_root_microcode_attrs, | ||
537 | }; | ||
538 | |||
519 | static int __init microcode_init(void) | 539 | static int __init microcode_init(void) |
520 | { | 540 | { |
521 | struct cpuinfo_x86 *c = &cpu_data(0); | 541 | struct cpuinfo_x86 *c = &cpu_data(0); |
@@ -540,16 +560,25 @@ static int __init microcode_init(void) | |||
540 | mutex_lock(µcode_mutex); | 560 | mutex_lock(µcode_mutex); |
541 | 561 | ||
542 | error = subsys_interface_register(&mc_cpu_interface); | 562 | error = subsys_interface_register(&mc_cpu_interface); |
543 | 563 | if (!error) | |
564 | perf_check_microcode(); | ||
544 | mutex_unlock(µcode_mutex); | 565 | mutex_unlock(µcode_mutex); |
545 | put_online_cpus(); | 566 | put_online_cpus(); |
546 | 567 | ||
547 | if (error) | 568 | if (error) |
548 | goto out_pdev; | 569 | goto out_pdev; |
549 | 570 | ||
571 | error = sysfs_create_group(&cpu_subsys.dev_root->kobj, | ||
572 | &cpu_root_microcode_group); | ||
573 | |||
574 | if (error) { | ||
575 | pr_err("Error creating microcode group!\n"); | ||
576 | goto out_driver; | ||
577 | } | ||
578 | |||
550 | error = microcode_dev_init(); | 579 | error = microcode_dev_init(); |
551 | if (error) | 580 | if (error) |
552 | goto out_driver; | 581 | goto out_ucode_group; |
553 | 582 | ||
554 | register_syscore_ops(&mc_syscore_ops); | 583 | register_syscore_ops(&mc_syscore_ops); |
555 | register_hotcpu_notifier(&mc_cpu_notifier); | 584 | register_hotcpu_notifier(&mc_cpu_notifier); |
@@ -559,7 +588,11 @@ static int __init microcode_init(void) | |||
559 | 588 | ||
560 | return 0; | 589 | return 0; |
561 | 590 | ||
562 | out_driver: | 591 | out_ucode_group: |
592 | sysfs_remove_group(&cpu_subsys.dev_root->kobj, | ||
593 | &cpu_root_microcode_group); | ||
594 | |||
595 | out_driver: | ||
563 | get_online_cpus(); | 596 | get_online_cpus(); |
564 | mutex_lock(µcode_mutex); | 597 | mutex_lock(µcode_mutex); |
565 | 598 | ||
@@ -568,7 +601,7 @@ out_driver: | |||
568 | mutex_unlock(µcode_mutex); | 601 | mutex_unlock(µcode_mutex); |
569 | put_online_cpus(); | 602 | put_online_cpus(); |
570 | 603 | ||
571 | out_pdev: | 604 | out_pdev: |
572 | platform_device_unregister(microcode_pdev); | 605 | platform_device_unregister(microcode_pdev); |
573 | return error; | 606 | return error; |
574 | 607 | ||
@@ -584,6 +617,9 @@ static void __exit microcode_exit(void) | |||
584 | unregister_hotcpu_notifier(&mc_cpu_notifier); | 617 | unregister_hotcpu_notifier(&mc_cpu_notifier); |
585 | unregister_syscore_ops(&mc_syscore_ops); | 618 | unregister_syscore_ops(&mc_syscore_ops); |
586 | 619 | ||
620 | sysfs_remove_group(&cpu_subsys.dev_root->kobj, | ||
621 | &cpu_root_microcode_group); | ||
622 | |||
587 | get_online_cpus(); | 623 | get_online_cpus(); |
588 | mutex_lock(µcode_mutex); | 624 | mutex_lock(µcode_mutex); |
589 | 625 | ||
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 9ce885996fd7..17fff18a1031 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c | |||
@@ -352,9 +352,7 @@ struct pv_cpu_ops pv_cpu_ops = { | |||
352 | #endif | 352 | #endif |
353 | .wbinvd = native_wbinvd, | 353 | .wbinvd = native_wbinvd, |
354 | .read_msr = native_read_msr_safe, | 354 | .read_msr = native_read_msr_safe, |
355 | .rdmsr_regs = native_rdmsr_safe_regs, | ||
356 | .write_msr = native_write_msr_safe, | 355 | .write_msr = native_write_msr_safe, |
357 | .wrmsr_regs = native_wrmsr_safe_regs, | ||
358 | .read_tsc = native_read_tsc, | 356 | .read_tsc = native_read_tsc, |
359 | .read_pmc = native_read_pmc, | 357 | .read_pmc = native_read_pmc, |
360 | .read_tscp = native_read_tscp, | 358 | .read_tscp = native_read_tscp, |
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 61cdf7fdf099..3e215ba68766 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
@@ -466,7 +466,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) | |||
466 | task->thread.gs = addr; | 466 | task->thread.gs = addr; |
467 | if (doit) { | 467 | if (doit) { |
468 | load_gs_index(0); | 468 | load_gs_index(0); |
469 | ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr); | 469 | ret = wrmsrl_safe(MSR_KERNEL_GS_BASE, addr); |
470 | } | 470 | } |
471 | } | 471 | } |
472 | put_cpu(); | 472 | put_cpu(); |
@@ -494,7 +494,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) | |||
494 | /* set the selector to 0 to not confuse | 494 | /* set the selector to 0 to not confuse |
495 | __switch_to */ | 495 | __switch_to */ |
496 | loadsegment(fs, 0); | 496 | loadsegment(fs, 0); |
497 | ret = checking_wrmsrl(MSR_FS_BASE, addr); | 497 | ret = wrmsrl_safe(MSR_FS_BASE, addr); |
498 | } | 498 | } |
499 | } | 499 | } |
500 | put_cpu(); | 500 | put_cpu(); |
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index dc4e910a7d96..36fd42091fa7 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c | |||
@@ -409,9 +409,10 @@ static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, | |||
409 | * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. | 409 | * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. |
410 | * @mm: the probed address space. | 410 | * @mm: the probed address space. |
411 | * @arch_uprobe: the probepoint information. | 411 | * @arch_uprobe: the probepoint information. |
412 | * @addr: virtual address at which to install the probepoint | ||
412 | * Return 0 on success or a -ve number on error. | 413 | * Return 0 on success or a -ve number on error. |
413 | */ | 414 | */ |
414 | int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm) | 415 | int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long addr) |
415 | { | 416 | { |
416 | int ret; | 417 | int ret; |
417 | struct insn insn; | 418 | struct insn insn; |
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 2e88438ffd83..9b7ec1150ab0 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c | |||
@@ -80,10 +80,10 @@ static inline struct kvm_pmc *get_fixed_pmc_idx(struct kvm_pmu *pmu, int idx) | |||
80 | 80 | ||
81 | static struct kvm_pmc *global_idx_to_pmc(struct kvm_pmu *pmu, int idx) | 81 | static struct kvm_pmc *global_idx_to_pmc(struct kvm_pmu *pmu, int idx) |
82 | { | 82 | { |
83 | if (idx < X86_PMC_IDX_FIXED) | 83 | if (idx < INTEL_PMC_IDX_FIXED) |
84 | return get_gp_pmc(pmu, MSR_P6_EVNTSEL0 + idx, MSR_P6_EVNTSEL0); | 84 | return get_gp_pmc(pmu, MSR_P6_EVNTSEL0 + idx, MSR_P6_EVNTSEL0); |
85 | else | 85 | else |
86 | return get_fixed_pmc_idx(pmu, idx - X86_PMC_IDX_FIXED); | 86 | return get_fixed_pmc_idx(pmu, idx - INTEL_PMC_IDX_FIXED); |
87 | } | 87 | } |
88 | 88 | ||
89 | void kvm_deliver_pmi(struct kvm_vcpu *vcpu) | 89 | void kvm_deliver_pmi(struct kvm_vcpu *vcpu) |
@@ -291,7 +291,7 @@ static void reprogram_idx(struct kvm_pmu *pmu, int idx) | |||
291 | if (pmc_is_gp(pmc)) | 291 | if (pmc_is_gp(pmc)) |
292 | reprogram_gp_counter(pmc, pmc->eventsel); | 292 | reprogram_gp_counter(pmc, pmc->eventsel); |
293 | else { | 293 | else { |
294 | int fidx = idx - X86_PMC_IDX_FIXED; | 294 | int fidx = idx - INTEL_PMC_IDX_FIXED; |
295 | reprogram_fixed_counter(pmc, | 295 | reprogram_fixed_counter(pmc, |
296 | fixed_en_pmi(pmu->fixed_ctr_ctrl, fidx), fidx); | 296 | fixed_en_pmi(pmu->fixed_ctr_ctrl, fidx), fidx); |
297 | } | 297 | } |
@@ -452,7 +452,7 @@ void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu) | |||
452 | return; | 452 | return; |
453 | 453 | ||
454 | pmu->nr_arch_gp_counters = min((int)(entry->eax >> 8) & 0xff, | 454 | pmu->nr_arch_gp_counters = min((int)(entry->eax >> 8) & 0xff, |
455 | X86_PMC_MAX_GENERIC); | 455 | INTEL_PMC_MAX_GENERIC); |
456 | pmu->counter_bitmask[KVM_PMC_GP] = | 456 | pmu->counter_bitmask[KVM_PMC_GP] = |
457 | ((u64)1 << ((entry->eax >> 16) & 0xff)) - 1; | 457 | ((u64)1 << ((entry->eax >> 16) & 0xff)) - 1; |
458 | bitmap_len = (entry->eax >> 24) & 0xff; | 458 | bitmap_len = (entry->eax >> 24) & 0xff; |
@@ -462,13 +462,13 @@ void kvm_pmu_cpuid_update(struct kvm_vcpu *vcpu) | |||
462 | pmu->nr_arch_fixed_counters = 0; | 462 | pmu->nr_arch_fixed_counters = 0; |
463 | } else { | 463 | } else { |
464 | pmu->nr_arch_fixed_counters = min((int)(entry->edx & 0x1f), | 464 | pmu->nr_arch_fixed_counters = min((int)(entry->edx & 0x1f), |
465 | X86_PMC_MAX_FIXED); | 465 | INTEL_PMC_MAX_FIXED); |
466 | pmu->counter_bitmask[KVM_PMC_FIXED] = | 466 | pmu->counter_bitmask[KVM_PMC_FIXED] = |
467 | ((u64)1 << ((entry->edx >> 5) & 0xff)) - 1; | 467 | ((u64)1 << ((entry->edx >> 5) & 0xff)) - 1; |
468 | } | 468 | } |
469 | 469 | ||
470 | pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) | | 470 | pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) | |
471 | (((1ull << pmu->nr_arch_fixed_counters) - 1) << X86_PMC_IDX_FIXED); | 471 | (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED); |
472 | pmu->global_ctrl_mask = ~pmu->global_ctrl; | 472 | pmu->global_ctrl_mask = ~pmu->global_ctrl; |
473 | } | 473 | } |
474 | 474 | ||
@@ -478,15 +478,15 @@ void kvm_pmu_init(struct kvm_vcpu *vcpu) | |||
478 | struct kvm_pmu *pmu = &vcpu->arch.pmu; | 478 | struct kvm_pmu *pmu = &vcpu->arch.pmu; |
479 | 479 | ||
480 | memset(pmu, 0, sizeof(*pmu)); | 480 | memset(pmu, 0, sizeof(*pmu)); |
481 | for (i = 0; i < X86_PMC_MAX_GENERIC; i++) { | 481 | for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) { |
482 | pmu->gp_counters[i].type = KVM_PMC_GP; | 482 | pmu->gp_counters[i].type = KVM_PMC_GP; |
483 | pmu->gp_counters[i].vcpu = vcpu; | 483 | pmu->gp_counters[i].vcpu = vcpu; |
484 | pmu->gp_counters[i].idx = i; | 484 | pmu->gp_counters[i].idx = i; |
485 | } | 485 | } |
486 | for (i = 0; i < X86_PMC_MAX_FIXED; i++) { | 486 | for (i = 0; i < INTEL_PMC_MAX_FIXED; i++) { |
487 | pmu->fixed_counters[i].type = KVM_PMC_FIXED; | 487 | pmu->fixed_counters[i].type = KVM_PMC_FIXED; |
488 | pmu->fixed_counters[i].vcpu = vcpu; | 488 | pmu->fixed_counters[i].vcpu = vcpu; |
489 | pmu->fixed_counters[i].idx = i + X86_PMC_IDX_FIXED; | 489 | pmu->fixed_counters[i].idx = i + INTEL_PMC_IDX_FIXED; |
490 | } | 490 | } |
491 | init_irq_work(&pmu->irq_work, trigger_pmi); | 491 | init_irq_work(&pmu->irq_work, trigger_pmi); |
492 | kvm_pmu_cpuid_update(vcpu); | 492 | kvm_pmu_cpuid_update(vcpu); |
@@ -498,13 +498,13 @@ void kvm_pmu_reset(struct kvm_vcpu *vcpu) | |||
498 | int i; | 498 | int i; |
499 | 499 | ||
500 | irq_work_sync(&pmu->irq_work); | 500 | irq_work_sync(&pmu->irq_work); |
501 | for (i = 0; i < X86_PMC_MAX_GENERIC; i++) { | 501 | for (i = 0; i < INTEL_PMC_MAX_GENERIC; i++) { |
502 | struct kvm_pmc *pmc = &pmu->gp_counters[i]; | 502 | struct kvm_pmc *pmc = &pmu->gp_counters[i]; |
503 | stop_counter(pmc); | 503 | stop_counter(pmc); |
504 | pmc->counter = pmc->eventsel = 0; | 504 | pmc->counter = pmc->eventsel = 0; |
505 | } | 505 | } |
506 | 506 | ||
507 | for (i = 0; i < X86_PMC_MAX_FIXED; i++) | 507 | for (i = 0; i < INTEL_PMC_MAX_FIXED; i++) |
508 | stop_counter(&pmu->fixed_counters[i]); | 508 | stop_counter(&pmu->fixed_counters[i]); |
509 | 509 | ||
510 | pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status = | 510 | pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status = |
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index 911d2641f14c..62d02e3c3ed6 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h | |||
@@ -710,16 +710,6 @@ TRACE_EVENT(kvm_skinit, | |||
710 | __entry->rip, __entry->slb) | 710 | __entry->rip, __entry->slb) |
711 | ); | 711 | ); |
712 | 712 | ||
713 | #define __print_insn(insn, ilen) ({ \ | ||
714 | int i; \ | ||
715 | const char *ret = p->buffer + p->len; \ | ||
716 | \ | ||
717 | for (i = 0; i < ilen; ++i) \ | ||
718 | trace_seq_printf(p, " %02x", insn[i]); \ | ||
719 | trace_seq_printf(p, "%c", 0); \ | ||
720 | ret; \ | ||
721 | }) | ||
722 | |||
723 | #define KVM_EMUL_INSN_F_CR0_PE (1 << 0) | 713 | #define KVM_EMUL_INSN_F_CR0_PE (1 << 0) |
724 | #define KVM_EMUL_INSN_F_EFL_VM (1 << 1) | 714 | #define KVM_EMUL_INSN_F_EFL_VM (1 << 1) |
725 | #define KVM_EMUL_INSN_F_CS_D (1 << 2) | 715 | #define KVM_EMUL_INSN_F_CS_D (1 << 2) |
@@ -786,7 +776,7 @@ TRACE_EVENT(kvm_emulate_insn, | |||
786 | 776 | ||
787 | TP_printk("%x:%llx:%s (%s)%s", | 777 | TP_printk("%x:%llx:%s (%s)%s", |
788 | __entry->csbase, __entry->rip, | 778 | __entry->csbase, __entry->rip, |
789 | __print_insn(__entry->insn, __entry->len), | 779 | __print_hex(__entry->insn, __entry->len), |
790 | __print_symbolic(__entry->flags, | 780 | __print_symbolic(__entry->flags, |
791 | kvm_trace_symbol_emul_flags), | 781 | kvm_trace_symbol_emul_flags), |
792 | __entry->failed ? " failed" : "" | 782 | __entry->failed ? " failed" : "" |
diff --git a/arch/x86/lib/msr-reg-export.c b/arch/x86/lib/msr-reg-export.c index a311cc59b65d..8d6ef78b5d01 100644 --- a/arch/x86/lib/msr-reg-export.c +++ b/arch/x86/lib/msr-reg-export.c | |||
@@ -1,5 +1,5 @@ | |||
1 | #include <linux/module.h> | 1 | #include <linux/module.h> |
2 | #include <asm/msr.h> | 2 | #include <asm/msr.h> |
3 | 3 | ||
4 | EXPORT_SYMBOL(native_rdmsr_safe_regs); | 4 | EXPORT_SYMBOL(rdmsr_safe_regs); |
5 | EXPORT_SYMBOL(native_wrmsr_safe_regs); | 5 | EXPORT_SYMBOL(wrmsr_safe_regs); |
diff --git a/arch/x86/lib/msr-reg.S b/arch/x86/lib/msr-reg.S index 69fa10623f21..f6d13eefad10 100644 --- a/arch/x86/lib/msr-reg.S +++ b/arch/x86/lib/msr-reg.S | |||
@@ -6,13 +6,13 @@ | |||
6 | 6 | ||
7 | #ifdef CONFIG_X86_64 | 7 | #ifdef CONFIG_X86_64 |
8 | /* | 8 | /* |
9 | * int native_{rdmsr,wrmsr}_safe_regs(u32 gprs[8]); | 9 | * int {rdmsr,wrmsr}_safe_regs(u32 gprs[8]); |
10 | * | 10 | * |
11 | * reg layout: u32 gprs[eax, ecx, edx, ebx, esp, ebp, esi, edi] | 11 | * reg layout: u32 gprs[eax, ecx, edx, ebx, esp, ebp, esi, edi] |
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | .macro op_safe_regs op | 14 | .macro op_safe_regs op |
15 | ENTRY(native_\op\()_safe_regs) | 15 | ENTRY(\op\()_safe_regs) |
16 | CFI_STARTPROC | 16 | CFI_STARTPROC |
17 | pushq_cfi %rbx | 17 | pushq_cfi %rbx |
18 | pushq_cfi %rbp | 18 | pushq_cfi %rbp |
@@ -45,13 +45,13 @@ ENTRY(native_\op\()_safe_regs) | |||
45 | 45 | ||
46 | _ASM_EXTABLE(1b, 3b) | 46 | _ASM_EXTABLE(1b, 3b) |
47 | CFI_ENDPROC | 47 | CFI_ENDPROC |
48 | ENDPROC(native_\op\()_safe_regs) | 48 | ENDPROC(\op\()_safe_regs) |
49 | .endm | 49 | .endm |
50 | 50 | ||
51 | #else /* X86_32 */ | 51 | #else /* X86_32 */ |
52 | 52 | ||
53 | .macro op_safe_regs op | 53 | .macro op_safe_regs op |
54 | ENTRY(native_\op\()_safe_regs) | 54 | ENTRY(\op\()_safe_regs) |
55 | CFI_STARTPROC | 55 | CFI_STARTPROC |
56 | pushl_cfi %ebx | 56 | pushl_cfi %ebx |
57 | pushl_cfi %ebp | 57 | pushl_cfi %ebp |
@@ -92,7 +92,7 @@ ENTRY(native_\op\()_safe_regs) | |||
92 | 92 | ||
93 | _ASM_EXTABLE(1b, 3b) | 93 | _ASM_EXTABLE(1b, 3b) |
94 | CFI_ENDPROC | 94 | CFI_ENDPROC |
95 | ENDPROC(native_\op\()_safe_regs) | 95 | ENDPROC(\op\()_safe_regs) |
96 | .endm | 96 | .endm |
97 | 97 | ||
98 | #endif | 98 | #endif |
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 303f08637826..b2b94438ff05 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c | |||
@@ -312,7 +312,7 @@ static int op_amd_fill_in_addresses(struct op_msrs * const msrs) | |||
312 | goto fail; | 312 | goto fail; |
313 | } | 313 | } |
314 | /* both registers must be reserved */ | 314 | /* both registers must be reserved */ |
315 | if (num_counters == AMD64_NUM_COUNTERS_F15H) { | 315 | if (num_counters == AMD64_NUM_COUNTERS_CORE) { |
316 | msrs->counters[i].addr = MSR_F15H_PERF_CTR + (i << 1); | 316 | msrs->counters[i].addr = MSR_F15H_PERF_CTR + (i << 1); |
317 | msrs->controls[i].addr = MSR_F15H_PERF_CTL + (i << 1); | 317 | msrs->controls[i].addr = MSR_F15H_PERF_CTL + (i << 1); |
318 | } else { | 318 | } else { |
@@ -514,7 +514,7 @@ static int op_amd_init(struct oprofile_operations *ops) | |||
514 | ops->create_files = setup_ibs_files; | 514 | ops->create_files = setup_ibs_files; |
515 | 515 | ||
516 | if (boot_cpu_data.x86 == 0x15) { | 516 | if (boot_cpu_data.x86 == 0x15) { |
517 | num_counters = AMD64_NUM_COUNTERS_F15H; | 517 | num_counters = AMD64_NUM_COUNTERS_CORE; |
518 | } else { | 518 | } else { |
519 | num_counters = AMD64_NUM_COUNTERS; | 519 | num_counters = AMD64_NUM_COUNTERS; |
520 | } | 520 | } |
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c index 66e6d9359826..0faad646f5fd 100644 --- a/arch/x86/vdso/vdso32-setup.c +++ b/arch/x86/vdso/vdso32-setup.c | |||
@@ -205,9 +205,9 @@ void syscall32_cpu_init(void) | |||
205 | { | 205 | { |
206 | /* Load these always in case some future AMD CPU supports | 206 | /* Load these always in case some future AMD CPU supports |
207 | SYSENTER from compat mode too. */ | 207 | SYSENTER from compat mode too. */ |
208 | checking_wrmsrl(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS); | 208 | wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS); |
209 | checking_wrmsrl(MSR_IA32_SYSENTER_ESP, 0ULL); | 209 | wrmsrl_safe(MSR_IA32_SYSENTER_ESP, 0ULL); |
210 | checking_wrmsrl(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target); | 210 | wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)ia32_sysenter_target); |
211 | 211 | ||
212 | wrmsrl(MSR_CSTAR, ia32_cstar_target); | 212 | wrmsrl(MSR_CSTAR, ia32_cstar_target); |
213 | } | 213 | } |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index ff962d4b821e..ed7d54985d0c 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -1124,9 +1124,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { | |||
1124 | .wbinvd = native_wbinvd, | 1124 | .wbinvd = native_wbinvd, |
1125 | 1125 | ||
1126 | .read_msr = native_read_msr_safe, | 1126 | .read_msr = native_read_msr_safe, |
1127 | .rdmsr_regs = native_rdmsr_safe_regs, | ||
1128 | .write_msr = xen_write_msr_safe, | 1127 | .write_msr = xen_write_msr_safe, |
1129 | .wrmsr_regs = native_wrmsr_safe_regs, | ||
1130 | 1128 | ||
1131 | .read_tsc = native_read_tsc, | 1129 | .read_tsc = native_read_tsc, |
1132 | .read_pmc = native_read_pmc, | 1130 | .read_pmc = native_read_pmc, |
diff --git a/drivers/oprofile/oprofile_perf.c b/drivers/oprofile/oprofile_perf.c index efc4b7f308cf..f3cfa0b9adfa 100644 --- a/drivers/oprofile/oprofile_perf.c +++ b/drivers/oprofile/oprofile_perf.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2010 ARM Ltd. | 2 | * Copyright 2010 ARM Ltd. |
3 | * Copyright 2012 Advanced Micro Devices, Inc., Robert Richter | ||
3 | * | 4 | * |
4 | * Perf-events backend for OProfile. | 5 | * Perf-events backend for OProfile. |
5 | */ | 6 | */ |
@@ -25,7 +26,7 @@ static int oprofile_perf_enabled; | |||
25 | static DEFINE_MUTEX(oprofile_perf_mutex); | 26 | static DEFINE_MUTEX(oprofile_perf_mutex); |
26 | 27 | ||
27 | static struct op_counter_config *counter_config; | 28 | static struct op_counter_config *counter_config; |
28 | static struct perf_event **perf_events[NR_CPUS]; | 29 | static DEFINE_PER_CPU(struct perf_event **, perf_events); |
29 | static int num_counters; | 30 | static int num_counters; |
30 | 31 | ||
31 | /* | 32 | /* |
@@ -38,7 +39,7 @@ static void op_overflow_handler(struct perf_event *event, | |||
38 | u32 cpu = smp_processor_id(); | 39 | u32 cpu = smp_processor_id(); |
39 | 40 | ||
40 | for (id = 0; id < num_counters; ++id) | 41 | for (id = 0; id < num_counters; ++id) |
41 | if (perf_events[cpu][id] == event) | 42 | if (per_cpu(perf_events, cpu)[id] == event) |
42 | break; | 43 | break; |
43 | 44 | ||
44 | if (id != num_counters) | 45 | if (id != num_counters) |
@@ -74,7 +75,7 @@ static int op_create_counter(int cpu, int event) | |||
74 | { | 75 | { |
75 | struct perf_event *pevent; | 76 | struct perf_event *pevent; |
76 | 77 | ||
77 | if (!counter_config[event].enabled || perf_events[cpu][event]) | 78 | if (!counter_config[event].enabled || per_cpu(perf_events, cpu)[event]) |
78 | return 0; | 79 | return 0; |
79 | 80 | ||
80 | pevent = perf_event_create_kernel_counter(&counter_config[event].attr, | 81 | pevent = perf_event_create_kernel_counter(&counter_config[event].attr, |
@@ -91,18 +92,18 @@ static int op_create_counter(int cpu, int event) | |||
91 | return -EBUSY; | 92 | return -EBUSY; |
92 | } | 93 | } |
93 | 94 | ||
94 | perf_events[cpu][event] = pevent; | 95 | per_cpu(perf_events, cpu)[event] = pevent; |
95 | 96 | ||
96 | return 0; | 97 | return 0; |
97 | } | 98 | } |
98 | 99 | ||
99 | static void op_destroy_counter(int cpu, int event) | 100 | static void op_destroy_counter(int cpu, int event) |
100 | { | 101 | { |
101 | struct perf_event *pevent = perf_events[cpu][event]; | 102 | struct perf_event *pevent = per_cpu(perf_events, cpu)[event]; |
102 | 103 | ||
103 | if (pevent) { | 104 | if (pevent) { |
104 | perf_event_release_kernel(pevent); | 105 | perf_event_release_kernel(pevent); |
105 | perf_events[cpu][event] = NULL; | 106 | per_cpu(perf_events, cpu)[event] = NULL; |
106 | } | 107 | } |
107 | } | 108 | } |
108 | 109 | ||
@@ -257,12 +258,12 @@ void oprofile_perf_exit(void) | |||
257 | 258 | ||
258 | for_each_possible_cpu(cpu) { | 259 | for_each_possible_cpu(cpu) { |
259 | for (id = 0; id < num_counters; ++id) { | 260 | for (id = 0; id < num_counters; ++id) { |
260 | event = perf_events[cpu][id]; | 261 | event = per_cpu(perf_events, cpu)[id]; |
261 | if (event) | 262 | if (event) |
262 | perf_event_release_kernel(event); | 263 | perf_event_release_kernel(event); |
263 | } | 264 | } |
264 | 265 | ||
265 | kfree(perf_events[cpu]); | 266 | kfree(per_cpu(perf_events, cpu)); |
266 | } | 267 | } |
267 | 268 | ||
268 | kfree(counter_config); | 269 | kfree(counter_config); |
@@ -277,8 +278,6 @@ int __init oprofile_perf_init(struct oprofile_operations *ops) | |||
277 | if (ret) | 278 | if (ret) |
278 | return ret; | 279 | return ret; |
279 | 280 | ||
280 | memset(&perf_events, 0, sizeof(perf_events)); | ||
281 | |||
282 | num_counters = perf_num_counters(); | 281 | num_counters = perf_num_counters(); |
283 | if (num_counters <= 0) { | 282 | if (num_counters <= 0) { |
284 | pr_info("oprofile: no performance counters\n"); | 283 | pr_info("oprofile: no performance counters\n"); |
@@ -298,9 +297,9 @@ int __init oprofile_perf_init(struct oprofile_operations *ops) | |||
298 | } | 297 | } |
299 | 298 | ||
300 | for_each_possible_cpu(cpu) { | 299 | for_each_possible_cpu(cpu) { |
301 | perf_events[cpu] = kcalloc(num_counters, | 300 | per_cpu(perf_events, cpu) = kcalloc(num_counters, |
302 | sizeof(struct perf_event *), GFP_KERNEL); | 301 | sizeof(struct perf_event *), GFP_KERNEL); |
303 | if (!perf_events[cpu]) { | 302 | if (!per_cpu(perf_events, cpu)) { |
304 | pr_info("oprofile: failed to allocate %d perf events " | 303 | pr_info("oprofile: failed to allocate %d perf events " |
305 | "for cpu %d\n", num_counters, cpu); | 304 | "for cpu %d\n", num_counters, cpu); |
306 | ret = -ENOMEM; | 305 | ret = -ENOMEM; |
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 176a939d1547..af961d6f7ab1 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -65,7 +65,7 @@ struct trace_iterator { | |||
65 | void *private; | 65 | void *private; |
66 | int cpu_file; | 66 | int cpu_file; |
67 | struct mutex mutex; | 67 | struct mutex mutex; |
68 | struct ring_buffer_iter *buffer_iter[NR_CPUS]; | 68 | struct ring_buffer_iter **buffer_iter; |
69 | unsigned long iter_flags; | 69 | unsigned long iter_flags; |
70 | 70 | ||
71 | /* trace_seq for __print_flags() and __print_symbolic() etc. */ | 71 | /* trace_seq for __print_flags() and __print_symbolic() etc. */ |
@@ -207,6 +207,9 @@ struct ftrace_event_call { | |||
207 | * bit 1: enabled | 207 | * bit 1: enabled |
208 | * bit 2: filter_active | 208 | * bit 2: filter_active |
209 | * bit 3: enabled cmd record | 209 | * bit 3: enabled cmd record |
210 | * bit 4: allow trace by non root (cap any) | ||
211 | * bit 5: failed to apply filter | ||
212 | * bit 6: ftrace internal event (do not enable) | ||
210 | * | 213 | * |
211 | * Changes to flags must hold the event_mutex. | 214 | * Changes to flags must hold the event_mutex. |
212 | * | 215 | * |
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index c513a40510f5..0976fc46d1e0 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h | |||
@@ -42,8 +42,7 @@ | |||
42 | * allowed. | 42 | * allowed. |
43 | * | 43 | * |
44 | * Not initializing the key (static data is initialized to 0s anyway) is the | 44 | * Not initializing the key (static data is initialized to 0s anyway) is the |
45 | * same as using STATIC_KEY_INIT_FALSE and static_key_false() is | 45 | * same as using STATIC_KEY_INIT_FALSE. |
46 | * equivalent with static_branch(). | ||
47 | * | 46 | * |
48 | */ | 47 | */ |
49 | 48 | ||
@@ -107,12 +106,6 @@ static __always_inline bool static_key_true(struct static_key *key) | |||
107 | return !static_key_false(key); | 106 | return !static_key_false(key); |
108 | } | 107 | } |
109 | 108 | ||
110 | /* Deprecated. Please use 'static_key_false() instead. */ | ||
111 | static __always_inline bool static_branch(struct static_key *key) | ||
112 | { | ||
113 | return arch_static_branch(key); | ||
114 | } | ||
115 | |||
116 | extern struct jump_entry __start___jump_table[]; | 109 | extern struct jump_entry __start___jump_table[]; |
117 | extern struct jump_entry __stop___jump_table[]; | 110 | extern struct jump_entry __stop___jump_table[]; |
118 | 111 | ||
@@ -166,14 +159,6 @@ static __always_inline bool static_key_true(struct static_key *key) | |||
166 | return false; | 159 | return false; |
167 | } | 160 | } |
168 | 161 | ||
169 | /* Deprecated. Please use 'static_key_false() instead. */ | ||
170 | static __always_inline bool static_branch(struct static_key *key) | ||
171 | { | ||
172 | if (unlikely(atomic_read(&key->enabled)) > 0) | ||
173 | return true; | ||
174 | return false; | ||
175 | } | ||
176 | |||
177 | static inline void static_key_slow_inc(struct static_key *key) | 162 | static inline void static_key_slow_inc(struct static_key *key) |
178 | { | 163 | { |
179 | atomic_inc(&key->enabled); | 164 | atomic_inc(&key->enabled); |
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ab741b0d0074..5f187026b812 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
@@ -2755,6 +2755,17 @@ | |||
2755 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27 | 2755 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27 |
2756 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e | 2756 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e |
2757 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f | 2757 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f |
2758 | #define PCI_DEVICE_ID_INTEL_UNC_HA 0x3c46 | ||
2759 | #define PCI_DEVICE_ID_INTEL_UNC_IMC0 0x3cb0 | ||
2760 | #define PCI_DEVICE_ID_INTEL_UNC_IMC1 0x3cb1 | ||
2761 | #define PCI_DEVICE_ID_INTEL_UNC_IMC2 0x3cb4 | ||
2762 | #define PCI_DEVICE_ID_INTEL_UNC_IMC3 0x3cb5 | ||
2763 | #define PCI_DEVICE_ID_INTEL_UNC_QPI0 0x3c41 | ||
2764 | #define PCI_DEVICE_ID_INTEL_UNC_QPI1 0x3c42 | ||
2765 | #define PCI_DEVICE_ID_INTEL_UNC_R2PCIE 0x3c43 | ||
2766 | #define PCI_DEVICE_ID_INTEL_UNC_R3QPI0 0x3c44 | ||
2767 | #define PCI_DEVICE_ID_INTEL_UNC_R3QPI1 0x3c45 | ||
2768 | #define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX 0x3ce0 | ||
2758 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f | 2769 | #define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f |
2759 | #define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 | 2770 | #define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 |
2760 | #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 | 2771 | #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 45db49f64bb4..76c5c8b724a7 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -677,6 +677,7 @@ struct hw_perf_event { | |||
677 | u64 last_tag; | 677 | u64 last_tag; |
678 | unsigned long config_base; | 678 | unsigned long config_base; |
679 | unsigned long event_base; | 679 | unsigned long event_base; |
680 | int event_base_rdpmc; | ||
680 | int idx; | 681 | int idx; |
681 | int last_cpu; | 682 | int last_cpu; |
682 | 683 | ||
@@ -1106,6 +1107,8 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, | |||
1106 | struct task_struct *task, | 1107 | struct task_struct *task, |
1107 | perf_overflow_handler_t callback, | 1108 | perf_overflow_handler_t callback, |
1108 | void *context); | 1109 | void *context); |
1110 | extern void perf_pmu_migrate_context(struct pmu *pmu, | ||
1111 | int src_cpu, int dst_cpu); | ||
1109 | extern u64 perf_event_read_value(struct perf_event *event, | 1112 | extern u64 perf_event_read_value(struct perf_event *event, |
1110 | u64 *enabled, u64 *running); | 1113 | u64 *enabled, u64 *running); |
1111 | 1114 | ||
diff --git a/include/linux/sched.h b/include/linux/sched.h index 4a1f493e0fef..64d9df5c3a49 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1581,7 +1581,6 @@ struct task_struct { | |||
1581 | #endif | 1581 | #endif |
1582 | #ifdef CONFIG_UPROBES | 1582 | #ifdef CONFIG_UPROBES |
1583 | struct uprobe_task *utask; | 1583 | struct uprobe_task *utask; |
1584 | int uprobe_srcu_id; | ||
1585 | #endif | 1584 | #endif |
1586 | }; | 1585 | }; |
1587 | 1586 | ||
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index bd96ecd0e05c..802de56c41e8 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
@@ -153,7 +153,7 @@ static inline void tracepoint_synchronize_unregister(void) | |||
153 | } \ | 153 | } \ |
154 | static inline void trace_##name##_rcuidle(proto) \ | 154 | static inline void trace_##name##_rcuidle(proto) \ |
155 | { \ | 155 | { \ |
156 | if (static_branch(&__tracepoint_##name.key)) \ | 156 | if (static_key_false(&__tracepoint_##name.key)) \ |
157 | __DO_TRACE(&__tracepoint_##name, \ | 157 | __DO_TRACE(&__tracepoint_##name, \ |
158 | TP_PROTO(data_proto), \ | 158 | TP_PROTO(data_proto), \ |
159 | TP_ARGS(data_args), \ | 159 | TP_ARGS(data_args), \ |
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h index 769724944fc6..c6bc2faaf261 100644 --- a/include/trace/ftrace.h +++ b/include/trace/ftrace.h | |||
@@ -571,6 +571,7 @@ static inline void ftrace_test_probe_##call(void) \ | |||
571 | 571 | ||
572 | #undef __print_flags | 572 | #undef __print_flags |
573 | #undef __print_symbolic | 573 | #undef __print_symbolic |
574 | #undef __print_hex | ||
574 | #undef __get_dynamic_array | 575 | #undef __get_dynamic_array |
575 | #undef __get_str | 576 | #undef __get_str |
576 | 577 | ||
diff --git a/kernel/events/core.c b/kernel/events/core.c index d7d71d6ec972..f1cf0edeb39a 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -1645,6 +1645,8 @@ perf_install_in_context(struct perf_event_context *ctx, | |||
1645 | lockdep_assert_held(&ctx->mutex); | 1645 | lockdep_assert_held(&ctx->mutex); |
1646 | 1646 | ||
1647 | event->ctx = ctx; | 1647 | event->ctx = ctx; |
1648 | if (event->cpu != -1) | ||
1649 | event->cpu = cpu; | ||
1648 | 1650 | ||
1649 | if (!task) { | 1651 | if (!task) { |
1650 | /* | 1652 | /* |
@@ -6252,6 +6254,8 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6252 | } | 6254 | } |
6253 | } | 6255 | } |
6254 | 6256 | ||
6257 | get_online_cpus(); | ||
6258 | |||
6255 | event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, | 6259 | event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, |
6256 | NULL, NULL); | 6260 | NULL, NULL); |
6257 | if (IS_ERR(event)) { | 6261 | if (IS_ERR(event)) { |
@@ -6304,7 +6308,7 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6304 | /* | 6308 | /* |
6305 | * Get the target context (task or percpu): | 6309 | * Get the target context (task or percpu): |
6306 | */ | 6310 | */ |
6307 | ctx = find_get_context(pmu, task, cpu); | 6311 | ctx = find_get_context(pmu, task, event->cpu); |
6308 | if (IS_ERR(ctx)) { | 6312 | if (IS_ERR(ctx)) { |
6309 | err = PTR_ERR(ctx); | 6313 | err = PTR_ERR(ctx); |
6310 | goto err_alloc; | 6314 | goto err_alloc; |
@@ -6377,20 +6381,23 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6377 | mutex_lock(&ctx->mutex); | 6381 | mutex_lock(&ctx->mutex); |
6378 | 6382 | ||
6379 | if (move_group) { | 6383 | if (move_group) { |
6380 | perf_install_in_context(ctx, group_leader, cpu); | 6384 | synchronize_rcu(); |
6385 | perf_install_in_context(ctx, group_leader, event->cpu); | ||
6381 | get_ctx(ctx); | 6386 | get_ctx(ctx); |
6382 | list_for_each_entry(sibling, &group_leader->sibling_list, | 6387 | list_for_each_entry(sibling, &group_leader->sibling_list, |
6383 | group_entry) { | 6388 | group_entry) { |
6384 | perf_install_in_context(ctx, sibling, cpu); | 6389 | perf_install_in_context(ctx, sibling, event->cpu); |
6385 | get_ctx(ctx); | 6390 | get_ctx(ctx); |
6386 | } | 6391 | } |
6387 | } | 6392 | } |
6388 | 6393 | ||
6389 | perf_install_in_context(ctx, event, cpu); | 6394 | perf_install_in_context(ctx, event, event->cpu); |
6390 | ++ctx->generation; | 6395 | ++ctx->generation; |
6391 | perf_unpin_context(ctx); | 6396 | perf_unpin_context(ctx); |
6392 | mutex_unlock(&ctx->mutex); | 6397 | mutex_unlock(&ctx->mutex); |
6393 | 6398 | ||
6399 | put_online_cpus(); | ||
6400 | |||
6394 | event->owner = current; | 6401 | event->owner = current; |
6395 | 6402 | ||
6396 | mutex_lock(¤t->perf_event_mutex); | 6403 | mutex_lock(¤t->perf_event_mutex); |
@@ -6419,6 +6426,7 @@ err_context: | |||
6419 | err_alloc: | 6426 | err_alloc: |
6420 | free_event(event); | 6427 | free_event(event); |
6421 | err_task: | 6428 | err_task: |
6429 | put_online_cpus(); | ||
6422 | if (task) | 6430 | if (task) |
6423 | put_task_struct(task); | 6431 | put_task_struct(task); |
6424 | err_group_fd: | 6432 | err_group_fd: |
@@ -6479,6 +6487,39 @@ err: | |||
6479 | } | 6487 | } |
6480 | EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter); | 6488 | EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter); |
6481 | 6489 | ||
6490 | void perf_pmu_migrate_context(struct pmu *pmu, int src_cpu, int dst_cpu) | ||
6491 | { | ||
6492 | struct perf_event_context *src_ctx; | ||
6493 | struct perf_event_context *dst_ctx; | ||
6494 | struct perf_event *event, *tmp; | ||
6495 | LIST_HEAD(events); | ||
6496 | |||
6497 | src_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, src_cpu)->ctx; | ||
6498 | dst_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, dst_cpu)->ctx; | ||
6499 | |||
6500 | mutex_lock(&src_ctx->mutex); | ||
6501 | list_for_each_entry_safe(event, tmp, &src_ctx->event_list, | ||
6502 | event_entry) { | ||
6503 | perf_remove_from_context(event); | ||
6504 | put_ctx(src_ctx); | ||
6505 | list_add(&event->event_entry, &events); | ||
6506 | } | ||
6507 | mutex_unlock(&src_ctx->mutex); | ||
6508 | |||
6509 | synchronize_rcu(); | ||
6510 | |||
6511 | mutex_lock(&dst_ctx->mutex); | ||
6512 | list_for_each_entry_safe(event, tmp, &events, event_entry) { | ||
6513 | list_del(&event->event_entry); | ||
6514 | if (event->state >= PERF_EVENT_STATE_OFF) | ||
6515 | event->state = PERF_EVENT_STATE_INACTIVE; | ||
6516 | perf_install_in_context(dst_ctx, event, dst_cpu); | ||
6517 | get_ctx(dst_ctx); | ||
6518 | } | ||
6519 | mutex_unlock(&dst_ctx->mutex); | ||
6520 | } | ||
6521 | EXPORT_SYMBOL_GPL(perf_pmu_migrate_context); | ||
6522 | |||
6482 | static void sync_child_event(struct perf_event *child_event, | 6523 | static void sync_child_event(struct perf_event *child_event, |
6483 | struct task_struct *child) | 6524 | struct task_struct *child) |
6484 | { | 6525 | { |
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 985be4d80fe8..f93532748bca 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -38,13 +38,29 @@ | |||
38 | #define UINSNS_PER_PAGE (PAGE_SIZE/UPROBE_XOL_SLOT_BYTES) | 38 | #define UINSNS_PER_PAGE (PAGE_SIZE/UPROBE_XOL_SLOT_BYTES) |
39 | #define MAX_UPROBE_XOL_SLOTS UINSNS_PER_PAGE | 39 | #define MAX_UPROBE_XOL_SLOTS UINSNS_PER_PAGE |
40 | 40 | ||
41 | static struct srcu_struct uprobes_srcu; | ||
42 | static struct rb_root uprobes_tree = RB_ROOT; | 41 | static struct rb_root uprobes_tree = RB_ROOT; |
43 | 42 | ||
44 | static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */ | 43 | static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */ |
45 | 44 | ||
46 | #define UPROBES_HASH_SZ 13 | 45 | #define UPROBES_HASH_SZ 13 |
47 | 46 | ||
47 | /* | ||
48 | * We need separate register/unregister and mmap/munmap lock hashes because | ||
49 | * of mmap_sem nesting. | ||
50 | * | ||
51 | * uprobe_register() needs to install probes on (potentially) all processes | ||
52 | * and thus needs to acquire multiple mmap_sems (consequtively, not | ||
53 | * concurrently), whereas uprobe_mmap() is called while holding mmap_sem | ||
54 | * for the particular process doing the mmap. | ||
55 | * | ||
56 | * uprobe_register()->register_for_each_vma() needs to drop/acquire mmap_sem | ||
57 | * because of lock order against i_mmap_mutex. This means there's a hole in | ||
58 | * the register vma iteration where a mmap() can happen. | ||
59 | * | ||
60 | * Thus uprobe_register() can race with uprobe_mmap() and we can try and | ||
61 | * install a probe where one is already installed. | ||
62 | */ | ||
63 | |||
48 | /* serialize (un)register */ | 64 | /* serialize (un)register */ |
49 | static struct mutex uprobes_mutex[UPROBES_HASH_SZ]; | 65 | static struct mutex uprobes_mutex[UPROBES_HASH_SZ]; |
50 | 66 | ||
@@ -61,17 +77,6 @@ static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; | |||
61 | */ | 77 | */ |
62 | static atomic_t uprobe_events = ATOMIC_INIT(0); | 78 | static atomic_t uprobe_events = ATOMIC_INIT(0); |
63 | 79 | ||
64 | /* | ||
65 | * Maintain a temporary per vma info that can be used to search if a vma | ||
66 | * has already been handled. This structure is introduced since extending | ||
67 | * vm_area_struct wasnt recommended. | ||
68 | */ | ||
69 | struct vma_info { | ||
70 | struct list_head probe_list; | ||
71 | struct mm_struct *mm; | ||
72 | loff_t vaddr; | ||
73 | }; | ||
74 | |||
75 | struct uprobe { | 80 | struct uprobe { |
76 | struct rb_node rb_node; /* node in the rb tree */ | 81 | struct rb_node rb_node; /* node in the rb tree */ |
77 | atomic_t ref; | 82 | atomic_t ref; |
@@ -100,7 +105,8 @@ static bool valid_vma(struct vm_area_struct *vma, bool is_register) | |||
100 | if (!is_register) | 105 | if (!is_register) |
101 | return true; | 106 | return true; |
102 | 107 | ||
103 | if ((vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) == (VM_READ|VM_EXEC)) | 108 | if ((vma->vm_flags & (VM_HUGETLB|VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) |
109 | == (VM_READ|VM_EXEC)) | ||
104 | return true; | 110 | return true; |
105 | 111 | ||
106 | return false; | 112 | return false; |
@@ -129,33 +135,17 @@ static loff_t vma_address(struct vm_area_struct *vma, loff_t offset) | |||
129 | static int __replace_page(struct vm_area_struct *vma, struct page *page, struct page *kpage) | 135 | static int __replace_page(struct vm_area_struct *vma, struct page *page, struct page *kpage) |
130 | { | 136 | { |
131 | struct mm_struct *mm = vma->vm_mm; | 137 | struct mm_struct *mm = vma->vm_mm; |
132 | pgd_t *pgd; | ||
133 | pud_t *pud; | ||
134 | pmd_t *pmd; | ||
135 | pte_t *ptep; | ||
136 | spinlock_t *ptl; | ||
137 | unsigned long addr; | 138 | unsigned long addr; |
138 | int err = -EFAULT; | 139 | spinlock_t *ptl; |
140 | pte_t *ptep; | ||
139 | 141 | ||
140 | addr = page_address_in_vma(page, vma); | 142 | addr = page_address_in_vma(page, vma); |
141 | if (addr == -EFAULT) | 143 | if (addr == -EFAULT) |
142 | goto out; | 144 | return -EFAULT; |
143 | |||
144 | pgd = pgd_offset(mm, addr); | ||
145 | if (!pgd_present(*pgd)) | ||
146 | goto out; | ||
147 | |||
148 | pud = pud_offset(pgd, addr); | ||
149 | if (!pud_present(*pud)) | ||
150 | goto out; | ||
151 | |||
152 | pmd = pmd_offset(pud, addr); | ||
153 | if (!pmd_present(*pmd)) | ||
154 | goto out; | ||
155 | 145 | ||
156 | ptep = pte_offset_map_lock(mm, pmd, addr, &ptl); | 146 | ptep = page_check_address(page, mm, addr, &ptl, 0); |
157 | if (!ptep) | 147 | if (!ptep) |
158 | goto out; | 148 | return -EAGAIN; |
159 | 149 | ||
160 | get_page(kpage); | 150 | get_page(kpage); |
161 | page_add_new_anon_rmap(kpage, vma, addr); | 151 | page_add_new_anon_rmap(kpage, vma, addr); |
@@ -174,10 +164,8 @@ static int __replace_page(struct vm_area_struct *vma, struct page *page, struct | |||
174 | try_to_free_swap(page); | 164 | try_to_free_swap(page); |
175 | put_page(page); | 165 | put_page(page); |
176 | pte_unmap_unlock(ptep, ptl); | 166 | pte_unmap_unlock(ptep, ptl); |
177 | err = 0; | ||
178 | 167 | ||
179 | out: | 168 | return 0; |
180 | return err; | ||
181 | } | 169 | } |
182 | 170 | ||
183 | /** | 171 | /** |
@@ -222,9 +210,8 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm, | |||
222 | void *vaddr_old, *vaddr_new; | 210 | void *vaddr_old, *vaddr_new; |
223 | struct vm_area_struct *vma; | 211 | struct vm_area_struct *vma; |
224 | struct uprobe *uprobe; | 212 | struct uprobe *uprobe; |
225 | loff_t addr; | ||
226 | int ret; | 213 | int ret; |
227 | 214 | retry: | |
228 | /* Read the page with vaddr into memory */ | 215 | /* Read the page with vaddr into memory */ |
229 | ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma); | 216 | ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma); |
230 | if (ret <= 0) | 217 | if (ret <= 0) |
@@ -246,10 +233,6 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm, | |||
246 | if (mapping != vma->vm_file->f_mapping) | 233 | if (mapping != vma->vm_file->f_mapping) |
247 | goto put_out; | 234 | goto put_out; |
248 | 235 | ||
249 | addr = vma_address(vma, uprobe->offset); | ||
250 | if (vaddr != (unsigned long)addr) | ||
251 | goto put_out; | ||
252 | |||
253 | ret = -ENOMEM; | 236 | ret = -ENOMEM; |
254 | new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr); | 237 | new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr); |
255 | if (!new_page) | 238 | if (!new_page) |
@@ -267,11 +250,7 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm, | |||
267 | vaddr_new = kmap_atomic(new_page); | 250 | vaddr_new = kmap_atomic(new_page); |
268 | 251 | ||
269 | memcpy(vaddr_new, vaddr_old, PAGE_SIZE); | 252 | memcpy(vaddr_new, vaddr_old, PAGE_SIZE); |
270 | 253 | memcpy(vaddr_new + (vaddr & ~PAGE_MASK), &opcode, UPROBE_SWBP_INSN_SIZE); | |
271 | /* poke the new insn in, ASSUMES we don't cross page boundary */ | ||
272 | vaddr &= ~PAGE_MASK; | ||
273 | BUG_ON(vaddr + UPROBE_SWBP_INSN_SIZE > PAGE_SIZE); | ||
274 | memcpy(vaddr_new + vaddr, &opcode, UPROBE_SWBP_INSN_SIZE); | ||
275 | 254 | ||
276 | kunmap_atomic(vaddr_new); | 255 | kunmap_atomic(vaddr_new); |
277 | kunmap_atomic(vaddr_old); | 256 | kunmap_atomic(vaddr_old); |
@@ -291,6 +270,8 @@ unlock_out: | |||
291 | put_out: | 270 | put_out: |
292 | put_page(old_page); | 271 | put_page(old_page); |
293 | 272 | ||
273 | if (unlikely(ret == -EAGAIN)) | ||
274 | goto retry; | ||
294 | return ret; | 275 | return ret; |
295 | } | 276 | } |
296 | 277 | ||
@@ -312,7 +293,7 @@ static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_ | |||
312 | void *vaddr_new; | 293 | void *vaddr_new; |
313 | int ret; | 294 | int ret; |
314 | 295 | ||
315 | ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &page, NULL); | 296 | ret = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL); |
316 | if (ret <= 0) | 297 | if (ret <= 0) |
317 | return ret; | 298 | return ret; |
318 | 299 | ||
@@ -333,10 +314,20 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) | |||
333 | uprobe_opcode_t opcode; | 314 | uprobe_opcode_t opcode; |
334 | int result; | 315 | int result; |
335 | 316 | ||
317 | if (current->mm == mm) { | ||
318 | pagefault_disable(); | ||
319 | result = __copy_from_user_inatomic(&opcode, (void __user*)vaddr, | ||
320 | sizeof(opcode)); | ||
321 | pagefault_enable(); | ||
322 | |||
323 | if (likely(result == 0)) | ||
324 | goto out; | ||
325 | } | ||
326 | |||
336 | result = read_opcode(mm, vaddr, &opcode); | 327 | result = read_opcode(mm, vaddr, &opcode); |
337 | if (result) | 328 | if (result) |
338 | return result; | 329 | return result; |
339 | 330 | out: | |
340 | if (is_swbp_insn(&opcode)) | 331 | if (is_swbp_insn(&opcode)) |
341 | return 1; | 332 | return 1; |
342 | 333 | ||
@@ -355,7 +346,9 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) | |||
355 | int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) | 346 | int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr) |
356 | { | 347 | { |
357 | int result; | 348 | int result; |
358 | 349 | /* | |
350 | * See the comment near uprobes_hash(). | ||
351 | */ | ||
359 | result = is_swbp_at_addr(mm, vaddr); | 352 | result = is_swbp_at_addr(mm, vaddr); |
360 | if (result == 1) | 353 | if (result == 1) |
361 | return -EEXIST; | 354 | return -EEXIST; |
@@ -520,7 +513,6 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset) | |||
520 | uprobe->inode = igrab(inode); | 513 | uprobe->inode = igrab(inode); |
521 | uprobe->offset = offset; | 514 | uprobe->offset = offset; |
522 | init_rwsem(&uprobe->consumer_rwsem); | 515 | init_rwsem(&uprobe->consumer_rwsem); |
523 | INIT_LIST_HEAD(&uprobe->pending_list); | ||
524 | 516 | ||
525 | /* add to uprobes_tree, sorted on inode:offset */ | 517 | /* add to uprobes_tree, sorted on inode:offset */ |
526 | cur_uprobe = insert_uprobe(uprobe); | 518 | cur_uprobe = insert_uprobe(uprobe); |
@@ -588,20 +580,22 @@ static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *uc) | |||
588 | } | 580 | } |
589 | 581 | ||
590 | static int | 582 | static int |
591 | __copy_insn(struct address_space *mapping, struct vm_area_struct *vma, char *insn, | 583 | __copy_insn(struct address_space *mapping, struct file *filp, char *insn, |
592 | unsigned long nbytes, unsigned long offset) | 584 | unsigned long nbytes, loff_t offset) |
593 | { | 585 | { |
594 | struct file *filp = vma->vm_file; | ||
595 | struct page *page; | 586 | struct page *page; |
596 | void *vaddr; | 587 | void *vaddr; |
597 | unsigned long off1; | 588 | unsigned long off; |
598 | unsigned long idx; | 589 | pgoff_t idx; |
599 | 590 | ||
600 | if (!filp) | 591 | if (!filp) |
601 | return -EINVAL; | 592 | return -EINVAL; |
602 | 593 | ||
603 | idx = (unsigned long)(offset >> PAGE_CACHE_SHIFT); | 594 | if (!mapping->a_ops->readpage) |
604 | off1 = offset &= ~PAGE_MASK; | 595 | return -EIO; |
596 | |||
597 | idx = offset >> PAGE_CACHE_SHIFT; | ||
598 | off = offset & ~PAGE_MASK; | ||
605 | 599 | ||
606 | /* | 600 | /* |
607 | * Ensure that the page that has the original instruction is | 601 | * Ensure that the page that has the original instruction is |
@@ -612,22 +606,20 @@ __copy_insn(struct address_space *mapping, struct vm_area_struct *vma, char *ins | |||
612 | return PTR_ERR(page); | 606 | return PTR_ERR(page); |
613 | 607 | ||
614 | vaddr = kmap_atomic(page); | 608 | vaddr = kmap_atomic(page); |
615 | memcpy(insn, vaddr + off1, nbytes); | 609 | memcpy(insn, vaddr + off, nbytes); |
616 | kunmap_atomic(vaddr); | 610 | kunmap_atomic(vaddr); |
617 | page_cache_release(page); | 611 | page_cache_release(page); |
618 | 612 | ||
619 | return 0; | 613 | return 0; |
620 | } | 614 | } |
621 | 615 | ||
622 | static int | 616 | static int copy_insn(struct uprobe *uprobe, struct file *filp) |
623 | copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr) | ||
624 | { | 617 | { |
625 | struct address_space *mapping; | 618 | struct address_space *mapping; |
626 | unsigned long nbytes; | 619 | unsigned long nbytes; |
627 | int bytes; | 620 | int bytes; |
628 | 621 | ||
629 | addr &= ~PAGE_MASK; | 622 | nbytes = PAGE_SIZE - (uprobe->offset & ~PAGE_MASK); |
630 | nbytes = PAGE_SIZE - addr; | ||
631 | mapping = uprobe->inode->i_mapping; | 623 | mapping = uprobe->inode->i_mapping; |
632 | 624 | ||
633 | /* Instruction at end of binary; copy only available bytes */ | 625 | /* Instruction at end of binary; copy only available bytes */ |
@@ -638,13 +630,13 @@ copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr) | |||
638 | 630 | ||
639 | /* Instruction at the page-boundary; copy bytes in second page */ | 631 | /* Instruction at the page-boundary; copy bytes in second page */ |
640 | if (nbytes < bytes) { | 632 | if (nbytes < bytes) { |
641 | if (__copy_insn(mapping, vma, uprobe->arch.insn + nbytes, | 633 | int err = __copy_insn(mapping, filp, uprobe->arch.insn + nbytes, |
642 | bytes - nbytes, uprobe->offset + nbytes)) | 634 | bytes - nbytes, uprobe->offset + nbytes); |
643 | return -ENOMEM; | 635 | if (err) |
644 | 636 | return err; | |
645 | bytes = nbytes; | 637 | bytes = nbytes; |
646 | } | 638 | } |
647 | return __copy_insn(mapping, vma, uprobe->arch.insn, bytes, uprobe->offset); | 639 | return __copy_insn(mapping, filp, uprobe->arch.insn, bytes, uprobe->offset); |
648 | } | 640 | } |
649 | 641 | ||
650 | /* | 642 | /* |
@@ -672,9 +664,8 @@ copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr) | |||
672 | */ | 664 | */ |
673 | static int | 665 | static int |
674 | install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | 666 | install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, |
675 | struct vm_area_struct *vma, loff_t vaddr) | 667 | struct vm_area_struct *vma, unsigned long vaddr) |
676 | { | 668 | { |
677 | unsigned long addr; | ||
678 | int ret; | 669 | int ret; |
679 | 670 | ||
680 | /* | 671 | /* |
@@ -687,20 +678,22 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | |||
687 | if (!uprobe->consumers) | 678 | if (!uprobe->consumers) |
688 | return -EEXIST; | 679 | return -EEXIST; |
689 | 680 | ||
690 | addr = (unsigned long)vaddr; | ||
691 | |||
692 | if (!(uprobe->flags & UPROBE_COPY_INSN)) { | 681 | if (!(uprobe->flags & UPROBE_COPY_INSN)) { |
693 | ret = copy_insn(uprobe, vma, addr); | 682 | ret = copy_insn(uprobe, vma->vm_file); |
694 | if (ret) | 683 | if (ret) |
695 | return ret; | 684 | return ret; |
696 | 685 | ||
697 | if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn)) | 686 | if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn)) |
698 | return -EEXIST; | 687 | return -ENOTSUPP; |
699 | 688 | ||
700 | ret = arch_uprobe_analyze_insn(&uprobe->arch, mm); | 689 | ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr); |
701 | if (ret) | 690 | if (ret) |
702 | return ret; | 691 | return ret; |
703 | 692 | ||
693 | /* write_opcode() assumes we don't cross page boundary */ | ||
694 | BUG_ON((uprobe->offset & ~PAGE_MASK) + | ||
695 | UPROBE_SWBP_INSN_SIZE > PAGE_SIZE); | ||
696 | |||
704 | uprobe->flags |= UPROBE_COPY_INSN; | 697 | uprobe->flags |= UPROBE_COPY_INSN; |
705 | } | 698 | } |
706 | 699 | ||
@@ -713,7 +706,7 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | |||
713 | * Hence increment before and decrement on failure. | 706 | * Hence increment before and decrement on failure. |
714 | */ | 707 | */ |
715 | atomic_inc(&mm->uprobes_state.count); | 708 | atomic_inc(&mm->uprobes_state.count); |
716 | ret = set_swbp(&uprobe->arch, mm, addr); | 709 | ret = set_swbp(&uprobe->arch, mm, vaddr); |
717 | if (ret) | 710 | if (ret) |
718 | atomic_dec(&mm->uprobes_state.count); | 711 | atomic_dec(&mm->uprobes_state.count); |
719 | 712 | ||
@@ -721,27 +714,21 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | |||
721 | } | 714 | } |
722 | 715 | ||
723 | static void | 716 | static void |
724 | remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, loff_t vaddr) | 717 | remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr) |
725 | { | 718 | { |
726 | if (!set_orig_insn(&uprobe->arch, mm, (unsigned long)vaddr, true)) | 719 | if (!set_orig_insn(&uprobe->arch, mm, vaddr, true)) |
727 | atomic_dec(&mm->uprobes_state.count); | 720 | atomic_dec(&mm->uprobes_state.count); |
728 | } | 721 | } |
729 | 722 | ||
730 | /* | 723 | /* |
731 | * There could be threads that have hit the breakpoint and are entering the | 724 | * There could be threads that have already hit the breakpoint. They |
732 | * notifier code and trying to acquire the uprobes_treelock. The thread | 725 | * will recheck the current insn and restart if find_uprobe() fails. |
733 | * calling delete_uprobe() that is removing the uprobe from the rb_tree can | 726 | * See find_active_uprobe(). |
734 | * race with these threads and might acquire the uprobes_treelock compared | ||
735 | * to some of the breakpoint hit threads. In such a case, the breakpoint | ||
736 | * hit threads will not find the uprobe. The current unregistering thread | ||
737 | * waits till all other threads have hit a breakpoint, to acquire the | ||
738 | * uprobes_treelock before the uprobe is removed from the rbtree. | ||
739 | */ | 727 | */ |
740 | static void delete_uprobe(struct uprobe *uprobe) | 728 | static void delete_uprobe(struct uprobe *uprobe) |
741 | { | 729 | { |
742 | unsigned long flags; | 730 | unsigned long flags; |
743 | 731 | ||
744 | synchronize_srcu(&uprobes_srcu); | ||
745 | spin_lock_irqsave(&uprobes_treelock, flags); | 732 | spin_lock_irqsave(&uprobes_treelock, flags); |
746 | rb_erase(&uprobe->rb_node, &uprobes_tree); | 733 | rb_erase(&uprobe->rb_node, &uprobes_tree); |
747 | spin_unlock_irqrestore(&uprobes_treelock, flags); | 734 | spin_unlock_irqrestore(&uprobes_treelock, flags); |
@@ -750,139 +737,135 @@ static void delete_uprobe(struct uprobe *uprobe) | |||
750 | atomic_dec(&uprobe_events); | 737 | atomic_dec(&uprobe_events); |
751 | } | 738 | } |
752 | 739 | ||
753 | static struct vma_info * | 740 | struct map_info { |
754 | __find_next_vma_info(struct address_space *mapping, struct list_head *head, | 741 | struct map_info *next; |
755 | struct vma_info *vi, loff_t offset, bool is_register) | 742 | struct mm_struct *mm; |
743 | unsigned long vaddr; | ||
744 | }; | ||
745 | |||
746 | static inline struct map_info *free_map_info(struct map_info *info) | ||
747 | { | ||
748 | struct map_info *next = info->next; | ||
749 | kfree(info); | ||
750 | return next; | ||
751 | } | ||
752 | |||
753 | static struct map_info * | ||
754 | build_map_info(struct address_space *mapping, loff_t offset, bool is_register) | ||
756 | { | 755 | { |
756 | unsigned long pgoff = offset >> PAGE_SHIFT; | ||
757 | struct prio_tree_iter iter; | 757 | struct prio_tree_iter iter; |
758 | struct vm_area_struct *vma; | 758 | struct vm_area_struct *vma; |
759 | struct vma_info *tmpvi; | 759 | struct map_info *curr = NULL; |
760 | unsigned long pgoff; | 760 | struct map_info *prev = NULL; |
761 | int existing_vma; | 761 | struct map_info *info; |
762 | loff_t vaddr; | 762 | int more = 0; |
763 | |||
764 | pgoff = offset >> PAGE_SHIFT; | ||
765 | 763 | ||
764 | again: | ||
765 | mutex_lock(&mapping->i_mmap_mutex); | ||
766 | vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { | 766 | vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { |
767 | if (!valid_vma(vma, is_register)) | 767 | if (!valid_vma(vma, is_register)) |
768 | continue; | 768 | continue; |
769 | 769 | ||
770 | existing_vma = 0; | 770 | if (!prev && !more) { |
771 | vaddr = vma_address(vma, offset); | 771 | /* |
772 | 772 | * Needs GFP_NOWAIT to avoid i_mmap_mutex recursion through | |
773 | list_for_each_entry(tmpvi, head, probe_list) { | 773 | * reclaim. This is optimistic, no harm done if it fails. |
774 | if (tmpvi->mm == vma->vm_mm && tmpvi->vaddr == vaddr) { | 774 | */ |
775 | existing_vma = 1; | 775 | prev = kmalloc(sizeof(struct map_info), |
776 | break; | 776 | GFP_NOWAIT | __GFP_NOMEMALLOC | __GFP_NOWARN); |
777 | } | 777 | if (prev) |
778 | prev->next = NULL; | ||
778 | } | 779 | } |
779 | 780 | if (!prev) { | |
780 | /* | 781 | more++; |
781 | * Another vma needs a probe to be installed. However skip | 782 | continue; |
782 | * installing the probe if the vma is about to be unlinked. | ||
783 | */ | ||
784 | if (!existing_vma && atomic_inc_not_zero(&vma->vm_mm->mm_users)) { | ||
785 | vi->mm = vma->vm_mm; | ||
786 | vi->vaddr = vaddr; | ||
787 | list_add(&vi->probe_list, head); | ||
788 | |||
789 | return vi; | ||
790 | } | 783 | } |
791 | } | ||
792 | 784 | ||
793 | return NULL; | 785 | if (!atomic_inc_not_zero(&vma->vm_mm->mm_users)) |
794 | } | 786 | continue; |
795 | |||
796 | /* | ||
797 | * Iterate in the rmap prio tree and find a vma where a probe has not | ||
798 | * yet been inserted. | ||
799 | */ | ||
800 | static struct vma_info * | ||
801 | find_next_vma_info(struct address_space *mapping, struct list_head *head, | ||
802 | loff_t offset, bool is_register) | ||
803 | { | ||
804 | struct vma_info *vi, *retvi; | ||
805 | 787 | ||
806 | vi = kzalloc(sizeof(struct vma_info), GFP_KERNEL); | 788 | info = prev; |
807 | if (!vi) | 789 | prev = prev->next; |
808 | return ERR_PTR(-ENOMEM); | 790 | info->next = curr; |
791 | curr = info; | ||
809 | 792 | ||
810 | mutex_lock(&mapping->i_mmap_mutex); | 793 | info->mm = vma->vm_mm; |
811 | retvi = __find_next_vma_info(mapping, head, vi, offset, is_register); | 794 | info->vaddr = vma_address(vma, offset); |
795 | } | ||
812 | mutex_unlock(&mapping->i_mmap_mutex); | 796 | mutex_unlock(&mapping->i_mmap_mutex); |
813 | 797 | ||
814 | if (!retvi) | 798 | if (!more) |
815 | kfree(vi); | 799 | goto out; |
800 | |||
801 | prev = curr; | ||
802 | while (curr) { | ||
803 | mmput(curr->mm); | ||
804 | curr = curr->next; | ||
805 | } | ||
816 | 806 | ||
817 | return retvi; | 807 | do { |
808 | info = kmalloc(sizeof(struct map_info), GFP_KERNEL); | ||
809 | if (!info) { | ||
810 | curr = ERR_PTR(-ENOMEM); | ||
811 | goto out; | ||
812 | } | ||
813 | info->next = prev; | ||
814 | prev = info; | ||
815 | } while (--more); | ||
816 | |||
817 | goto again; | ||
818 | out: | ||
819 | while (prev) | ||
820 | prev = free_map_info(prev); | ||
821 | return curr; | ||
818 | } | 822 | } |
819 | 823 | ||
820 | static int register_for_each_vma(struct uprobe *uprobe, bool is_register) | 824 | static int register_for_each_vma(struct uprobe *uprobe, bool is_register) |
821 | { | 825 | { |
822 | struct list_head try_list; | 826 | struct map_info *info; |
823 | struct vm_area_struct *vma; | 827 | int err = 0; |
824 | struct address_space *mapping; | ||
825 | struct vma_info *vi, *tmpvi; | ||
826 | struct mm_struct *mm; | ||
827 | loff_t vaddr; | ||
828 | int ret; | ||
829 | 828 | ||
830 | mapping = uprobe->inode->i_mapping; | 829 | info = build_map_info(uprobe->inode->i_mapping, |
831 | INIT_LIST_HEAD(&try_list); | 830 | uprobe->offset, is_register); |
831 | if (IS_ERR(info)) | ||
832 | return PTR_ERR(info); | ||
832 | 833 | ||
833 | ret = 0; | 834 | while (info) { |
835 | struct mm_struct *mm = info->mm; | ||
836 | struct vm_area_struct *vma; | ||
834 | 837 | ||
835 | for (;;) { | 838 | if (err) |
836 | vi = find_next_vma_info(mapping, &try_list, uprobe->offset, is_register); | 839 | goto free; |
837 | if (!vi) | ||
838 | break; | ||
839 | 840 | ||
840 | if (IS_ERR(vi)) { | 841 | down_write(&mm->mmap_sem); |
841 | ret = PTR_ERR(vi); | 842 | vma = find_vma(mm, (unsigned long)info->vaddr); |
842 | break; | 843 | if (!vma || !valid_vma(vma, is_register)) |
843 | } | 844 | goto unlock; |
844 | 845 | ||
845 | mm = vi->mm; | ||
846 | down_read(&mm->mmap_sem); | ||
847 | vma = find_vma(mm, (unsigned long)vi->vaddr); | ||
848 | if (!vma || !valid_vma(vma, is_register)) { | ||
849 | list_del(&vi->probe_list); | ||
850 | kfree(vi); | ||
851 | up_read(&mm->mmap_sem); | ||
852 | mmput(mm); | ||
853 | continue; | ||
854 | } | ||
855 | vaddr = vma_address(vma, uprobe->offset); | ||
856 | if (vma->vm_file->f_mapping->host != uprobe->inode || | 846 | if (vma->vm_file->f_mapping->host != uprobe->inode || |
857 | vaddr != vi->vaddr) { | 847 | vma_address(vma, uprobe->offset) != info->vaddr) |
858 | list_del(&vi->probe_list); | 848 | goto unlock; |
859 | kfree(vi); | ||
860 | up_read(&mm->mmap_sem); | ||
861 | mmput(mm); | ||
862 | continue; | ||
863 | } | ||
864 | |||
865 | if (is_register) | ||
866 | ret = install_breakpoint(uprobe, mm, vma, vi->vaddr); | ||
867 | else | ||
868 | remove_breakpoint(uprobe, mm, vi->vaddr); | ||
869 | 849 | ||
870 | up_read(&mm->mmap_sem); | ||
871 | mmput(mm); | ||
872 | if (is_register) { | 850 | if (is_register) { |
873 | if (ret && ret == -EEXIST) | 851 | err = install_breakpoint(uprobe, mm, vma, info->vaddr); |
874 | ret = 0; | 852 | /* |
875 | if (ret) | 853 | * We can race against uprobe_mmap(), see the |
876 | break; | 854 | * comment near uprobe_hash(). |
855 | */ | ||
856 | if (err == -EEXIST) | ||
857 | err = 0; | ||
858 | } else { | ||
859 | remove_breakpoint(uprobe, mm, info->vaddr); | ||
877 | } | 860 | } |
861 | unlock: | ||
862 | up_write(&mm->mmap_sem); | ||
863 | free: | ||
864 | mmput(mm); | ||
865 | info = free_map_info(info); | ||
878 | } | 866 | } |
879 | 867 | ||
880 | list_for_each_entry_safe(vi, tmpvi, &try_list, probe_list) { | 868 | return err; |
881 | list_del(&vi->probe_list); | ||
882 | kfree(vi); | ||
883 | } | ||
884 | |||
885 | return ret; | ||
886 | } | 869 | } |
887 | 870 | ||
888 | static int __uprobe_register(struct uprobe *uprobe) | 871 | static int __uprobe_register(struct uprobe *uprobe) |
@@ -1048,7 +1031,7 @@ static void build_probe_list(struct inode *inode, struct list_head *head) | |||
1048 | int uprobe_mmap(struct vm_area_struct *vma) | 1031 | int uprobe_mmap(struct vm_area_struct *vma) |
1049 | { | 1032 | { |
1050 | struct list_head tmp_list; | 1033 | struct list_head tmp_list; |
1051 | struct uprobe *uprobe, *u; | 1034 | struct uprobe *uprobe; |
1052 | struct inode *inode; | 1035 | struct inode *inode; |
1053 | int ret, count; | 1036 | int ret, count; |
1054 | 1037 | ||
@@ -1066,12 +1049,9 @@ int uprobe_mmap(struct vm_area_struct *vma) | |||
1066 | ret = 0; | 1049 | ret = 0; |
1067 | count = 0; | 1050 | count = 0; |
1068 | 1051 | ||
1069 | list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { | 1052 | list_for_each_entry(uprobe, &tmp_list, pending_list) { |
1070 | loff_t vaddr; | ||
1071 | |||
1072 | list_del(&uprobe->pending_list); | ||
1073 | if (!ret) { | 1053 | if (!ret) { |
1074 | vaddr = vma_address(vma, uprobe->offset); | 1054 | loff_t vaddr = vma_address(vma, uprobe->offset); |
1075 | 1055 | ||
1076 | if (vaddr < vma->vm_start || vaddr >= vma->vm_end) { | 1056 | if (vaddr < vma->vm_start || vaddr >= vma->vm_end) { |
1077 | put_uprobe(uprobe); | 1057 | put_uprobe(uprobe); |
@@ -1079,8 +1059,10 @@ int uprobe_mmap(struct vm_area_struct *vma) | |||
1079 | } | 1059 | } |
1080 | 1060 | ||
1081 | ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); | 1061 | ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); |
1082 | 1062 | /* | |
1083 | /* Ignore double add: */ | 1063 | * We can race against uprobe_register(), see the |
1064 | * comment near uprobe_hash(). | ||
1065 | */ | ||
1084 | if (ret == -EEXIST) { | 1066 | if (ret == -EEXIST) { |
1085 | ret = 0; | 1067 | ret = 0; |
1086 | 1068 | ||
@@ -1115,7 +1097,7 @@ int uprobe_mmap(struct vm_area_struct *vma) | |||
1115 | void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) | 1097 | void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) |
1116 | { | 1098 | { |
1117 | struct list_head tmp_list; | 1099 | struct list_head tmp_list; |
1118 | struct uprobe *uprobe, *u; | 1100 | struct uprobe *uprobe; |
1119 | struct inode *inode; | 1101 | struct inode *inode; |
1120 | 1102 | ||
1121 | if (!atomic_read(&uprobe_events) || !valid_vma(vma, false)) | 1103 | if (!atomic_read(&uprobe_events) || !valid_vma(vma, false)) |
@@ -1132,11 +1114,8 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon | |||
1132 | mutex_lock(uprobes_mmap_hash(inode)); | 1114 | mutex_lock(uprobes_mmap_hash(inode)); |
1133 | build_probe_list(inode, &tmp_list); | 1115 | build_probe_list(inode, &tmp_list); |
1134 | 1116 | ||
1135 | list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { | 1117 | list_for_each_entry(uprobe, &tmp_list, pending_list) { |
1136 | loff_t vaddr; | 1118 | loff_t vaddr = vma_address(vma, uprobe->offset); |
1137 | |||
1138 | list_del(&uprobe->pending_list); | ||
1139 | vaddr = vma_address(vma, uprobe->offset); | ||
1140 | 1119 | ||
1141 | if (vaddr >= start && vaddr < end) { | 1120 | if (vaddr >= start && vaddr < end) { |
1142 | /* | 1121 | /* |
@@ -1378,9 +1357,6 @@ void uprobe_free_utask(struct task_struct *t) | |||
1378 | { | 1357 | { |
1379 | struct uprobe_task *utask = t->utask; | 1358 | struct uprobe_task *utask = t->utask; |
1380 | 1359 | ||
1381 | if (t->uprobe_srcu_id != -1) | ||
1382 | srcu_read_unlock_raw(&uprobes_srcu, t->uprobe_srcu_id); | ||
1383 | |||
1384 | if (!utask) | 1360 | if (!utask) |
1385 | return; | 1361 | return; |
1386 | 1362 | ||
@@ -1398,7 +1374,6 @@ void uprobe_free_utask(struct task_struct *t) | |||
1398 | void uprobe_copy_process(struct task_struct *t) | 1374 | void uprobe_copy_process(struct task_struct *t) |
1399 | { | 1375 | { |
1400 | t->utask = NULL; | 1376 | t->utask = NULL; |
1401 | t->uprobe_srcu_id = -1; | ||
1402 | } | 1377 | } |
1403 | 1378 | ||
1404 | /* | 1379 | /* |
@@ -1417,7 +1392,6 @@ static struct uprobe_task *add_utask(void) | |||
1417 | if (unlikely(!utask)) | 1392 | if (unlikely(!utask)) |
1418 | return NULL; | 1393 | return NULL; |
1419 | 1394 | ||
1420 | utask->active_uprobe = NULL; | ||
1421 | current->utask = utask; | 1395 | current->utask = utask; |
1422 | return utask; | 1396 | return utask; |
1423 | } | 1397 | } |
@@ -1479,41 +1453,64 @@ static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs) | |||
1479 | return false; | 1453 | return false; |
1480 | } | 1454 | } |
1481 | 1455 | ||
1456 | static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) | ||
1457 | { | ||
1458 | struct mm_struct *mm = current->mm; | ||
1459 | struct uprobe *uprobe = NULL; | ||
1460 | struct vm_area_struct *vma; | ||
1461 | |||
1462 | down_read(&mm->mmap_sem); | ||
1463 | vma = find_vma(mm, bp_vaddr); | ||
1464 | if (vma && vma->vm_start <= bp_vaddr) { | ||
1465 | if (valid_vma(vma, false)) { | ||
1466 | struct inode *inode; | ||
1467 | loff_t offset; | ||
1468 | |||
1469 | inode = vma->vm_file->f_mapping->host; | ||
1470 | offset = bp_vaddr - vma->vm_start; | ||
1471 | offset += (vma->vm_pgoff << PAGE_SHIFT); | ||
1472 | uprobe = find_uprobe(inode, offset); | ||
1473 | } | ||
1474 | |||
1475 | if (!uprobe) | ||
1476 | *is_swbp = is_swbp_at_addr(mm, bp_vaddr); | ||
1477 | } else { | ||
1478 | *is_swbp = -EFAULT; | ||
1479 | } | ||
1480 | up_read(&mm->mmap_sem); | ||
1481 | |||
1482 | return uprobe; | ||
1483 | } | ||
1484 | |||
1482 | /* | 1485 | /* |
1483 | * Run handler and ask thread to singlestep. | 1486 | * Run handler and ask thread to singlestep. |
1484 | * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. | 1487 | * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. |
1485 | */ | 1488 | */ |
1486 | static void handle_swbp(struct pt_regs *regs) | 1489 | static void handle_swbp(struct pt_regs *regs) |
1487 | { | 1490 | { |
1488 | struct vm_area_struct *vma; | ||
1489 | struct uprobe_task *utask; | 1491 | struct uprobe_task *utask; |
1490 | struct uprobe *uprobe; | 1492 | struct uprobe *uprobe; |
1491 | struct mm_struct *mm; | ||
1492 | unsigned long bp_vaddr; | 1493 | unsigned long bp_vaddr; |
1494 | int uninitialized_var(is_swbp); | ||
1493 | 1495 | ||
1494 | uprobe = NULL; | ||
1495 | bp_vaddr = uprobe_get_swbp_addr(regs); | 1496 | bp_vaddr = uprobe_get_swbp_addr(regs); |
1496 | mm = current->mm; | 1497 | uprobe = find_active_uprobe(bp_vaddr, &is_swbp); |
1497 | down_read(&mm->mmap_sem); | ||
1498 | vma = find_vma(mm, bp_vaddr); | ||
1499 | |||
1500 | if (vma && vma->vm_start <= bp_vaddr && valid_vma(vma, false)) { | ||
1501 | struct inode *inode; | ||
1502 | loff_t offset; | ||
1503 | |||
1504 | inode = vma->vm_file->f_mapping->host; | ||
1505 | offset = bp_vaddr - vma->vm_start; | ||
1506 | offset += (vma->vm_pgoff << PAGE_SHIFT); | ||
1507 | uprobe = find_uprobe(inode, offset); | ||
1508 | } | ||
1509 | |||
1510 | srcu_read_unlock_raw(&uprobes_srcu, current->uprobe_srcu_id); | ||
1511 | current->uprobe_srcu_id = -1; | ||
1512 | up_read(&mm->mmap_sem); | ||
1513 | 1498 | ||
1514 | if (!uprobe) { | 1499 | if (!uprobe) { |
1515 | /* No matching uprobe; signal SIGTRAP. */ | 1500 | if (is_swbp > 0) { |
1516 | send_sig(SIGTRAP, current, 0); | 1501 | /* No matching uprobe; signal SIGTRAP. */ |
1502 | send_sig(SIGTRAP, current, 0); | ||
1503 | } else { | ||
1504 | /* | ||
1505 | * Either we raced with uprobe_unregister() or we can't | ||
1506 | * access this memory. The latter is only possible if | ||
1507 | * another thread plays with our ->mm. In both cases | ||
1508 | * we can simply restart. If this vma was unmapped we | ||
1509 | * can pretend this insn was not executed yet and get | ||
1510 | * the (correct) SIGSEGV after restart. | ||
1511 | */ | ||
1512 | instruction_pointer_set(regs, bp_vaddr); | ||
1513 | } | ||
1517 | return; | 1514 | return; |
1518 | } | 1515 | } |
1519 | 1516 | ||
@@ -1620,7 +1617,6 @@ int uprobe_pre_sstep_notifier(struct pt_regs *regs) | |||
1620 | utask->state = UTASK_BP_HIT; | 1617 | utask->state = UTASK_BP_HIT; |
1621 | 1618 | ||
1622 | set_thread_flag(TIF_UPROBE); | 1619 | set_thread_flag(TIF_UPROBE); |
1623 | current->uprobe_srcu_id = srcu_read_lock_raw(&uprobes_srcu); | ||
1624 | 1620 | ||
1625 | return 1; | 1621 | return 1; |
1626 | } | 1622 | } |
@@ -1655,7 +1651,6 @@ static int __init init_uprobes(void) | |||
1655 | mutex_init(&uprobes_mutex[i]); | 1651 | mutex_init(&uprobes_mutex[i]); |
1656 | mutex_init(&uprobes_mmap_mutex[i]); | 1652 | mutex_init(&uprobes_mmap_mutex[i]); |
1657 | } | 1653 | } |
1658 | init_srcu_struct(&uprobes_srcu); | ||
1659 | 1654 | ||
1660 | return register_die_notifier(&uprobe_exception_nb); | 1655 | return register_die_notifier(&uprobe_exception_nb); |
1661 | } | 1656 | } |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index a008663d86c8..b4f20fba09fc 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -312,7 +312,7 @@ static int remove_ftrace_list_ops(struct ftrace_ops **list, | |||
312 | 312 | ||
313 | static int __register_ftrace_function(struct ftrace_ops *ops) | 313 | static int __register_ftrace_function(struct ftrace_ops *ops) |
314 | { | 314 | { |
315 | if (ftrace_disabled) | 315 | if (unlikely(ftrace_disabled)) |
316 | return -ENODEV; | 316 | return -ENODEV; |
317 | 317 | ||
318 | if (FTRACE_WARN_ON(ops == &global_ops)) | 318 | if (FTRACE_WARN_ON(ops == &global_ops)) |
@@ -4299,16 +4299,12 @@ int register_ftrace_function(struct ftrace_ops *ops) | |||
4299 | 4299 | ||
4300 | mutex_lock(&ftrace_lock); | 4300 | mutex_lock(&ftrace_lock); |
4301 | 4301 | ||
4302 | if (unlikely(ftrace_disabled)) | ||
4303 | goto out_unlock; | ||
4304 | |||
4305 | ret = __register_ftrace_function(ops); | 4302 | ret = __register_ftrace_function(ops); |
4306 | if (!ret) | 4303 | if (!ret) |
4307 | ret = ftrace_startup(ops, 0); | 4304 | ret = ftrace_startup(ops, 0); |
4308 | 4305 | ||
4309 | |||
4310 | out_unlock: | ||
4311 | mutex_unlock(&ftrace_lock); | 4306 | mutex_unlock(&ftrace_lock); |
4307 | |||
4312 | return ret; | 4308 | return ret; |
4313 | } | 4309 | } |
4314 | EXPORT_SYMBOL_GPL(register_ftrace_function); | 4310 | EXPORT_SYMBOL_GPL(register_ftrace_function); |
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index f765465bffe4..49491fa7daa2 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
@@ -3239,6 +3239,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) | |||
3239 | if (cpu_buffer->commit_page == cpu_buffer->reader_page) | 3239 | if (cpu_buffer->commit_page == cpu_buffer->reader_page) |
3240 | goto out; | 3240 | goto out; |
3241 | 3241 | ||
3242 | /* Don't bother swapping if the ring buffer is empty */ | ||
3243 | if (rb_num_of_entries(cpu_buffer) == 0) | ||
3244 | goto out; | ||
3245 | |||
3242 | /* | 3246 | /* |
3243 | * Reset the reader page to size zero. | 3247 | * Reset the reader page to size zero. |
3244 | */ | 3248 | */ |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index a7fa0702be1c..a120f98c4112 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -830,6 +830,8 @@ int register_tracer(struct tracer *type) | |||
830 | current_trace = saved_tracer; | 830 | current_trace = saved_tracer; |
831 | if (ret) { | 831 | if (ret) { |
832 | printk(KERN_CONT "FAILED!\n"); | 832 | printk(KERN_CONT "FAILED!\n"); |
833 | /* Add the warning after printing 'FAILED' */ | ||
834 | WARN_ON(1); | ||
833 | goto out; | 835 | goto out; |
834 | } | 836 | } |
835 | /* Only reset on passing, to avoid touching corrupted buffers */ | 837 | /* Only reset on passing, to avoid touching corrupted buffers */ |
@@ -1708,9 +1710,11 @@ EXPORT_SYMBOL_GPL(trace_vprintk); | |||
1708 | 1710 | ||
1709 | static void trace_iterator_increment(struct trace_iterator *iter) | 1711 | static void trace_iterator_increment(struct trace_iterator *iter) |
1710 | { | 1712 | { |
1713 | struct ring_buffer_iter *buf_iter = trace_buffer_iter(iter, iter->cpu); | ||
1714 | |||
1711 | iter->idx++; | 1715 | iter->idx++; |
1712 | if (iter->buffer_iter[iter->cpu]) | 1716 | if (buf_iter) |
1713 | ring_buffer_read(iter->buffer_iter[iter->cpu], NULL); | 1717 | ring_buffer_read(buf_iter, NULL); |
1714 | } | 1718 | } |
1715 | 1719 | ||
1716 | static struct trace_entry * | 1720 | static struct trace_entry * |
@@ -1718,7 +1722,7 @@ peek_next_entry(struct trace_iterator *iter, int cpu, u64 *ts, | |||
1718 | unsigned long *lost_events) | 1722 | unsigned long *lost_events) |
1719 | { | 1723 | { |
1720 | struct ring_buffer_event *event; | 1724 | struct ring_buffer_event *event; |
1721 | struct ring_buffer_iter *buf_iter = iter->buffer_iter[cpu]; | 1725 | struct ring_buffer_iter *buf_iter = trace_buffer_iter(iter, cpu); |
1722 | 1726 | ||
1723 | if (buf_iter) | 1727 | if (buf_iter) |
1724 | event = ring_buffer_iter_peek(buf_iter, ts); | 1728 | event = ring_buffer_iter_peek(buf_iter, ts); |
@@ -1856,10 +1860,10 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu) | |||
1856 | 1860 | ||
1857 | tr->data[cpu]->skipped_entries = 0; | 1861 | tr->data[cpu]->skipped_entries = 0; |
1858 | 1862 | ||
1859 | if (!iter->buffer_iter[cpu]) | 1863 | buf_iter = trace_buffer_iter(iter, cpu); |
1864 | if (!buf_iter) | ||
1860 | return; | 1865 | return; |
1861 | 1866 | ||
1862 | buf_iter = iter->buffer_iter[cpu]; | ||
1863 | ring_buffer_iter_reset(buf_iter); | 1867 | ring_buffer_iter_reset(buf_iter); |
1864 | 1868 | ||
1865 | /* | 1869 | /* |
@@ -2205,13 +2209,15 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter) | |||
2205 | 2209 | ||
2206 | int trace_empty(struct trace_iterator *iter) | 2210 | int trace_empty(struct trace_iterator *iter) |
2207 | { | 2211 | { |
2212 | struct ring_buffer_iter *buf_iter; | ||
2208 | int cpu; | 2213 | int cpu; |
2209 | 2214 | ||
2210 | /* If we are looking at one CPU buffer, only check that one */ | 2215 | /* If we are looking at one CPU buffer, only check that one */ |
2211 | if (iter->cpu_file != TRACE_PIPE_ALL_CPU) { | 2216 | if (iter->cpu_file != TRACE_PIPE_ALL_CPU) { |
2212 | cpu = iter->cpu_file; | 2217 | cpu = iter->cpu_file; |
2213 | if (iter->buffer_iter[cpu]) { | 2218 | buf_iter = trace_buffer_iter(iter, cpu); |
2214 | if (!ring_buffer_iter_empty(iter->buffer_iter[cpu])) | 2219 | if (buf_iter) { |
2220 | if (!ring_buffer_iter_empty(buf_iter)) | ||
2215 | return 0; | 2221 | return 0; |
2216 | } else { | 2222 | } else { |
2217 | if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu)) | 2223 | if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu)) |
@@ -2221,8 +2227,9 @@ int trace_empty(struct trace_iterator *iter) | |||
2221 | } | 2227 | } |
2222 | 2228 | ||
2223 | for_each_tracing_cpu(cpu) { | 2229 | for_each_tracing_cpu(cpu) { |
2224 | if (iter->buffer_iter[cpu]) { | 2230 | buf_iter = trace_buffer_iter(iter, cpu); |
2225 | if (!ring_buffer_iter_empty(iter->buffer_iter[cpu])) | 2231 | if (buf_iter) { |
2232 | if (!ring_buffer_iter_empty(buf_iter)) | ||
2226 | return 0; | 2233 | return 0; |
2227 | } else { | 2234 | } else { |
2228 | if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu)) | 2235 | if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu)) |
@@ -2381,6 +2388,11 @@ __tracing_open(struct inode *inode, struct file *file) | |||
2381 | if (!iter) | 2388 | if (!iter) |
2382 | return ERR_PTR(-ENOMEM); | 2389 | return ERR_PTR(-ENOMEM); |
2383 | 2390 | ||
2391 | iter->buffer_iter = kzalloc(sizeof(*iter->buffer_iter) * num_possible_cpus(), | ||
2392 | GFP_KERNEL); | ||
2393 | if (!iter->buffer_iter) | ||
2394 | goto release; | ||
2395 | |||
2384 | /* | 2396 | /* |
2385 | * We make a copy of the current tracer to avoid concurrent | 2397 | * We make a copy of the current tracer to avoid concurrent |
2386 | * changes on it while we are reading. | 2398 | * changes on it while we are reading. |
@@ -2441,6 +2453,8 @@ __tracing_open(struct inode *inode, struct file *file) | |||
2441 | fail: | 2453 | fail: |
2442 | mutex_unlock(&trace_types_lock); | 2454 | mutex_unlock(&trace_types_lock); |
2443 | kfree(iter->trace); | 2455 | kfree(iter->trace); |
2456 | kfree(iter->buffer_iter); | ||
2457 | release: | ||
2444 | seq_release_private(inode, file); | 2458 | seq_release_private(inode, file); |
2445 | return ERR_PTR(-ENOMEM); | 2459 | return ERR_PTR(-ENOMEM); |
2446 | } | 2460 | } |
@@ -2481,6 +2495,7 @@ static int tracing_release(struct inode *inode, struct file *file) | |||
2481 | mutex_destroy(&iter->mutex); | 2495 | mutex_destroy(&iter->mutex); |
2482 | free_cpumask_var(iter->started); | 2496 | free_cpumask_var(iter->started); |
2483 | kfree(iter->trace); | 2497 | kfree(iter->trace); |
2498 | kfree(iter->buffer_iter); | ||
2484 | seq_release_private(inode, file); | 2499 | seq_release_private(inode, file); |
2485 | return 0; | 2500 | return 0; |
2486 | } | 2501 | } |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 5aec220d2de0..55e1f7f0db12 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -317,6 +317,14 @@ struct tracer { | |||
317 | 317 | ||
318 | #define TRACE_PIPE_ALL_CPU -1 | 318 | #define TRACE_PIPE_ALL_CPU -1 |
319 | 319 | ||
320 | static inline struct ring_buffer_iter * | ||
321 | trace_buffer_iter(struct trace_iterator *iter, int cpu) | ||
322 | { | ||
323 | if (iter->buffer_iter && iter->buffer_iter[cpu]) | ||
324 | return iter->buffer_iter[cpu]; | ||
325 | return NULL; | ||
326 | } | ||
327 | |||
320 | int tracer_init(struct tracer *t, struct trace_array *tr); | 328 | int tracer_init(struct tracer *t, struct trace_array *tr); |
321 | int tracing_is_enabled(void); | 329 | int tracing_is_enabled(void); |
322 | void trace_wake_up(void); | 330 | void trace_wake_up(void); |
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index a7d2a4c653d8..ce27c8ba8d31 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -538,7 +538,7 @@ get_return_for_leaf(struct trace_iterator *iter, | |||
538 | next = &data->ret; | 538 | next = &data->ret; |
539 | } else { | 539 | } else { |
540 | 540 | ||
541 | ring_iter = iter->buffer_iter[iter->cpu]; | 541 | ring_iter = trace_buffer_iter(iter, iter->cpu); |
542 | 542 | ||
543 | /* First peek to compare current entry and the next one */ | 543 | /* First peek to compare current entry and the next one */ |
544 | if (ring_iter) | 544 | if (ring_iter) |
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index df611a0e76c5..123b189c732c 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c | |||
@@ -1325,4 +1325,4 @@ __init static int init_events(void) | |||
1325 | 1325 | ||
1326 | return 0; | 1326 | return 0; |
1327 | } | 1327 | } |
1328 | device_initcall(init_events); | 1328 | early_initcall(init_events); |
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 3d69aa9ff51e..46c2f6b7b123 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile | |||
@@ -250,8 +250,12 @@ endef | |||
250 | all_objs := $(sort $(ALL_OBJS)) | 250 | all_objs := $(sort $(ALL_OBJS)) |
251 | all_deps := $(all_objs:%.o=.%.d) | 251 | all_deps := $(all_objs:%.o=.%.d) |
252 | 252 | ||
253 | # let .d file also depends on the source and header files | ||
253 | define check_deps | 254 | define check_deps |
254 | $(CC) -M $(CFLAGS) $< > $@; | 255 | @set -e; $(RM) $@; \ |
256 | $(CC) -M $(CFLAGS) $< > $@.$$$$; \ | ||
257 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ | ||
258 | $(RM) $@.$$$$ | ||
255 | endef | 259 | endef |
256 | 260 | ||
257 | $(gui_deps): ks_version.h | 261 | $(gui_deps): ks_version.h |
@@ -270,11 +274,13 @@ endif | |||
270 | 274 | ||
271 | tags: force | 275 | tags: force |
272 | $(RM) tags | 276 | $(RM) tags |
273 | find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px | 277 | find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ |
278 | --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' | ||
274 | 279 | ||
275 | TAGS: force | 280 | TAGS: force |
276 | $(RM) TAGS | 281 | $(RM) TAGS |
277 | find . -name '*.[ch]' | xargs etags | 282 | find . -name '*.[ch]' | xargs etags \ |
283 | --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' | ||
278 | 284 | ||
279 | define do_install | 285 | define do_install |
280 | $(print_install) \ | 286 | $(print_install) \ |
@@ -290,7 +296,7 @@ install_lib: all_cmd install_plugins install_python | |||
290 | install: install_lib | 296 | install: install_lib |
291 | 297 | ||
292 | clean: | 298 | clean: |
293 | $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES).*.d | 299 | $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d |
294 | $(RM) tags TAGS | 300 | $(RM) tags TAGS |
295 | 301 | ||
296 | endif # skip-makefile | 302 | endif # skip-makefile |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 554828219c33..5f34aa371b56 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -467,8 +467,10 @@ int pevent_register_function(struct pevent *pevent, char *func, | |||
467 | item->mod = NULL; | 467 | item->mod = NULL; |
468 | item->addr = addr; | 468 | item->addr = addr; |
469 | 469 | ||
470 | pevent->funclist = item; | 470 | if (!item->func || (mod && !item->mod)) |
471 | die("malloc func"); | ||
471 | 472 | ||
473 | pevent->funclist = item; | ||
472 | pevent->func_count++; | 474 | pevent->func_count++; |
473 | 475 | ||
474 | return 0; | 476 | return 0; |
@@ -511,12 +513,12 @@ struct printk_list { | |||
511 | 513 | ||
512 | static int printk_cmp(const void *a, const void *b) | 514 | static int printk_cmp(const void *a, const void *b) |
513 | { | 515 | { |
514 | const struct func_map *fa = a; | 516 | const struct printk_map *pa = a; |
515 | const struct func_map *fb = b; | 517 | const struct printk_map *pb = b; |
516 | 518 | ||
517 | if (fa->addr < fb->addr) | 519 | if (pa->addr < pb->addr) |
518 | return -1; | 520 | return -1; |
519 | if (fa->addr > fb->addr) | 521 | if (pa->addr > pb->addr) |
520 | return 1; | 522 | return 1; |
521 | 523 | ||
522 | return 0; | 524 | return 0; |
@@ -583,10 +585,13 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt, | |||
583 | item = malloc_or_die(sizeof(*item)); | 585 | item = malloc_or_die(sizeof(*item)); |
584 | 586 | ||
585 | item->next = pevent->printklist; | 587 | item->next = pevent->printklist; |
586 | pevent->printklist = item; | ||
587 | item->printk = strdup(fmt); | 588 | item->printk = strdup(fmt); |
588 | item->addr = addr; | 589 | item->addr = addr; |
589 | 590 | ||
591 | if (!item->printk) | ||
592 | die("malloc fmt"); | ||
593 | |||
594 | pevent->printklist = item; | ||
590 | pevent->printk_count++; | 595 | pevent->printk_count++; |
591 | 596 | ||
592 | return 0; | 597 | return 0; |
@@ -616,7 +621,9 @@ static struct event_format *alloc_event(void) | |||
616 | { | 621 | { |
617 | struct event_format *event; | 622 | struct event_format *event; |
618 | 623 | ||
619 | event = malloc_or_die(sizeof(*event)); | 624 | event = malloc(sizeof(*event)); |
625 | if (!event) | ||
626 | return NULL; | ||
620 | memset(event, 0, sizeof(*event)); | 627 | memset(event, 0, sizeof(*event)); |
621 | 628 | ||
622 | return event; | 629 | return event; |
@@ -626,12 +633,8 @@ static void add_event(struct pevent *pevent, struct event_format *event) | |||
626 | { | 633 | { |
627 | int i; | 634 | int i; |
628 | 635 | ||
629 | if (!pevent->events) | 636 | pevent->events = realloc(pevent->events, sizeof(event) * |
630 | pevent->events = malloc_or_die(sizeof(event)); | 637 | (pevent->nr_events + 1)); |
631 | else | ||
632 | pevent->events = | ||
633 | realloc(pevent->events, sizeof(event) * | ||
634 | (pevent->nr_events + 1)); | ||
635 | if (!pevent->events) | 638 | if (!pevent->events) |
636 | die("Can not allocate events"); | 639 | die("Can not allocate events"); |
637 | 640 | ||
@@ -697,6 +700,10 @@ static void free_arg(struct print_arg *arg) | |||
697 | free_arg(arg->symbol.field); | 700 | free_arg(arg->symbol.field); |
698 | free_flag_sym(arg->symbol.symbols); | 701 | free_flag_sym(arg->symbol.symbols); |
699 | break; | 702 | break; |
703 | case PRINT_HEX: | ||
704 | free_arg(arg->hex.field); | ||
705 | free_arg(arg->hex.size); | ||
706 | break; | ||
700 | case PRINT_TYPE: | 707 | case PRINT_TYPE: |
701 | free(arg->typecast.type); | 708 | free(arg->typecast.type); |
702 | free_arg(arg->typecast.item); | 709 | free_arg(arg->typecast.item); |
@@ -775,6 +782,25 @@ int pevent_peek_char(void) | |||
775 | return __peek_char(); | 782 | return __peek_char(); |
776 | } | 783 | } |
777 | 784 | ||
785 | static int extend_token(char **tok, char *buf, int size) | ||
786 | { | ||
787 | char *newtok = realloc(*tok, size); | ||
788 | |||
789 | if (!newtok) { | ||
790 | free(*tok); | ||
791 | *tok = NULL; | ||
792 | return -1; | ||
793 | } | ||
794 | |||
795 | if (!*tok) | ||
796 | strcpy(newtok, buf); | ||
797 | else | ||
798 | strcat(newtok, buf); | ||
799 | *tok = newtok; | ||
800 | |||
801 | return 0; | ||
802 | } | ||
803 | |||
778 | static enum event_type force_token(const char *str, char **tok); | 804 | static enum event_type force_token(const char *str, char **tok); |
779 | 805 | ||
780 | static enum event_type __read_token(char **tok) | 806 | static enum event_type __read_token(char **tok) |
@@ -859,17 +885,10 @@ static enum event_type __read_token(char **tok) | |||
859 | do { | 885 | do { |
860 | if (i == (BUFSIZ - 1)) { | 886 | if (i == (BUFSIZ - 1)) { |
861 | buf[i] = 0; | 887 | buf[i] = 0; |
862 | if (*tok) { | 888 | tok_size += BUFSIZ; |
863 | *tok = realloc(*tok, tok_size + BUFSIZ); | ||
864 | if (!*tok) | ||
865 | return EVENT_NONE; | ||
866 | strcat(*tok, buf); | ||
867 | } else | ||
868 | *tok = strdup(buf); | ||
869 | 889 | ||
870 | if (!*tok) | 890 | if (extend_token(tok, buf, tok_size) < 0) |
871 | return EVENT_NONE; | 891 | return EVENT_NONE; |
872 | tok_size += BUFSIZ; | ||
873 | i = 0; | 892 | i = 0; |
874 | } | 893 | } |
875 | last_ch = ch; | 894 | last_ch = ch; |
@@ -908,17 +927,10 @@ static enum event_type __read_token(char **tok) | |||
908 | while (get_type(__peek_char()) == type) { | 927 | while (get_type(__peek_char()) == type) { |
909 | if (i == (BUFSIZ - 1)) { | 928 | if (i == (BUFSIZ - 1)) { |
910 | buf[i] = 0; | 929 | buf[i] = 0; |
911 | if (*tok) { | 930 | tok_size += BUFSIZ; |
912 | *tok = realloc(*tok, tok_size + BUFSIZ); | ||
913 | if (!*tok) | ||
914 | return EVENT_NONE; | ||
915 | strcat(*tok, buf); | ||
916 | } else | ||
917 | *tok = strdup(buf); | ||
918 | 931 | ||
919 | if (!*tok) | 932 | if (extend_token(tok, buf, tok_size) < 0) |
920 | return EVENT_NONE; | 933 | return EVENT_NONE; |
921 | tok_size += BUFSIZ; | ||
922 | i = 0; | 934 | i = 0; |
923 | } | 935 | } |
924 | ch = __read_char(); | 936 | ch = __read_char(); |
@@ -927,14 +939,7 @@ static enum event_type __read_token(char **tok) | |||
927 | 939 | ||
928 | out: | 940 | out: |
929 | buf[i] = 0; | 941 | buf[i] = 0; |
930 | if (*tok) { | 942 | if (extend_token(tok, buf, tok_size + i + 1) < 0) |
931 | *tok = realloc(*tok, tok_size + i); | ||
932 | if (!*tok) | ||
933 | return EVENT_NONE; | ||
934 | strcat(*tok, buf); | ||
935 | } else | ||
936 | *tok = strdup(buf); | ||
937 | if (!*tok) | ||
938 | return EVENT_NONE; | 943 | return EVENT_NONE; |
939 | 944 | ||
940 | if (type == EVENT_ITEM) { | 945 | if (type == EVENT_ITEM) { |
@@ -1255,9 +1260,15 @@ static int event_read_fields(struct event_format *event, struct format_field **f | |||
1255 | field->flags |= FIELD_IS_POINTER; | 1260 | field->flags |= FIELD_IS_POINTER; |
1256 | 1261 | ||
1257 | if (field->type) { | 1262 | if (field->type) { |
1258 | field->type = realloc(field->type, | 1263 | char *new_type; |
1259 | strlen(field->type) + | 1264 | new_type = realloc(field->type, |
1260 | strlen(last_token) + 2); | 1265 | strlen(field->type) + |
1266 | strlen(last_token) + 2); | ||
1267 | if (!new_type) { | ||
1268 | free(last_token); | ||
1269 | goto fail; | ||
1270 | } | ||
1271 | field->type = new_type; | ||
1261 | strcat(field->type, " "); | 1272 | strcat(field->type, " "); |
1262 | strcat(field->type, last_token); | 1273 | strcat(field->type, last_token); |
1263 | free(last_token); | 1274 | free(last_token); |
@@ -1282,6 +1293,7 @@ static int event_read_fields(struct event_format *event, struct format_field **f | |||
1282 | if (strcmp(token, "[") == 0) { | 1293 | if (strcmp(token, "[") == 0) { |
1283 | enum event_type last_type = type; | 1294 | enum event_type last_type = type; |
1284 | char *brackets = token; | 1295 | char *brackets = token; |
1296 | char *new_brackets; | ||
1285 | int len; | 1297 | int len; |
1286 | 1298 | ||
1287 | field->flags |= FIELD_IS_ARRAY; | 1299 | field->flags |= FIELD_IS_ARRAY; |
@@ -1301,9 +1313,14 @@ static int event_read_fields(struct event_format *event, struct format_field **f | |||
1301 | len = 1; | 1313 | len = 1; |
1302 | last_type = type; | 1314 | last_type = type; |
1303 | 1315 | ||
1304 | brackets = realloc(brackets, | 1316 | new_brackets = realloc(brackets, |
1305 | strlen(brackets) + | 1317 | strlen(brackets) + |
1306 | strlen(token) + len); | 1318 | strlen(token) + len); |
1319 | if (!new_brackets) { | ||
1320 | free(brackets); | ||
1321 | goto fail; | ||
1322 | } | ||
1323 | brackets = new_brackets; | ||
1307 | if (len == 2) | 1324 | if (len == 2) |
1308 | strcat(brackets, " "); | 1325 | strcat(brackets, " "); |
1309 | strcat(brackets, token); | 1326 | strcat(brackets, token); |
@@ -1319,7 +1336,12 @@ static int event_read_fields(struct event_format *event, struct format_field **f | |||
1319 | 1336 | ||
1320 | free_token(token); | 1337 | free_token(token); |
1321 | 1338 | ||
1322 | brackets = realloc(brackets, strlen(brackets) + 2); | 1339 | new_brackets = realloc(brackets, strlen(brackets) + 2); |
1340 | if (!new_brackets) { | ||
1341 | free(brackets); | ||
1342 | goto fail; | ||
1343 | } | ||
1344 | brackets = new_brackets; | ||
1323 | strcat(brackets, "]"); | 1345 | strcat(brackets, "]"); |
1324 | 1346 | ||
1325 | /* add brackets to type */ | 1347 | /* add brackets to type */ |
@@ -1330,10 +1352,16 @@ static int event_read_fields(struct event_format *event, struct format_field **f | |||
1330 | * the format: type [] item; | 1352 | * the format: type [] item; |
1331 | */ | 1353 | */ |
1332 | if (type == EVENT_ITEM) { | 1354 | if (type == EVENT_ITEM) { |
1333 | field->type = realloc(field->type, | 1355 | char *new_type; |
1334 | strlen(field->type) + | 1356 | new_type = realloc(field->type, |
1335 | strlen(field->name) + | 1357 | strlen(field->type) + |
1336 | strlen(brackets) + 2); | 1358 | strlen(field->name) + |
1359 | strlen(brackets) + 2); | ||
1360 | if (!new_type) { | ||
1361 | free(brackets); | ||
1362 | goto fail; | ||
1363 | } | ||
1364 | field->type = new_type; | ||
1337 | strcat(field->type, " "); | 1365 | strcat(field->type, " "); |
1338 | strcat(field->type, field->name); | 1366 | strcat(field->type, field->name); |
1339 | free_token(field->name); | 1367 | free_token(field->name); |
@@ -1341,9 +1369,15 @@ static int event_read_fields(struct event_format *event, struct format_field **f | |||
1341 | field->name = token; | 1369 | field->name = token; |
1342 | type = read_token(&token); | 1370 | type = read_token(&token); |
1343 | } else { | 1371 | } else { |
1344 | field->type = realloc(field->type, | 1372 | char *new_type; |
1345 | strlen(field->type) + | 1373 | new_type = realloc(field->type, |
1346 | strlen(brackets) + 1); | 1374 | strlen(field->type) + |
1375 | strlen(brackets) + 1); | ||
1376 | if (!new_type) { | ||
1377 | free(brackets); | ||
1378 | goto fail; | ||
1379 | } | ||
1380 | field->type = new_type; | ||
1347 | strcat(field->type, brackets); | 1381 | strcat(field->type, brackets); |
1348 | } | 1382 | } |
1349 | free(brackets); | 1383 | free(brackets); |
@@ -1726,10 +1760,16 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok) | |||
1726 | /* could just be a type pointer */ | 1760 | /* could just be a type pointer */ |
1727 | if ((strcmp(arg->op.op, "*") == 0) && | 1761 | if ((strcmp(arg->op.op, "*") == 0) && |
1728 | type == EVENT_DELIM && (strcmp(token, ")") == 0)) { | 1762 | type == EVENT_DELIM && (strcmp(token, ")") == 0)) { |
1763 | char *new_atom; | ||
1764 | |||
1729 | if (left->type != PRINT_ATOM) | 1765 | if (left->type != PRINT_ATOM) |
1730 | die("bad pointer type"); | 1766 | die("bad pointer type"); |
1731 | left->atom.atom = realloc(left->atom.atom, | 1767 | new_atom = realloc(left->atom.atom, |
1732 | strlen(left->atom.atom) + 3); | 1768 | strlen(left->atom.atom) + 3); |
1769 | if (!new_atom) | ||
1770 | goto out_free; | ||
1771 | |||
1772 | left->atom.atom = new_atom; | ||
1733 | strcat(left->atom.atom, " *"); | 1773 | strcat(left->atom.atom, " *"); |
1734 | free(arg->op.op); | 1774 | free(arg->op.op); |
1735 | *arg = *left; | 1775 | *arg = *left; |
@@ -2146,6 +2186,8 @@ process_fields(struct event_format *event, struct print_flag_sym **list, char ** | |||
2146 | if (value == NULL) | 2186 | if (value == NULL) |
2147 | goto out_free; | 2187 | goto out_free; |
2148 | field->value = strdup(value); | 2188 | field->value = strdup(value); |
2189 | if (field->value == NULL) | ||
2190 | goto out_free; | ||
2149 | 2191 | ||
2150 | free_arg(arg); | 2192 | free_arg(arg); |
2151 | arg = alloc_arg(); | 2193 | arg = alloc_arg(); |
@@ -2159,6 +2201,8 @@ process_fields(struct event_format *event, struct print_flag_sym **list, char ** | |||
2159 | if (value == NULL) | 2201 | if (value == NULL) |
2160 | goto out_free; | 2202 | goto out_free; |
2161 | field->str = strdup(value); | 2203 | field->str = strdup(value); |
2204 | if (field->str == NULL) | ||
2205 | goto out_free; | ||
2162 | free_arg(arg); | 2206 | free_arg(arg); |
2163 | arg = NULL; | 2207 | arg = NULL; |
2164 | 2208 | ||
@@ -2260,6 +2304,45 @@ process_symbols(struct event_format *event, struct print_arg *arg, char **tok) | |||
2260 | } | 2304 | } |
2261 | 2305 | ||
2262 | static enum event_type | 2306 | static enum event_type |
2307 | process_hex(struct event_format *event, struct print_arg *arg, char **tok) | ||
2308 | { | ||
2309 | struct print_arg *field; | ||
2310 | enum event_type type; | ||
2311 | char *token; | ||
2312 | |||
2313 | memset(arg, 0, sizeof(*arg)); | ||
2314 | arg->type = PRINT_HEX; | ||
2315 | |||
2316 | field = alloc_arg(); | ||
2317 | type = process_arg(event, field, &token); | ||
2318 | |||
2319 | if (test_type_token(type, token, EVENT_DELIM, ",")) | ||
2320 | goto out_free; | ||
2321 | |||
2322 | arg->hex.field = field; | ||
2323 | |||
2324 | free_token(token); | ||
2325 | |||
2326 | field = alloc_arg(); | ||
2327 | type = process_arg(event, field, &token); | ||
2328 | |||
2329 | if (test_type_token(type, token, EVENT_DELIM, ")")) | ||
2330 | goto out_free; | ||
2331 | |||
2332 | arg->hex.size = field; | ||
2333 | |||
2334 | free_token(token); | ||
2335 | type = read_token_item(tok); | ||
2336 | return type; | ||
2337 | |||
2338 | out_free: | ||
2339 | free_arg(field); | ||
2340 | free_token(token); | ||
2341 | *tok = NULL; | ||
2342 | return EVENT_ERROR; | ||
2343 | } | ||
2344 | |||
2345 | static enum event_type | ||
2263 | process_dynamic_array(struct event_format *event, struct print_arg *arg, char **tok) | 2346 | process_dynamic_array(struct event_format *event, struct print_arg *arg, char **tok) |
2264 | { | 2347 | { |
2265 | struct format_field *field; | 2348 | struct format_field *field; |
@@ -2488,6 +2571,10 @@ process_function(struct event_format *event, struct print_arg *arg, | |||
2488 | is_symbolic_field = 1; | 2571 | is_symbolic_field = 1; |
2489 | return process_symbols(event, arg, tok); | 2572 | return process_symbols(event, arg, tok); |
2490 | } | 2573 | } |
2574 | if (strcmp(token, "__print_hex") == 0) { | ||
2575 | free_token(token); | ||
2576 | return process_hex(event, arg, tok); | ||
2577 | } | ||
2491 | if (strcmp(token, "__get_str") == 0) { | 2578 | if (strcmp(token, "__get_str") == 0) { |
2492 | free_token(token); | 2579 | free_token(token); |
2493 | return process_str(event, arg, tok); | 2580 | return process_str(event, arg, tok); |
@@ -2541,7 +2628,16 @@ process_arg_token(struct event_format *event, struct print_arg *arg, | |||
2541 | } | 2628 | } |
2542 | /* atoms can be more than one token long */ | 2629 | /* atoms can be more than one token long */ |
2543 | while (type == EVENT_ITEM) { | 2630 | while (type == EVENT_ITEM) { |
2544 | atom = realloc(atom, strlen(atom) + strlen(token) + 2); | 2631 | char *new_atom; |
2632 | new_atom = realloc(atom, | ||
2633 | strlen(atom) + strlen(token) + 2); | ||
2634 | if (!new_atom) { | ||
2635 | free(atom); | ||
2636 | *tok = NULL; | ||
2637 | free_token(token); | ||
2638 | return EVENT_ERROR; | ||
2639 | } | ||
2640 | atom = new_atom; | ||
2545 | strcat(atom, " "); | 2641 | strcat(atom, " "); |
2546 | strcat(atom, token); | 2642 | strcat(atom, token); |
2547 | free_token(token); | 2643 | free_token(token); |
@@ -2835,7 +2931,7 @@ static int get_common_info(struct pevent *pevent, | |||
2835 | event = pevent->events[0]; | 2931 | event = pevent->events[0]; |
2836 | field = pevent_find_common_field(event, type); | 2932 | field = pevent_find_common_field(event, type); |
2837 | if (!field) | 2933 | if (!field) |
2838 | die("field '%s' not found", type); | 2934 | return -1; |
2839 | 2935 | ||
2840 | *offset = field->offset; | 2936 | *offset = field->offset; |
2841 | *size = field->size; | 2937 | *size = field->size; |
@@ -2886,15 +2982,16 @@ static int parse_common_flags(struct pevent *pevent, void *data) | |||
2886 | 2982 | ||
2887 | static int parse_common_lock_depth(struct pevent *pevent, void *data) | 2983 | static int parse_common_lock_depth(struct pevent *pevent, void *data) |
2888 | { | 2984 | { |
2889 | int ret; | 2985 | return __parse_common(pevent, data, |
2890 | 2986 | &pevent->ld_size, &pevent->ld_offset, | |
2891 | ret = __parse_common(pevent, data, | 2987 | "common_lock_depth"); |
2892 | &pevent->ld_size, &pevent->ld_offset, | 2988 | } |
2893 | "common_lock_depth"); | ||
2894 | if (ret < 0) | ||
2895 | return -1; | ||
2896 | 2989 | ||
2897 | return ret; | 2990 | static int parse_common_migrate_disable(struct pevent *pevent, void *data) |
2991 | { | ||
2992 | return __parse_common(pevent, data, | ||
2993 | &pevent->ld_size, &pevent->ld_offset, | ||
2994 | "common_migrate_disable"); | ||
2898 | } | 2995 | } |
2899 | 2996 | ||
2900 | static int events_id_cmp(const void *a, const void *b); | 2997 | static int events_id_cmp(const void *a, const void *b); |
@@ -2995,6 +3092,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg | |||
2995 | break; | 3092 | break; |
2996 | case PRINT_FLAGS: | 3093 | case PRINT_FLAGS: |
2997 | case PRINT_SYMBOL: | 3094 | case PRINT_SYMBOL: |
3095 | case PRINT_HEX: | ||
2998 | break; | 3096 | break; |
2999 | case PRINT_TYPE: | 3097 | case PRINT_TYPE: |
3000 | val = eval_num_arg(data, size, event, arg->typecast.item); | 3098 | val = eval_num_arg(data, size, event, arg->typecast.item); |
@@ -3214,11 +3312,13 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3214 | { | 3312 | { |
3215 | struct pevent *pevent = event->pevent; | 3313 | struct pevent *pevent = event->pevent; |
3216 | struct print_flag_sym *flag; | 3314 | struct print_flag_sym *flag; |
3315 | struct format_field *field; | ||
3217 | unsigned long long val, fval; | 3316 | unsigned long long val, fval; |
3218 | unsigned long addr; | 3317 | unsigned long addr; |
3219 | char *str; | 3318 | char *str; |
3319 | unsigned char *hex; | ||
3220 | int print; | 3320 | int print; |
3221 | int len; | 3321 | int i, len; |
3222 | 3322 | ||
3223 | switch (arg->type) { | 3323 | switch (arg->type) { |
3224 | case PRINT_NULL: | 3324 | case PRINT_NULL: |
@@ -3228,27 +3328,29 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3228 | print_str_to_seq(s, format, len_arg, arg->atom.atom); | 3328 | print_str_to_seq(s, format, len_arg, arg->atom.atom); |
3229 | return; | 3329 | return; |
3230 | case PRINT_FIELD: | 3330 | case PRINT_FIELD: |
3231 | if (!arg->field.field) { | 3331 | field = arg->field.field; |
3232 | arg->field.field = pevent_find_any_field(event, arg->field.name); | 3332 | if (!field) { |
3233 | if (!arg->field.field) | 3333 | field = pevent_find_any_field(event, arg->field.name); |
3334 | if (!field) | ||
3234 | die("field %s not found", arg->field.name); | 3335 | die("field %s not found", arg->field.name); |
3336 | arg->field.field = field; | ||
3235 | } | 3337 | } |
3236 | /* Zero sized fields, mean the rest of the data */ | 3338 | /* Zero sized fields, mean the rest of the data */ |
3237 | len = arg->field.field->size ? : size - arg->field.field->offset; | 3339 | len = field->size ? : size - field->offset; |
3238 | 3340 | ||
3239 | /* | 3341 | /* |
3240 | * Some events pass in pointers. If this is not an array | 3342 | * Some events pass in pointers. If this is not an array |
3241 | * and the size is the same as long_size, assume that it | 3343 | * and the size is the same as long_size, assume that it |
3242 | * is a pointer. | 3344 | * is a pointer. |
3243 | */ | 3345 | */ |
3244 | if (!(arg->field.field->flags & FIELD_IS_ARRAY) && | 3346 | if (!(field->flags & FIELD_IS_ARRAY) && |
3245 | arg->field.field->size == pevent->long_size) { | 3347 | field->size == pevent->long_size) { |
3246 | addr = *(unsigned long *)(data + arg->field.field->offset); | 3348 | addr = *(unsigned long *)(data + field->offset); |
3247 | trace_seq_printf(s, "%lx", addr); | 3349 | trace_seq_printf(s, "%lx", addr); |
3248 | break; | 3350 | break; |
3249 | } | 3351 | } |
3250 | str = malloc_or_die(len + 1); | 3352 | str = malloc_or_die(len + 1); |
3251 | memcpy(str, data + arg->field.field->offset, len); | 3353 | memcpy(str, data + field->offset, len); |
3252 | str[len] = 0; | 3354 | str[len] = 0; |
3253 | print_str_to_seq(s, format, len_arg, str); | 3355 | print_str_to_seq(s, format, len_arg, str); |
3254 | free(str); | 3356 | free(str); |
@@ -3281,6 +3383,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3281 | } | 3383 | } |
3282 | } | 3384 | } |
3283 | break; | 3385 | break; |
3386 | case PRINT_HEX: | ||
3387 | field = arg->hex.field->field.field; | ||
3388 | if (!field) { | ||
3389 | str = arg->hex.field->field.name; | ||
3390 | field = pevent_find_any_field(event, str); | ||
3391 | if (!field) | ||
3392 | die("field %s not found", str); | ||
3393 | arg->hex.field->field.field = field; | ||
3394 | } | ||
3395 | hex = data + field->offset; | ||
3396 | len = eval_num_arg(data, size, event, arg->hex.size); | ||
3397 | for (i = 0; i < len; i++) { | ||
3398 | if (i) | ||
3399 | trace_seq_putc(s, ' '); | ||
3400 | trace_seq_printf(s, "%02x", hex[i]); | ||
3401 | } | ||
3402 | break; | ||
3284 | 3403 | ||
3285 | case PRINT_TYPE: | 3404 | case PRINT_TYPE: |
3286 | break; | 3405 | break; |
@@ -3299,7 +3418,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3299 | break; | 3418 | break; |
3300 | } | 3419 | } |
3301 | case PRINT_BSTRING: | 3420 | case PRINT_BSTRING: |
3302 | trace_seq_printf(s, format, arg->string.string); | 3421 | print_str_to_seq(s, format, len_arg, arg->string.string); |
3303 | break; | 3422 | break; |
3304 | case PRINT_OP: | 3423 | case PRINT_OP: |
3305 | /* | 3424 | /* |
@@ -3363,6 +3482,10 @@ process_defined_func(struct trace_seq *s, void *data, int size, | |||
3363 | string = malloc_or_die(sizeof(*string)); | 3482 | string = malloc_or_die(sizeof(*string)); |
3364 | string->next = strings; | 3483 | string->next = strings; |
3365 | string->str = strdup(str.buffer); | 3484 | string->str = strdup(str.buffer); |
3485 | if (!string->str) | ||
3486 | die("malloc str"); | ||
3487 | |||
3488 | args[i] = (unsigned long long)string->str; | ||
3366 | strings = string; | 3489 | strings = string; |
3367 | trace_seq_destroy(&str); | 3490 | trace_seq_destroy(&str); |
3368 | break; | 3491 | break; |
@@ -3400,6 +3523,7 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc | |||
3400 | unsigned long long ip, val; | 3523 | unsigned long long ip, val; |
3401 | char *ptr; | 3524 | char *ptr; |
3402 | void *bptr; | 3525 | void *bptr; |
3526 | int vsize; | ||
3403 | 3527 | ||
3404 | field = pevent->bprint_buf_field; | 3528 | field = pevent->bprint_buf_field; |
3405 | ip_field = pevent->bprint_ip_field; | 3529 | ip_field = pevent->bprint_ip_field; |
@@ -3448,6 +3572,8 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc | |||
3448 | goto process_again; | 3572 | goto process_again; |
3449 | case '0' ... '9': | 3573 | case '0' ... '9': |
3450 | goto process_again; | 3574 | goto process_again; |
3575 | case '.': | ||
3576 | goto process_again; | ||
3451 | case 'p': | 3577 | case 'p': |
3452 | ls = 1; | 3578 | ls = 1; |
3453 | /* fall through */ | 3579 | /* fall through */ |
@@ -3455,23 +3581,30 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc | |||
3455 | case 'u': | 3581 | case 'u': |
3456 | case 'x': | 3582 | case 'x': |
3457 | case 'i': | 3583 | case 'i': |
3458 | /* the pointers are always 4 bytes aligned */ | ||
3459 | bptr = (void *)(((unsigned long)bptr + 3) & | ||
3460 | ~3); | ||
3461 | switch (ls) { | 3584 | switch (ls) { |
3462 | case 0: | 3585 | case 0: |
3463 | ls = 4; | 3586 | vsize = 4; |
3464 | break; | 3587 | break; |
3465 | case 1: | 3588 | case 1: |
3466 | ls = pevent->long_size; | 3589 | vsize = pevent->long_size; |
3467 | break; | 3590 | break; |
3468 | case 2: | 3591 | case 2: |
3469 | ls = 8; | 3592 | vsize = 8; |
3593 | break; | ||
3470 | default: | 3594 | default: |
3595 | vsize = ls; /* ? */ | ||
3471 | break; | 3596 | break; |
3472 | } | 3597 | } |
3473 | val = pevent_read_number(pevent, bptr, ls); | 3598 | /* fall through */ |
3474 | bptr += ls; | 3599 | case '*': |
3600 | if (*ptr == '*') | ||
3601 | vsize = 4; | ||
3602 | |||
3603 | /* the pointers are always 4 bytes aligned */ | ||
3604 | bptr = (void *)(((unsigned long)bptr + 3) & | ||
3605 | ~3); | ||
3606 | val = pevent_read_number(pevent, bptr, vsize); | ||
3607 | bptr += vsize; | ||
3475 | arg = alloc_arg(); | 3608 | arg = alloc_arg(); |
3476 | arg->next = NULL; | 3609 | arg->next = NULL; |
3477 | arg->type = PRINT_ATOM; | 3610 | arg->type = PRINT_ATOM; |
@@ -3479,12 +3612,21 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc | |||
3479 | sprintf(arg->atom.atom, "%lld", val); | 3612 | sprintf(arg->atom.atom, "%lld", val); |
3480 | *next = arg; | 3613 | *next = arg; |
3481 | next = &arg->next; | 3614 | next = &arg->next; |
3615 | /* | ||
3616 | * The '*' case means that an arg is used as the length. | ||
3617 | * We need to continue to figure out for what. | ||
3618 | */ | ||
3619 | if (*ptr == '*') | ||
3620 | goto process_again; | ||
3621 | |||
3482 | break; | 3622 | break; |
3483 | case 's': | 3623 | case 's': |
3484 | arg = alloc_arg(); | 3624 | arg = alloc_arg(); |
3485 | arg->next = NULL; | 3625 | arg->next = NULL; |
3486 | arg->type = PRINT_BSTRING; | 3626 | arg->type = PRINT_BSTRING; |
3487 | arg->string.string = strdup(bptr); | 3627 | arg->string.string = strdup(bptr); |
3628 | if (!arg->string.string) | ||
3629 | break; | ||
3488 | bptr += strlen(bptr) + 1; | 3630 | bptr += strlen(bptr) + 1; |
3489 | *next = arg; | 3631 | *next = arg; |
3490 | next = &arg->next; | 3632 | next = &arg->next; |
@@ -3589,6 +3731,16 @@ static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size, | |||
3589 | trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); | 3731 | trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); |
3590 | } | 3732 | } |
3591 | 3733 | ||
3734 | static int is_printable_array(char *p, unsigned int len) | ||
3735 | { | ||
3736 | unsigned int i; | ||
3737 | |||
3738 | for (i = 0; i < len && p[i]; i++) | ||
3739 | if (!isprint(p[i])) | ||
3740 | return 0; | ||
3741 | return 1; | ||
3742 | } | ||
3743 | |||
3592 | static void print_event_fields(struct trace_seq *s, void *data, int size, | 3744 | static void print_event_fields(struct trace_seq *s, void *data, int size, |
3593 | struct event_format *event) | 3745 | struct event_format *event) |
3594 | { | 3746 | { |
@@ -3608,7 +3760,8 @@ static void print_event_fields(struct trace_seq *s, void *data, int size, | |||
3608 | len = offset >> 16; | 3760 | len = offset >> 16; |
3609 | offset &= 0xffff; | 3761 | offset &= 0xffff; |
3610 | } | 3762 | } |
3611 | if (field->flags & FIELD_IS_STRING) { | 3763 | if (field->flags & FIELD_IS_STRING && |
3764 | is_printable_array(data + offset, len)) { | ||
3612 | trace_seq_printf(s, "%s", (char *)data + offset); | 3765 | trace_seq_printf(s, "%s", (char *)data + offset); |
3613 | } else { | 3766 | } else { |
3614 | trace_seq_puts(s, "ARRAY["); | 3767 | trace_seq_puts(s, "ARRAY["); |
@@ -3619,6 +3772,7 @@ static void print_event_fields(struct trace_seq *s, void *data, int size, | |||
3619 | *((unsigned char *)data + offset + i)); | 3772 | *((unsigned char *)data + offset + i)); |
3620 | } | 3773 | } |
3621 | trace_seq_putc(s, ']'); | 3774 | trace_seq_putc(s, ']'); |
3775 | field->flags &= ~FIELD_IS_STRING; | ||
3622 | } | 3776 | } |
3623 | } else { | 3777 | } else { |
3624 | val = pevent_read_number(event->pevent, data + field->offset, | 3778 | val = pevent_read_number(event->pevent, data + field->offset, |
@@ -3758,6 +3912,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event | |||
3758 | } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') { | 3912 | } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') { |
3759 | print_mac_arg(s, *(ptr+1), data, size, event, arg); | 3913 | print_mac_arg(s, *(ptr+1), data, size, event, arg); |
3760 | ptr++; | 3914 | ptr++; |
3915 | arg = arg->next; | ||
3761 | break; | 3916 | break; |
3762 | } | 3917 | } |
3763 | 3918 | ||
@@ -3794,14 +3949,15 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event | |||
3794 | break; | 3949 | break; |
3795 | } | 3950 | } |
3796 | } | 3951 | } |
3797 | if (pevent->long_size == 8 && ls) { | 3952 | if (pevent->long_size == 8 && ls && |
3953 | sizeof(long) != 8) { | ||
3798 | char *p; | 3954 | char *p; |
3799 | 3955 | ||
3800 | ls = 2; | 3956 | ls = 2; |
3801 | /* make %l into %ll */ | 3957 | /* make %l into %ll */ |
3802 | p = strchr(format, 'l'); | 3958 | p = strchr(format, 'l'); |
3803 | if (p) | 3959 | if (p) |
3804 | memmove(p, p+1, strlen(p)+1); | 3960 | memmove(p+1, p, strlen(p)+1); |
3805 | else if (strcmp(format, "%p") == 0) | 3961 | else if (strcmp(format, "%p") == 0) |
3806 | strcpy(format, "0x%llx"); | 3962 | strcpy(format, "0x%llx"); |
3807 | } | 3963 | } |
@@ -3878,8 +4034,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event | |||
3878 | * pevent_data_lat_fmt - parse the data for the latency format | 4034 | * pevent_data_lat_fmt - parse the data for the latency format |
3879 | * @pevent: a handle to the pevent | 4035 | * @pevent: a handle to the pevent |
3880 | * @s: the trace_seq to write to | 4036 | * @s: the trace_seq to write to |
3881 | * @data: the raw data to read from | 4037 | * @record: the record to read from |
3882 | * @size: currently unused. | ||
3883 | * | 4038 | * |
3884 | * This parses out the Latency format (interrupts disabled, | 4039 | * This parses out the Latency format (interrupts disabled, |
3885 | * need rescheduling, in hard/soft interrupt, preempt count | 4040 | * need rescheduling, in hard/soft interrupt, preempt count |
@@ -3889,10 +4044,13 @@ void pevent_data_lat_fmt(struct pevent *pevent, | |||
3889 | struct trace_seq *s, struct pevent_record *record) | 4044 | struct trace_seq *s, struct pevent_record *record) |
3890 | { | 4045 | { |
3891 | static int check_lock_depth = 1; | 4046 | static int check_lock_depth = 1; |
4047 | static int check_migrate_disable = 1; | ||
3892 | static int lock_depth_exists; | 4048 | static int lock_depth_exists; |
4049 | static int migrate_disable_exists; | ||
3893 | unsigned int lat_flags; | 4050 | unsigned int lat_flags; |
3894 | unsigned int pc; | 4051 | unsigned int pc; |
3895 | int lock_depth; | 4052 | int lock_depth; |
4053 | int migrate_disable; | ||
3896 | int hardirq; | 4054 | int hardirq; |
3897 | int softirq; | 4055 | int softirq; |
3898 | void *data = record->data; | 4056 | void *data = record->data; |
@@ -3900,18 +4058,26 @@ void pevent_data_lat_fmt(struct pevent *pevent, | |||
3900 | lat_flags = parse_common_flags(pevent, data); | 4058 | lat_flags = parse_common_flags(pevent, data); |
3901 | pc = parse_common_pc(pevent, data); | 4059 | pc = parse_common_pc(pevent, data); |
3902 | /* lock_depth may not always exist */ | 4060 | /* lock_depth may not always exist */ |
3903 | if (check_lock_depth) { | ||
3904 | struct format_field *field; | ||
3905 | struct event_format *event; | ||
3906 | |||
3907 | check_lock_depth = 0; | ||
3908 | event = pevent->events[0]; | ||
3909 | field = pevent_find_common_field(event, "common_lock_depth"); | ||
3910 | if (field) | ||
3911 | lock_depth_exists = 1; | ||
3912 | } | ||
3913 | if (lock_depth_exists) | 4061 | if (lock_depth_exists) |
3914 | lock_depth = parse_common_lock_depth(pevent, data); | 4062 | lock_depth = parse_common_lock_depth(pevent, data); |
4063 | else if (check_lock_depth) { | ||
4064 | lock_depth = parse_common_lock_depth(pevent, data); | ||
4065 | if (lock_depth < 0) | ||
4066 | check_lock_depth = 0; | ||
4067 | else | ||
4068 | lock_depth_exists = 1; | ||
4069 | } | ||
4070 | |||
4071 | /* migrate_disable may not always exist */ | ||
4072 | if (migrate_disable_exists) | ||
4073 | migrate_disable = parse_common_migrate_disable(pevent, data); | ||
4074 | else if (check_migrate_disable) { | ||
4075 | migrate_disable = parse_common_migrate_disable(pevent, data); | ||
4076 | if (migrate_disable < 0) | ||
4077 | check_migrate_disable = 0; | ||
4078 | else | ||
4079 | migrate_disable_exists = 1; | ||
4080 | } | ||
3915 | 4081 | ||
3916 | hardirq = lat_flags & TRACE_FLAG_HARDIRQ; | 4082 | hardirq = lat_flags & TRACE_FLAG_HARDIRQ; |
3917 | softirq = lat_flags & TRACE_FLAG_SOFTIRQ; | 4083 | softirq = lat_flags & TRACE_FLAG_SOFTIRQ; |
@@ -3930,6 +4096,13 @@ void pevent_data_lat_fmt(struct pevent *pevent, | |||
3930 | else | 4096 | else |
3931 | trace_seq_putc(s, '.'); | 4097 | trace_seq_putc(s, '.'); |
3932 | 4098 | ||
4099 | if (migrate_disable_exists) { | ||
4100 | if (migrate_disable < 0) | ||
4101 | trace_seq_putc(s, '.'); | ||
4102 | else | ||
4103 | trace_seq_printf(s, "%d", migrate_disable); | ||
4104 | } | ||
4105 | |||
3933 | if (lock_depth_exists) { | 4106 | if (lock_depth_exists) { |
3934 | if (lock_depth < 0) | 4107 | if (lock_depth < 0) |
3935 | trace_seq_putc(s, '.'); | 4108 | trace_seq_putc(s, '.'); |
@@ -3996,10 +4169,7 @@ const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid) | |||
3996 | * pevent_data_comm_from_pid - parse the data into the print format | 4169 | * pevent_data_comm_from_pid - parse the data into the print format |
3997 | * @s: the trace_seq to write to | 4170 | * @s: the trace_seq to write to |
3998 | * @event: the handle to the event | 4171 | * @event: the handle to the event |
3999 | * @cpu: the cpu the event was recorded on | 4172 | * @record: the record to read from |
4000 | * @data: the raw data | ||
4001 | * @size: the size of the raw data | ||
4002 | * @nsecs: the timestamp of the event | ||
4003 | * | 4173 | * |
4004 | * This parses the raw @data using the given @event information and | 4174 | * This parses the raw @data using the given @event information and |
4005 | * writes the print format into the trace_seq. | 4175 | * writes the print format into the trace_seq. |
@@ -4279,6 +4449,13 @@ static void print_args(struct print_arg *args) | |||
4279 | trace_seq_destroy(&s); | 4449 | trace_seq_destroy(&s); |
4280 | printf(")"); | 4450 | printf(")"); |
4281 | break; | 4451 | break; |
4452 | case PRINT_HEX: | ||
4453 | printf("__print_hex("); | ||
4454 | print_args(args->hex.field); | ||
4455 | printf(", "); | ||
4456 | print_args(args->hex.size); | ||
4457 | printf(")"); | ||
4458 | break; | ||
4282 | case PRINT_STRING: | 4459 | case PRINT_STRING: |
4283 | case PRINT_BSTRING: | 4460 | case PRINT_BSTRING: |
4284 | printf("__get_str(%s)", args->string.string); | 4461 | printf("__get_str(%s)", args->string.string); |
@@ -4541,6 +4718,8 @@ int pevent_parse_event(struct pevent *pevent, | |||
4541 | die("failed to read event id"); | 4718 | die("failed to read event id"); |
4542 | 4719 | ||
4543 | event->system = strdup(sys); | 4720 | event->system = strdup(sys); |
4721 | if (!event->system) | ||
4722 | die("failed to allocate system"); | ||
4544 | 4723 | ||
4545 | /* Add pevent to event so that it can be referenced */ | 4724 | /* Add pevent to event so that it can be referenced */ |
4546 | event->pevent = pevent; | 4725 | event->pevent = pevent; |
@@ -4582,6 +4761,11 @@ int pevent_parse_event(struct pevent *pevent, | |||
4582 | list = &arg->next; | 4761 | list = &arg->next; |
4583 | arg->type = PRINT_FIELD; | 4762 | arg->type = PRINT_FIELD; |
4584 | arg->field.name = strdup(field->name); | 4763 | arg->field.name = strdup(field->name); |
4764 | if (!arg->field.name) { | ||
4765 | do_warning("failed to allocate field name"); | ||
4766 | event->flags |= EVENT_FL_FAILED; | ||
4767 | return -1; | ||
4768 | } | ||
4585 | arg->field.field = field; | 4769 | arg->field.field = field; |
4586 | } | 4770 | } |
4587 | return 0; | 4771 | return 0; |
@@ -4753,7 +4937,7 @@ int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event, | |||
4753 | * @record: The record with the field name. | 4937 | * @record: The record with the field name. |
4754 | * @err: print default error if failed. | 4938 | * @err: print default error if failed. |
4755 | * | 4939 | * |
4756 | * Returns: 0 on success, -1 field not fould, or 1 if buffer is full. | 4940 | * Returns: 0 on success, -1 field not found, or 1 if buffer is full. |
4757 | */ | 4941 | */ |
4758 | int pevent_print_num_field(struct trace_seq *s, const char *fmt, | 4942 | int pevent_print_num_field(struct trace_seq *s, const char *fmt, |
4759 | struct event_format *event, const char *name, | 4943 | struct event_format *event, const char *name, |
@@ -4795,11 +4979,12 @@ static void free_func_handle(struct pevent_function_handler *func) | |||
4795 | * pevent_register_print_function - register a helper function | 4979 | * pevent_register_print_function - register a helper function |
4796 | * @pevent: the handle to the pevent | 4980 | * @pevent: the handle to the pevent |
4797 | * @func: the function to process the helper function | 4981 | * @func: the function to process the helper function |
4982 | * @ret_type: the return type of the helper function | ||
4798 | * @name: the name of the helper function | 4983 | * @name: the name of the helper function |
4799 | * @parameters: A list of enum pevent_func_arg_type | 4984 | * @parameters: A list of enum pevent_func_arg_type |
4800 | * | 4985 | * |
4801 | * Some events may have helper functions in the print format arguments. | 4986 | * Some events may have helper functions in the print format arguments. |
4802 | * This allows a plugin to dynmically create a way to process one | 4987 | * This allows a plugin to dynamically create a way to process one |
4803 | * of these functions. | 4988 | * of these functions. |
4804 | * | 4989 | * |
4805 | * The @parameters is a variable list of pevent_func_arg_type enums that | 4990 | * The @parameters is a variable list of pevent_func_arg_type enums that |
@@ -4870,12 +5055,13 @@ int pevent_register_print_function(struct pevent *pevent, | |||
4870 | } | 5055 | } |
4871 | 5056 | ||
4872 | /** | 5057 | /** |
4873 | * pevent_register_event_handle - register a way to parse an event | 5058 | * pevent_register_event_handler - register a way to parse an event |
4874 | * @pevent: the handle to the pevent | 5059 | * @pevent: the handle to the pevent |
4875 | * @id: the id of the event to register | 5060 | * @id: the id of the event to register |
4876 | * @sys_name: the system name the event belongs to | 5061 | * @sys_name: the system name the event belongs to |
4877 | * @event_name: the name of the event | 5062 | * @event_name: the name of the event |
4878 | * @func: the function to call to parse the event information | 5063 | * @func: the function to call to parse the event information |
5064 | * @context: the data to be passed to @func | ||
4879 | * | 5065 | * |
4880 | * This function allows a developer to override the parsing of | 5066 | * This function allows a developer to override the parsing of |
4881 | * a given event. If for some reason the default print format | 5067 | * a given event. If for some reason the default print format |
@@ -4925,6 +5111,11 @@ int pevent_register_event_handler(struct pevent *pevent, | |||
4925 | if (sys_name) | 5111 | if (sys_name) |
4926 | handle->sys_name = strdup(sys_name); | 5112 | handle->sys_name = strdup(sys_name); |
4927 | 5113 | ||
5114 | if ((event_name && !handle->event_name) || | ||
5115 | (sys_name && !handle->sys_name)) { | ||
5116 | die("Failed to allocate event/sys name"); | ||
5117 | } | ||
5118 | |||
4928 | handle->func = func; | 5119 | handle->func = func; |
4929 | handle->next = pevent->handlers; | 5120 | handle->next = pevent->handlers; |
4930 | pevent->handlers = handle; | 5121 | pevent->handlers = handle; |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index ac997bc7b592..5772ad8cb386 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
@@ -226,6 +226,11 @@ struct print_arg_symbol { | |||
226 | struct print_flag_sym *symbols; | 226 | struct print_flag_sym *symbols; |
227 | }; | 227 | }; |
228 | 228 | ||
229 | struct print_arg_hex { | ||
230 | struct print_arg *field; | ||
231 | struct print_arg *size; | ||
232 | }; | ||
233 | |||
229 | struct print_arg_dynarray { | 234 | struct print_arg_dynarray { |
230 | struct format_field *field; | 235 | struct format_field *field; |
231 | struct print_arg *index; | 236 | struct print_arg *index; |
@@ -253,6 +258,7 @@ enum print_arg_type { | |||
253 | PRINT_FIELD, | 258 | PRINT_FIELD, |
254 | PRINT_FLAGS, | 259 | PRINT_FLAGS, |
255 | PRINT_SYMBOL, | 260 | PRINT_SYMBOL, |
261 | PRINT_HEX, | ||
256 | PRINT_TYPE, | 262 | PRINT_TYPE, |
257 | PRINT_STRING, | 263 | PRINT_STRING, |
258 | PRINT_BSTRING, | 264 | PRINT_BSTRING, |
@@ -270,6 +276,7 @@ struct print_arg { | |||
270 | struct print_arg_typecast typecast; | 276 | struct print_arg_typecast typecast; |
271 | struct print_arg_flags flags; | 277 | struct print_arg_flags flags; |
272 | struct print_arg_symbol symbol; | 278 | struct print_arg_symbol symbol; |
279 | struct print_arg_hex hex; | ||
273 | struct print_arg_func func; | 280 | struct print_arg_func func; |
274 | struct print_arg_string string; | 281 | struct print_arg_string string; |
275 | struct print_arg_op op; | 282 | struct print_arg_op op; |
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index dfcfe2c131de..ad17855528f9 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c | |||
@@ -96,7 +96,7 @@ static enum event_type read_token(char **tok) | |||
96 | (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && | 96 | (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && |
97 | pevent_peek_char() == '~') { | 97 | pevent_peek_char() == '~') { |
98 | /* append it */ | 98 | /* append it */ |
99 | *tok = malloc(3); | 99 | *tok = malloc_or_die(3); |
100 | sprintf(*tok, "%c%c", *token, '~'); | 100 | sprintf(*tok, "%c%c", *token, '~'); |
101 | free_token(token); | 101 | free_token(token); |
102 | /* Now remove the '~' from the buffer */ | 102 | /* Now remove the '~' from the buffer */ |
@@ -148,17 +148,11 @@ add_filter_type(struct event_filter *filter, int id) | |||
148 | if (filter_type) | 148 | if (filter_type) |
149 | return filter_type; | 149 | return filter_type; |
150 | 150 | ||
151 | if (!filter->filters) | 151 | filter->event_filters = realloc(filter->event_filters, |
152 | filter->event_filters = | 152 | sizeof(*filter->event_filters) * |
153 | malloc_or_die(sizeof(*filter->event_filters)); | 153 | (filter->filters + 1)); |
154 | else { | 154 | if (!filter->event_filters) |
155 | filter->event_filters = | 155 | die("Could not allocate filter"); |
156 | realloc(filter->event_filters, | ||
157 | sizeof(*filter->event_filters) * | ||
158 | (filter->filters + 1)); | ||
159 | if (!filter->event_filters) | ||
160 | die("Could not allocate filter"); | ||
161 | } | ||
162 | 156 | ||
163 | for (i = 0; i < filter->filters; i++) { | 157 | for (i = 0; i < filter->filters; i++) { |
164 | if (filter->event_filters[i].event_id > id) | 158 | if (filter->event_filters[i].event_id > id) |
@@ -1480,7 +1474,7 @@ void pevent_filter_clear_trivial(struct event_filter *filter, | |||
1480 | { | 1474 | { |
1481 | struct filter_type *filter_type; | 1475 | struct filter_type *filter_type; |
1482 | int count = 0; | 1476 | int count = 0; |
1483 | int *ids; | 1477 | int *ids = NULL; |
1484 | int i; | 1478 | int i; |
1485 | 1479 | ||
1486 | if (!filter->filters) | 1480 | if (!filter->filters) |
@@ -1504,10 +1498,8 @@ void pevent_filter_clear_trivial(struct event_filter *filter, | |||
1504 | default: | 1498 | default: |
1505 | break; | 1499 | break; |
1506 | } | 1500 | } |
1507 | if (count) | 1501 | |
1508 | ids = realloc(ids, sizeof(*ids) * (count + 1)); | 1502 | ids = realloc(ids, sizeof(*ids) * (count + 1)); |
1509 | else | ||
1510 | ids = malloc(sizeof(*ids)); | ||
1511 | if (!ids) | 1503 | if (!ids) |
1512 | die("Can't allocate ids"); | 1504 | die("Can't allocate ids"); |
1513 | ids[count++] = filter_type->event_id; | 1505 | ids[count++] = filter_type->event_id; |
@@ -1710,18 +1702,43 @@ static int test_num(struct event_format *event, | |||
1710 | 1702 | ||
1711 | static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record) | 1703 | static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record) |
1712 | { | 1704 | { |
1713 | const char *val = record->data + arg->str.field->offset; | 1705 | struct event_format *event; |
1706 | struct pevent *pevent; | ||
1707 | unsigned long long addr; | ||
1708 | const char *val = NULL; | ||
1709 | char hex[64]; | ||
1714 | 1710 | ||
1715 | /* | 1711 | /* If the field is not a string convert it */ |
1716 | * We need to copy the data since we can't be sure the field | 1712 | if (arg->str.field->flags & FIELD_IS_STRING) { |
1717 | * is null terminated. | 1713 | val = record->data + arg->str.field->offset; |
1718 | */ | 1714 | |
1719 | if (*(val + arg->str.field->size - 1)) { | 1715 | /* |
1720 | /* copy it */ | 1716 | * We need to copy the data since we can't be sure the field |
1721 | memcpy(arg->str.buffer, val, arg->str.field->size); | 1717 | * is null terminated. |
1722 | /* the buffer is already NULL terminated */ | 1718 | */ |
1723 | val = arg->str.buffer; | 1719 | if (*(val + arg->str.field->size - 1)) { |
1720 | /* copy it */ | ||
1721 | memcpy(arg->str.buffer, val, arg->str.field->size); | ||
1722 | /* the buffer is already NULL terminated */ | ||
1723 | val = arg->str.buffer; | ||
1724 | } | ||
1725 | |||
1726 | } else { | ||
1727 | event = arg->str.field->event; | ||
1728 | pevent = event->pevent; | ||
1729 | addr = get_value(event, arg->str.field, record); | ||
1730 | |||
1731 | if (arg->str.field->flags & (FIELD_IS_POINTER | FIELD_IS_LONG)) | ||
1732 | /* convert to a kernel symbol */ | ||
1733 | val = pevent_find_function(pevent, addr); | ||
1734 | |||
1735 | if (val == NULL) { | ||
1736 | /* just use the hex of the string name */ | ||
1737 | snprintf(hex, 64, "0x%llx", addr); | ||
1738 | val = hex; | ||
1739 | } | ||
1724 | } | 1740 | } |
1741 | |||
1725 | return val; | 1742 | return val; |
1726 | } | 1743 | } |
1727 | 1744 | ||
@@ -2001,11 +2018,13 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2001 | char *lstr; | 2018 | char *lstr; |
2002 | char *rstr; | 2019 | char *rstr; |
2003 | char *op; | 2020 | char *op; |
2004 | char *str; | 2021 | char *str = NULL; |
2005 | int len; | 2022 | int len; |
2006 | 2023 | ||
2007 | lstr = arg_to_str(filter, arg->exp.left); | 2024 | lstr = arg_to_str(filter, arg->exp.left); |
2008 | rstr = arg_to_str(filter, arg->exp.right); | 2025 | rstr = arg_to_str(filter, arg->exp.right); |
2026 | if (!lstr || !rstr) | ||
2027 | goto out; | ||
2009 | 2028 | ||
2010 | switch (arg->exp.type) { | 2029 | switch (arg->exp.type) { |
2011 | case FILTER_EXP_ADD: | 2030 | case FILTER_EXP_ADD: |
@@ -2045,6 +2064,7 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2045 | len = strlen(op) + strlen(lstr) + strlen(rstr) + 4; | 2064 | len = strlen(op) + strlen(lstr) + strlen(rstr) + 4; |
2046 | str = malloc_or_die(len); | 2065 | str = malloc_or_die(len); |
2047 | snprintf(str, len, "%s %s %s", lstr, op, rstr); | 2066 | snprintf(str, len, "%s %s %s", lstr, op, rstr); |
2067 | out: | ||
2048 | free(lstr); | 2068 | free(lstr); |
2049 | free(rstr); | 2069 | free(rstr); |
2050 | 2070 | ||
@@ -2061,6 +2081,8 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2061 | 2081 | ||
2062 | lstr = arg_to_str(filter, arg->num.left); | 2082 | lstr = arg_to_str(filter, arg->num.left); |
2063 | rstr = arg_to_str(filter, arg->num.right); | 2083 | rstr = arg_to_str(filter, arg->num.right); |
2084 | if (!lstr || !rstr) | ||
2085 | goto out; | ||
2064 | 2086 | ||
2065 | switch (arg->num.type) { | 2087 | switch (arg->num.type) { |
2066 | case FILTER_CMP_EQ: | 2088 | case FILTER_CMP_EQ: |
@@ -2097,6 +2119,7 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2097 | break; | 2119 | break; |
2098 | } | 2120 | } |
2099 | 2121 | ||
2122 | out: | ||
2100 | free(lstr); | 2123 | free(lstr); |
2101 | free(rstr); | 2124 | free(rstr); |
2102 | return str; | 2125 | return str; |
@@ -2247,7 +2270,12 @@ int pevent_filter_compare(struct event_filter *filter1, struct event_filter *fil | |||
2247 | /* The best way to compare complex filters is with strings */ | 2270 | /* The best way to compare complex filters is with strings */ |
2248 | str1 = arg_to_str(filter1, filter_type1->filter); | 2271 | str1 = arg_to_str(filter1, filter_type1->filter); |
2249 | str2 = arg_to_str(filter2, filter_type2->filter); | 2272 | str2 = arg_to_str(filter2, filter_type2->filter); |
2250 | result = strcmp(str1, str2) != 0; | 2273 | if (str1 && str2) |
2274 | result = strcmp(str1, str2) != 0; | ||
2275 | else | ||
2276 | /* bail out if allocation fails */ | ||
2277 | result = 1; | ||
2278 | |||
2251 | free(str1); | 2279 | free(str1); |
2252 | free(str2); | 2280 | free(str2); |
2253 | if (result) | 2281 | if (result) |
diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt index a3dbadb26ef5..7065cd6fbdfc 100644 --- a/tools/perf/Documentation/perf-bench.txt +++ b/tools/perf/Documentation/perf-bench.txt | |||
@@ -12,7 +12,7 @@ SYNOPSIS | |||
12 | 12 | ||
13 | DESCRIPTION | 13 | DESCRIPTION |
14 | ----------- | 14 | ----------- |
15 | This 'perf bench' command is general framework for benchmark suites. | 15 | This 'perf bench' command is a general framework for benchmark suites. |
16 | 16 | ||
17 | COMMON OPTIONS | 17 | COMMON OPTIONS |
18 | -------------- | 18 | -------------- |
@@ -45,14 +45,20 @@ SUBSYSTEM | |||
45 | 'sched':: | 45 | 'sched':: |
46 | Scheduler and IPC mechanisms. | 46 | Scheduler and IPC mechanisms. |
47 | 47 | ||
48 | 'mem':: | ||
49 | Memory access performance. | ||
50 | |||
51 | 'all':: | ||
52 | All benchmark subsystems. | ||
53 | |||
48 | SUITES FOR 'sched' | 54 | SUITES FOR 'sched' |
49 | ~~~~~~~~~~~~~~~~~~ | 55 | ~~~~~~~~~~~~~~~~~~ |
50 | *messaging*:: | 56 | *messaging*:: |
51 | Suite for evaluating performance of scheduler and IPC mechanisms. | 57 | Suite for evaluating performance of scheduler and IPC mechanisms. |
52 | Based on hackbench by Rusty Russell. | 58 | Based on hackbench by Rusty Russell. |
53 | 59 | ||
54 | Options of *pipe* | 60 | Options of *messaging* |
55 | ^^^^^^^^^^^^^^^^^ | 61 | ^^^^^^^^^^^^^^^^^^^^^^ |
56 | -p:: | 62 | -p:: |
57 | --pipe:: | 63 | --pipe:: |
58 | Use pipe() instead of socketpair() | 64 | Use pipe() instead of socketpair() |
@@ -115,6 +121,72 @@ Example of *pipe* | |||
115 | 59004 ops/sec | 121 | 59004 ops/sec |
116 | --------------------- | 122 | --------------------- |
117 | 123 | ||
124 | SUITES FOR 'mem' | ||
125 | ~~~~~~~~~~~~~~~~ | ||
126 | *memcpy*:: | ||
127 | Suite for evaluating performance of simple memory copy in various ways. | ||
128 | |||
129 | Options of *memcpy* | ||
130 | ^^^^^^^^^^^^^^^^^^^ | ||
131 | -l:: | ||
132 | --length:: | ||
133 | Specify length of memory to copy (default: 1MB). | ||
134 | Available units are B, KB, MB, GB and TB (case insensitive). | ||
135 | |||
136 | -r:: | ||
137 | --routine:: | ||
138 | Specify routine to copy (default: default). | ||
139 | Available routines are depend on the architecture. | ||
140 | On x86-64, x86-64-unrolled, x86-64-movsq and x86-64-movsb are supported. | ||
141 | |||
142 | -i:: | ||
143 | --iterations:: | ||
144 | Repeat memcpy invocation this number of times. | ||
145 | |||
146 | -c:: | ||
147 | --cycle:: | ||
148 | Use perf's cpu-cycles event instead of gettimeofday syscall. | ||
149 | |||
150 | -o:: | ||
151 | --only-prefault:: | ||
152 | Show only the result with page faults before memcpy. | ||
153 | |||
154 | -n:: | ||
155 | --no-prefault:: | ||
156 | Show only the result without page faults before memcpy. | ||
157 | |||
158 | *memset*:: | ||
159 | Suite for evaluating performance of simple memory set in various ways. | ||
160 | |||
161 | Options of *memset* | ||
162 | ^^^^^^^^^^^^^^^^^^^ | ||
163 | -l:: | ||
164 | --length:: | ||
165 | Specify length of memory to set (default: 1MB). | ||
166 | Available units are B, KB, MB, GB and TB (case insensitive). | ||
167 | |||
168 | -r:: | ||
169 | --routine:: | ||
170 | Specify routine to set (default: default). | ||
171 | Available routines are depend on the architecture. | ||
172 | On x86-64, x86-64-unrolled, x86-64-stosq and x86-64-stosb are supported. | ||
173 | |||
174 | -i:: | ||
175 | --iterations:: | ||
176 | Repeat memset invocation this number of times. | ||
177 | |||
178 | -c:: | ||
179 | --cycle:: | ||
180 | Use perf's cpu-cycles event instead of gettimeofday syscall. | ||
181 | |||
182 | -o:: | ||
183 | --only-prefault:: | ||
184 | Show only the result with page faults before memset. | ||
185 | |||
186 | -n:: | ||
187 | --no-prefault:: | ||
188 | Show only the result without page faults before memset. | ||
189 | |||
118 | SEE ALSO | 190 | SEE ALSO |
119 | -------- | 191 | -------- |
120 | linkperf:perf[1] | 192 | linkperf:perf[1] |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 2d89f02719b5..495210a612c4 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -57,7 +57,7 @@ OPTIONS | |||
57 | 57 | ||
58 | -s:: | 58 | -s:: |
59 | --sort=:: | 59 | --sort=:: |
60 | Sort by key(s): pid, comm, dso, symbol, parent. | 60 | Sort by key(s): pid, comm, dso, symbol, parent, srcline. |
61 | 61 | ||
62 | -p:: | 62 | -p:: |
63 | --parent=<regex>:: | 63 | --parent=<regex>:: |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 4a5680cb242e..5b80d84d6b4a 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -112,7 +112,7 @@ Default is to monitor all CPUS. | |||
112 | 112 | ||
113 | -s:: | 113 | -s:: |
114 | --sort:: | 114 | --sort:: |
115 | Sort by key(s): pid, comm, dso, symbol, parent | 115 | Sort by key(s): pid, comm, dso, symbol, parent, srcline. |
116 | 116 | ||
117 | -n:: | 117 | -n:: |
118 | --show-nr-samples:: | 118 | --show-nr-samples:: |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 0eee64cfe9a0..75d74e5db8d5 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -155,7 +155,7 @@ endif | |||
155 | 155 | ||
156 | ### --- END CONFIGURATION SECTION --- | 156 | ### --- END CONFIGURATION SECTION --- |
157 | 157 | ||
158 | BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE | 158 | BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE |
159 | BASIC_LDFLAGS = | 159 | BASIC_LDFLAGS = |
160 | 160 | ||
161 | # Guard against environment variables | 161 | # Guard against environment variables |
@@ -503,6 +503,7 @@ else | |||
503 | LIB_OBJS += $(OUTPUT)ui/progress.o | 503 | LIB_OBJS += $(OUTPUT)ui/progress.o |
504 | LIB_OBJS += $(OUTPUT)ui/util.o | 504 | LIB_OBJS += $(OUTPUT)ui/util.o |
505 | LIB_OBJS += $(OUTPUT)ui/tui/setup.o | 505 | LIB_OBJS += $(OUTPUT)ui/tui/setup.o |
506 | LIB_OBJS += $(OUTPUT)ui/tui/util.o | ||
506 | LIB_H += ui/browser.h | 507 | LIB_H += ui/browser.h |
507 | LIB_H += ui/browsers/map.h | 508 | LIB_H += ui/browsers/map.h |
508 | LIB_H += ui/helpline.h | 509 | LIB_H += ui/helpline.h |
@@ -522,13 +523,18 @@ else | |||
522 | msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); | 523 | msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); |
523 | BASIC_CFLAGS += -DNO_GTK2_SUPPORT | 524 | BASIC_CFLAGS += -DNO_GTK2_SUPPORT |
524 | else | 525 | else |
526 | ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y) | ||
527 | BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR | ||
528 | endif | ||
525 | BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0) | 529 | BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0) |
526 | EXTLIBS += $(shell pkg-config --libs gtk+-2.0) | 530 | EXTLIBS += $(shell pkg-config --libs gtk+-2.0) |
527 | LIB_OBJS += $(OUTPUT)ui/gtk/browser.o | 531 | LIB_OBJS += $(OUTPUT)ui/gtk/browser.o |
528 | LIB_OBJS += $(OUTPUT)ui/gtk/setup.o | 532 | LIB_OBJS += $(OUTPUT)ui/gtk/setup.o |
533 | LIB_OBJS += $(OUTPUT)ui/gtk/util.o | ||
529 | # Make sure that it'd be included only once. | 534 | # Make sure that it'd be included only once. |
530 | ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),) | 535 | ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),) |
531 | LIB_OBJS += $(OUTPUT)ui/setup.o | 536 | LIB_OBJS += $(OUTPUT)ui/setup.o |
537 | LIB_OBJS += $(OUTPUT)ui/util.o | ||
532 | endif | 538 | endif |
533 | endif | 539 | endif |
534 | endif | 540 | endif |
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c index 71557225bf92..02dad5d3359b 100644 --- a/tools/perf/bench/mem-memcpy.c +++ b/tools/perf/bench/mem-memcpy.c | |||
@@ -24,21 +24,21 @@ | |||
24 | static const char *length_str = "1MB"; | 24 | static const char *length_str = "1MB"; |
25 | static const char *routine = "default"; | 25 | static const char *routine = "default"; |
26 | static int iterations = 1; | 26 | static int iterations = 1; |
27 | static bool use_clock; | 27 | static bool use_cycle; |
28 | static int clock_fd; | 28 | static int cycle_fd; |
29 | static bool only_prefault; | 29 | static bool only_prefault; |
30 | static bool no_prefault; | 30 | static bool no_prefault; |
31 | 31 | ||
32 | static const struct option options[] = { | 32 | static const struct option options[] = { |
33 | OPT_STRING('l', "length", &length_str, "1MB", | 33 | OPT_STRING('l', "length", &length_str, "1MB", |
34 | "Specify length of memory to copy. " | 34 | "Specify length of memory to copy. " |
35 | "available unit: B, MB, GB (upper and lower)"), | 35 | "Available units: B, KB, MB, GB and TB (upper and lower)"), |
36 | OPT_STRING('r', "routine", &routine, "default", | 36 | OPT_STRING('r', "routine", &routine, "default", |
37 | "Specify routine to copy"), | 37 | "Specify routine to copy"), |
38 | OPT_INTEGER('i', "iterations", &iterations, | 38 | OPT_INTEGER('i', "iterations", &iterations, |
39 | "repeat memcpy() invocation this number of times"), | 39 | "repeat memcpy() invocation this number of times"), |
40 | OPT_BOOLEAN('c', "clock", &use_clock, | 40 | OPT_BOOLEAN('c', "cycle", &use_cycle, |
41 | "Use CPU clock for measuring"), | 41 | "Use cycles event instead of gettimeofday() for measuring"), |
42 | OPT_BOOLEAN('o', "only-prefault", &only_prefault, | 42 | OPT_BOOLEAN('o', "only-prefault", &only_prefault, |
43 | "Show only the result with page faults before memcpy()"), | 43 | "Show only the result with page faults before memcpy()"), |
44 | OPT_BOOLEAN('n', "no-prefault", &no_prefault, | 44 | OPT_BOOLEAN('n', "no-prefault", &no_prefault, |
@@ -76,27 +76,27 @@ static const char * const bench_mem_memcpy_usage[] = { | |||
76 | NULL | 76 | NULL |
77 | }; | 77 | }; |
78 | 78 | ||
79 | static struct perf_event_attr clock_attr = { | 79 | static struct perf_event_attr cycle_attr = { |
80 | .type = PERF_TYPE_HARDWARE, | 80 | .type = PERF_TYPE_HARDWARE, |
81 | .config = PERF_COUNT_HW_CPU_CYCLES | 81 | .config = PERF_COUNT_HW_CPU_CYCLES |
82 | }; | 82 | }; |
83 | 83 | ||
84 | static void init_clock(void) | 84 | static void init_cycle(void) |
85 | { | 85 | { |
86 | clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0); | 86 | cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); |
87 | 87 | ||
88 | if (clock_fd < 0 && errno == ENOSYS) | 88 | if (cycle_fd < 0 && errno == ENOSYS) |
89 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 89 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
90 | else | 90 | else |
91 | BUG_ON(clock_fd < 0); | 91 | BUG_ON(cycle_fd < 0); |
92 | } | 92 | } |
93 | 93 | ||
94 | static u64 get_clock(void) | 94 | static u64 get_cycle(void) |
95 | { | 95 | { |
96 | int ret; | 96 | int ret; |
97 | u64 clk; | 97 | u64 clk; |
98 | 98 | ||
99 | ret = read(clock_fd, &clk, sizeof(u64)); | 99 | ret = read(cycle_fd, &clk, sizeof(u64)); |
100 | BUG_ON(ret != sizeof(u64)); | 100 | BUG_ON(ret != sizeof(u64)); |
101 | 101 | ||
102 | return clk; | 102 | return clk; |
@@ -119,9 +119,9 @@ static void alloc_mem(void **dst, void **src, size_t length) | |||
119 | die("memory allocation failed - maybe length is too large?\n"); | 119 | die("memory allocation failed - maybe length is too large?\n"); |
120 | } | 120 | } |
121 | 121 | ||
122 | static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault) | 122 | static u64 do_memcpy_cycle(memcpy_t fn, size_t len, bool prefault) |
123 | { | 123 | { |
124 | u64 clock_start = 0ULL, clock_end = 0ULL; | 124 | u64 cycle_start = 0ULL, cycle_end = 0ULL; |
125 | void *src = NULL, *dst = NULL; | 125 | void *src = NULL, *dst = NULL; |
126 | int i; | 126 | int i; |
127 | 127 | ||
@@ -130,14 +130,14 @@ static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault) | |||
130 | if (prefault) | 130 | if (prefault) |
131 | fn(dst, src, len); | 131 | fn(dst, src, len); |
132 | 132 | ||
133 | clock_start = get_clock(); | 133 | cycle_start = get_cycle(); |
134 | for (i = 0; i < iterations; ++i) | 134 | for (i = 0; i < iterations; ++i) |
135 | fn(dst, src, len); | 135 | fn(dst, src, len); |
136 | clock_end = get_clock(); | 136 | cycle_end = get_cycle(); |
137 | 137 | ||
138 | free(src); | 138 | free(src); |
139 | free(dst); | 139 | free(dst); |
140 | return clock_end - clock_start; | 140 | return cycle_end - cycle_start; |
141 | } | 141 | } |
142 | 142 | ||
143 | static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault) | 143 | static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault) |
@@ -182,17 +182,17 @@ int bench_mem_memcpy(int argc, const char **argv, | |||
182 | int i; | 182 | int i; |
183 | size_t len; | 183 | size_t len; |
184 | double result_bps[2]; | 184 | double result_bps[2]; |
185 | u64 result_clock[2]; | 185 | u64 result_cycle[2]; |
186 | 186 | ||
187 | argc = parse_options(argc, argv, options, | 187 | argc = parse_options(argc, argv, options, |
188 | bench_mem_memcpy_usage, 0); | 188 | bench_mem_memcpy_usage, 0); |
189 | 189 | ||
190 | if (use_clock) | 190 | if (use_cycle) |
191 | init_clock(); | 191 | init_cycle(); |
192 | 192 | ||
193 | len = (size_t)perf_atoll((char *)length_str); | 193 | len = (size_t)perf_atoll((char *)length_str); |
194 | 194 | ||
195 | result_clock[0] = result_clock[1] = 0ULL; | 195 | result_cycle[0] = result_cycle[1] = 0ULL; |
196 | result_bps[0] = result_bps[1] = 0.0; | 196 | result_bps[0] = result_bps[1] = 0.0; |
197 | 197 | ||
198 | if ((s64)len <= 0) { | 198 | if ((s64)len <= 0) { |
@@ -223,11 +223,11 @@ int bench_mem_memcpy(int argc, const char **argv, | |||
223 | 223 | ||
224 | if (!only_prefault && !no_prefault) { | 224 | if (!only_prefault && !no_prefault) { |
225 | /* show both of results */ | 225 | /* show both of results */ |
226 | if (use_clock) { | 226 | if (use_cycle) { |
227 | result_clock[0] = | 227 | result_cycle[0] = |
228 | do_memcpy_clock(routines[i].fn, len, false); | 228 | do_memcpy_cycle(routines[i].fn, len, false); |
229 | result_clock[1] = | 229 | result_cycle[1] = |
230 | do_memcpy_clock(routines[i].fn, len, true); | 230 | do_memcpy_cycle(routines[i].fn, len, true); |
231 | } else { | 231 | } else { |
232 | result_bps[0] = | 232 | result_bps[0] = |
233 | do_memcpy_gettimeofday(routines[i].fn, | 233 | do_memcpy_gettimeofday(routines[i].fn, |
@@ -237,9 +237,9 @@ int bench_mem_memcpy(int argc, const char **argv, | |||
237 | len, true); | 237 | len, true); |
238 | } | 238 | } |
239 | } else { | 239 | } else { |
240 | if (use_clock) { | 240 | if (use_cycle) { |
241 | result_clock[pf] = | 241 | result_cycle[pf] = |
242 | do_memcpy_clock(routines[i].fn, | 242 | do_memcpy_cycle(routines[i].fn, |
243 | len, only_prefault); | 243 | len, only_prefault); |
244 | } else { | 244 | } else { |
245 | result_bps[pf] = | 245 | result_bps[pf] = |
@@ -251,12 +251,12 @@ int bench_mem_memcpy(int argc, const char **argv, | |||
251 | switch (bench_format) { | 251 | switch (bench_format) { |
252 | case BENCH_FORMAT_DEFAULT: | 252 | case BENCH_FORMAT_DEFAULT: |
253 | if (!only_prefault && !no_prefault) { | 253 | if (!only_prefault && !no_prefault) { |
254 | if (use_clock) { | 254 | if (use_cycle) { |
255 | printf(" %14lf Clock/Byte\n", | 255 | printf(" %14lf Cycle/Byte\n", |
256 | (double)result_clock[0] | 256 | (double)result_cycle[0] |
257 | / (double)len); | 257 | / (double)len); |
258 | printf(" %14lf Clock/Byte (with prefault)\n", | 258 | printf(" %14lf Cycle/Byte (with prefault)\n", |
259 | (double)result_clock[1] | 259 | (double)result_cycle[1] |
260 | / (double)len); | 260 | / (double)len); |
261 | } else { | 261 | } else { |
262 | print_bps(result_bps[0]); | 262 | print_bps(result_bps[0]); |
@@ -265,9 +265,9 @@ int bench_mem_memcpy(int argc, const char **argv, | |||
265 | printf(" (with prefault)\n"); | 265 | printf(" (with prefault)\n"); |
266 | } | 266 | } |
267 | } else { | 267 | } else { |
268 | if (use_clock) { | 268 | if (use_cycle) { |
269 | printf(" %14lf Clock/Byte", | 269 | printf(" %14lf Cycle/Byte", |
270 | (double)result_clock[pf] | 270 | (double)result_cycle[pf] |
271 | / (double)len); | 271 | / (double)len); |
272 | } else | 272 | } else |
273 | print_bps(result_bps[pf]); | 273 | print_bps(result_bps[pf]); |
@@ -277,17 +277,17 @@ int bench_mem_memcpy(int argc, const char **argv, | |||
277 | break; | 277 | break; |
278 | case BENCH_FORMAT_SIMPLE: | 278 | case BENCH_FORMAT_SIMPLE: |
279 | if (!only_prefault && !no_prefault) { | 279 | if (!only_prefault && !no_prefault) { |
280 | if (use_clock) { | 280 | if (use_cycle) { |
281 | printf("%lf %lf\n", | 281 | printf("%lf %lf\n", |
282 | (double)result_clock[0] / (double)len, | 282 | (double)result_cycle[0] / (double)len, |
283 | (double)result_clock[1] / (double)len); | 283 | (double)result_cycle[1] / (double)len); |
284 | } else { | 284 | } else { |
285 | printf("%lf %lf\n", | 285 | printf("%lf %lf\n", |
286 | result_bps[0], result_bps[1]); | 286 | result_bps[0], result_bps[1]); |
287 | } | 287 | } |
288 | } else { | 288 | } else { |
289 | if (use_clock) { | 289 | if (use_cycle) { |
290 | printf("%lf\n", (double)result_clock[pf] | 290 | printf("%lf\n", (double)result_cycle[pf] |
291 | / (double)len); | 291 | / (double)len); |
292 | } else | 292 | } else |
293 | printf("%lf\n", result_bps[pf]); | 293 | printf("%lf\n", result_bps[pf]); |
diff --git a/tools/perf/bench/mem-memset.c b/tools/perf/bench/mem-memset.c index e9079185bd72..350cc9557265 100644 --- a/tools/perf/bench/mem-memset.c +++ b/tools/perf/bench/mem-memset.c | |||
@@ -24,21 +24,21 @@ | |||
24 | static const char *length_str = "1MB"; | 24 | static const char *length_str = "1MB"; |
25 | static const char *routine = "default"; | 25 | static const char *routine = "default"; |
26 | static int iterations = 1; | 26 | static int iterations = 1; |
27 | static bool use_clock; | 27 | static bool use_cycle; |
28 | static int clock_fd; | 28 | static int cycle_fd; |
29 | static bool only_prefault; | 29 | static bool only_prefault; |
30 | static bool no_prefault; | 30 | static bool no_prefault; |
31 | 31 | ||
32 | static const struct option options[] = { | 32 | static const struct option options[] = { |
33 | OPT_STRING('l', "length", &length_str, "1MB", | 33 | OPT_STRING('l', "length", &length_str, "1MB", |
34 | "Specify length of memory to copy. " | 34 | "Specify length of memory to set. " |
35 | "available unit: B, MB, GB (upper and lower)"), | 35 | "Available units: B, KB, MB, GB and TB (upper and lower)"), |
36 | OPT_STRING('r', "routine", &routine, "default", | 36 | OPT_STRING('r', "routine", &routine, "default", |
37 | "Specify routine to copy"), | 37 | "Specify routine to set"), |
38 | OPT_INTEGER('i', "iterations", &iterations, | 38 | OPT_INTEGER('i', "iterations", &iterations, |
39 | "repeat memset() invocation this number of times"), | 39 | "repeat memset() invocation this number of times"), |
40 | OPT_BOOLEAN('c', "clock", &use_clock, | 40 | OPT_BOOLEAN('c', "cycle", &use_cycle, |
41 | "Use CPU clock for measuring"), | 41 | "Use cycles event instead of gettimeofday() for measuring"), |
42 | OPT_BOOLEAN('o', "only-prefault", &only_prefault, | 42 | OPT_BOOLEAN('o', "only-prefault", &only_prefault, |
43 | "Show only the result with page faults before memset()"), | 43 | "Show only the result with page faults before memset()"), |
44 | OPT_BOOLEAN('n', "no-prefault", &no_prefault, | 44 | OPT_BOOLEAN('n', "no-prefault", &no_prefault, |
@@ -76,27 +76,27 @@ static const char * const bench_mem_memset_usage[] = { | |||
76 | NULL | 76 | NULL |
77 | }; | 77 | }; |
78 | 78 | ||
79 | static struct perf_event_attr clock_attr = { | 79 | static struct perf_event_attr cycle_attr = { |
80 | .type = PERF_TYPE_HARDWARE, | 80 | .type = PERF_TYPE_HARDWARE, |
81 | .config = PERF_COUNT_HW_CPU_CYCLES | 81 | .config = PERF_COUNT_HW_CPU_CYCLES |
82 | }; | 82 | }; |
83 | 83 | ||
84 | static void init_clock(void) | 84 | static void init_cycle(void) |
85 | { | 85 | { |
86 | clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0); | 86 | cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0); |
87 | 87 | ||
88 | if (clock_fd < 0 && errno == ENOSYS) | 88 | if (cycle_fd < 0 && errno == ENOSYS) |
89 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 89 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
90 | else | 90 | else |
91 | BUG_ON(clock_fd < 0); | 91 | BUG_ON(cycle_fd < 0); |
92 | } | 92 | } |
93 | 93 | ||
94 | static u64 get_clock(void) | 94 | static u64 get_cycle(void) |
95 | { | 95 | { |
96 | int ret; | 96 | int ret; |
97 | u64 clk; | 97 | u64 clk; |
98 | 98 | ||
99 | ret = read(clock_fd, &clk, sizeof(u64)); | 99 | ret = read(cycle_fd, &clk, sizeof(u64)); |
100 | BUG_ON(ret != sizeof(u64)); | 100 | BUG_ON(ret != sizeof(u64)); |
101 | 101 | ||
102 | return clk; | 102 | return clk; |
@@ -115,9 +115,9 @@ static void alloc_mem(void **dst, size_t length) | |||
115 | die("memory allocation failed - maybe length is too large?\n"); | 115 | die("memory allocation failed - maybe length is too large?\n"); |
116 | } | 116 | } |
117 | 117 | ||
118 | static u64 do_memset_clock(memset_t fn, size_t len, bool prefault) | 118 | static u64 do_memset_cycle(memset_t fn, size_t len, bool prefault) |
119 | { | 119 | { |
120 | u64 clock_start = 0ULL, clock_end = 0ULL; | 120 | u64 cycle_start = 0ULL, cycle_end = 0ULL; |
121 | void *dst = NULL; | 121 | void *dst = NULL; |
122 | int i; | 122 | int i; |
123 | 123 | ||
@@ -126,13 +126,13 @@ static u64 do_memset_clock(memset_t fn, size_t len, bool prefault) | |||
126 | if (prefault) | 126 | if (prefault) |
127 | fn(dst, -1, len); | 127 | fn(dst, -1, len); |
128 | 128 | ||
129 | clock_start = get_clock(); | 129 | cycle_start = get_cycle(); |
130 | for (i = 0; i < iterations; ++i) | 130 | for (i = 0; i < iterations; ++i) |
131 | fn(dst, i, len); | 131 | fn(dst, i, len); |
132 | clock_end = get_clock(); | 132 | cycle_end = get_cycle(); |
133 | 133 | ||
134 | free(dst); | 134 | free(dst); |
135 | return clock_end - clock_start; | 135 | return cycle_end - cycle_start; |
136 | } | 136 | } |
137 | 137 | ||
138 | static double do_memset_gettimeofday(memset_t fn, size_t len, bool prefault) | 138 | static double do_memset_gettimeofday(memset_t fn, size_t len, bool prefault) |
@@ -176,17 +176,17 @@ int bench_mem_memset(int argc, const char **argv, | |||
176 | int i; | 176 | int i; |
177 | size_t len; | 177 | size_t len; |
178 | double result_bps[2]; | 178 | double result_bps[2]; |
179 | u64 result_clock[2]; | 179 | u64 result_cycle[2]; |
180 | 180 | ||
181 | argc = parse_options(argc, argv, options, | 181 | argc = parse_options(argc, argv, options, |
182 | bench_mem_memset_usage, 0); | 182 | bench_mem_memset_usage, 0); |
183 | 183 | ||
184 | if (use_clock) | 184 | if (use_cycle) |
185 | init_clock(); | 185 | init_cycle(); |
186 | 186 | ||
187 | len = (size_t)perf_atoll((char *)length_str); | 187 | len = (size_t)perf_atoll((char *)length_str); |
188 | 188 | ||
189 | result_clock[0] = result_clock[1] = 0ULL; | 189 | result_cycle[0] = result_cycle[1] = 0ULL; |
190 | result_bps[0] = result_bps[1] = 0.0; | 190 | result_bps[0] = result_bps[1] = 0.0; |
191 | 191 | ||
192 | if ((s64)len <= 0) { | 192 | if ((s64)len <= 0) { |
@@ -217,11 +217,11 @@ int bench_mem_memset(int argc, const char **argv, | |||
217 | 217 | ||
218 | if (!only_prefault && !no_prefault) { | 218 | if (!only_prefault && !no_prefault) { |
219 | /* show both of results */ | 219 | /* show both of results */ |
220 | if (use_clock) { | 220 | if (use_cycle) { |
221 | result_clock[0] = | 221 | result_cycle[0] = |
222 | do_memset_clock(routines[i].fn, len, false); | 222 | do_memset_cycle(routines[i].fn, len, false); |
223 | result_clock[1] = | 223 | result_cycle[1] = |
224 | do_memset_clock(routines[i].fn, len, true); | 224 | do_memset_cycle(routines[i].fn, len, true); |
225 | } else { | 225 | } else { |
226 | result_bps[0] = | 226 | result_bps[0] = |
227 | do_memset_gettimeofday(routines[i].fn, | 227 | do_memset_gettimeofday(routines[i].fn, |
@@ -231,9 +231,9 @@ int bench_mem_memset(int argc, const char **argv, | |||
231 | len, true); | 231 | len, true); |
232 | } | 232 | } |
233 | } else { | 233 | } else { |
234 | if (use_clock) { | 234 | if (use_cycle) { |
235 | result_clock[pf] = | 235 | result_cycle[pf] = |
236 | do_memset_clock(routines[i].fn, | 236 | do_memset_cycle(routines[i].fn, |
237 | len, only_prefault); | 237 | len, only_prefault); |
238 | } else { | 238 | } else { |
239 | result_bps[pf] = | 239 | result_bps[pf] = |
@@ -245,12 +245,12 @@ int bench_mem_memset(int argc, const char **argv, | |||
245 | switch (bench_format) { | 245 | switch (bench_format) { |
246 | case BENCH_FORMAT_DEFAULT: | 246 | case BENCH_FORMAT_DEFAULT: |
247 | if (!only_prefault && !no_prefault) { | 247 | if (!only_prefault && !no_prefault) { |
248 | if (use_clock) { | 248 | if (use_cycle) { |
249 | printf(" %14lf Clock/Byte\n", | 249 | printf(" %14lf Cycle/Byte\n", |
250 | (double)result_clock[0] | 250 | (double)result_cycle[0] |
251 | / (double)len); | 251 | / (double)len); |
252 | printf(" %14lf Clock/Byte (with prefault)\n ", | 252 | printf(" %14lf Cycle/Byte (with prefault)\n ", |
253 | (double)result_clock[1] | 253 | (double)result_cycle[1] |
254 | / (double)len); | 254 | / (double)len); |
255 | } else { | 255 | } else { |
256 | print_bps(result_bps[0]); | 256 | print_bps(result_bps[0]); |
@@ -259,9 +259,9 @@ int bench_mem_memset(int argc, const char **argv, | |||
259 | printf(" (with prefault)\n"); | 259 | printf(" (with prefault)\n"); |
260 | } | 260 | } |
261 | } else { | 261 | } else { |
262 | if (use_clock) { | 262 | if (use_cycle) { |
263 | printf(" %14lf Clock/Byte", | 263 | printf(" %14lf Cycle/Byte", |
264 | (double)result_clock[pf] | 264 | (double)result_cycle[pf] |
265 | / (double)len); | 265 | / (double)len); |
266 | } else | 266 | } else |
267 | print_bps(result_bps[pf]); | 267 | print_bps(result_bps[pf]); |
@@ -271,17 +271,17 @@ int bench_mem_memset(int argc, const char **argv, | |||
271 | break; | 271 | break; |
272 | case BENCH_FORMAT_SIMPLE: | 272 | case BENCH_FORMAT_SIMPLE: |
273 | if (!only_prefault && !no_prefault) { | 273 | if (!only_prefault && !no_prefault) { |
274 | if (use_clock) { | 274 | if (use_cycle) { |
275 | printf("%lf %lf\n", | 275 | printf("%lf %lf\n", |
276 | (double)result_clock[0] / (double)len, | 276 | (double)result_cycle[0] / (double)len, |
277 | (double)result_clock[1] / (double)len); | 277 | (double)result_cycle[1] / (double)len); |
278 | } else { | 278 | } else { |
279 | printf("%lf %lf\n", | 279 | printf("%lf %lf\n", |
280 | result_bps[0], result_bps[1]); | 280 | result_bps[0], result_bps[1]); |
281 | } | 281 | } |
282 | } else { | 282 | } else { |
283 | if (use_clock) { | 283 | if (use_cycle) { |
284 | printf("%lf\n", (double)result_clock[pf] | 284 | printf("%lf\n", (double)result_cycle[pf] |
285 | / (double)len); | 285 | / (double)len); |
286 | } else | 286 | } else |
287 | printf("%lf\n", result_bps[pf]); | 287 | printf("%lf\n", result_bps[pf]); |
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index b0e74ab2d7a2..1f3100216448 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c | |||
@@ -33,7 +33,7 @@ struct bench_suite { | |||
33 | }; | 33 | }; |
34 | \ | 34 | \ |
35 | /* sentinel: easy for help */ | 35 | /* sentinel: easy for help */ |
36 | #define suite_all { "all", "test all suite (pseudo suite)", NULL } | 36 | #define suite_all { "all", "Test all benchmark suites", NULL } |
37 | 37 | ||
38 | static struct bench_suite sched_suites[] = { | 38 | static struct bench_suite sched_suites[] = { |
39 | { "messaging", | 39 | { "messaging", |
@@ -75,7 +75,7 @@ static struct bench_subsys subsystems[] = { | |||
75 | "memory access performance", | 75 | "memory access performance", |
76 | mem_suites }, | 76 | mem_suites }, |
77 | { "all", /* sentinel: easy for help */ | 77 | { "all", /* sentinel: easy for help */ |
78 | "test all subsystem (pseudo subsystem)", | 78 | "all benchmark subsystem", |
79 | NULL }, | 79 | NULL }, |
80 | { NULL, | 80 | { NULL, |
81 | NULL, | 81 | NULL, |
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index acd78dc28341..0dd5a058f766 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c | |||
@@ -60,7 +60,7 @@ static int __cmd_evlist(const char *input_name, struct perf_attr_details *detail | |||
60 | list_for_each_entry(pos, &session->evlist->entries, node) { | 60 | list_for_each_entry(pos, &session->evlist->entries, node) { |
61 | bool first = true; | 61 | bool first = true; |
62 | 62 | ||
63 | printf("%s", event_name(pos)); | 63 | printf("%s", perf_evsel__name(pos)); |
64 | 64 | ||
65 | if (details->verbose || details->freq) { | 65 | if (details->verbose || details->freq) { |
66 | comma_printf(&first, " sample_freq=%" PRIu64, | 66 | comma_printf(&first, " sample_freq=%" PRIu64, |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 547af48deb4f..ce35015f2dc6 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -57,6 +57,11 @@ static unsigned long nr_allocs, nr_cross_allocs; | |||
57 | 57 | ||
58 | #define PATH_SYS_NODE "/sys/devices/system/node" | 58 | #define PATH_SYS_NODE "/sys/devices/system/node" |
59 | 59 | ||
60 | struct perf_kmem { | ||
61 | struct perf_tool tool; | ||
62 | struct perf_session *session; | ||
63 | }; | ||
64 | |||
60 | static void init_cpunode_map(void) | 65 | static void init_cpunode_map(void) |
61 | { | 66 | { |
62 | FILE *fp; | 67 | FILE *fp; |
@@ -278,14 +283,16 @@ static void process_free_event(void *data, | |||
278 | s_alloc->alloc_cpu = -1; | 283 | s_alloc->alloc_cpu = -1; |
279 | } | 284 | } |
280 | 285 | ||
281 | static void process_raw_event(union perf_event *raw_event __used, void *data, | 286 | static void process_raw_event(struct perf_tool *tool, |
287 | union perf_event *raw_event __used, void *data, | ||
282 | int cpu, u64 timestamp, struct thread *thread) | 288 | int cpu, u64 timestamp, struct thread *thread) |
283 | { | 289 | { |
290 | struct perf_kmem *kmem = container_of(tool, struct perf_kmem, tool); | ||
284 | struct event_format *event; | 291 | struct event_format *event; |
285 | int type; | 292 | int type; |
286 | 293 | ||
287 | type = trace_parse_common_type(data); | 294 | type = trace_parse_common_type(kmem->session->pevent, data); |
288 | event = trace_find_event(type); | 295 | event = pevent_find_event(kmem->session->pevent, type); |
289 | 296 | ||
290 | if (!strcmp(event->name, "kmalloc") || | 297 | if (!strcmp(event->name, "kmalloc") || |
291 | !strcmp(event->name, "kmem_cache_alloc")) { | 298 | !strcmp(event->name, "kmem_cache_alloc")) { |
@@ -306,7 +313,7 @@ static void process_raw_event(union perf_event *raw_event __used, void *data, | |||
306 | } | 313 | } |
307 | } | 314 | } |
308 | 315 | ||
309 | static int process_sample_event(struct perf_tool *tool __used, | 316 | static int process_sample_event(struct perf_tool *tool, |
310 | union perf_event *event, | 317 | union perf_event *event, |
311 | struct perf_sample *sample, | 318 | struct perf_sample *sample, |
312 | struct perf_evsel *evsel __used, | 319 | struct perf_evsel *evsel __used, |
@@ -322,16 +329,18 @@ static int process_sample_event(struct perf_tool *tool __used, | |||
322 | 329 | ||
323 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 330 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
324 | 331 | ||
325 | process_raw_event(event, sample->raw_data, sample->cpu, | 332 | process_raw_event(tool, event, sample->raw_data, sample->cpu, |
326 | sample->time, thread); | 333 | sample->time, thread); |
327 | 334 | ||
328 | return 0; | 335 | return 0; |
329 | } | 336 | } |
330 | 337 | ||
331 | static struct perf_tool perf_kmem = { | 338 | static struct perf_kmem perf_kmem = { |
332 | .sample = process_sample_event, | 339 | .tool = { |
333 | .comm = perf_event__process_comm, | 340 | .sample = process_sample_event, |
334 | .ordered_samples = true, | 341 | .comm = perf_event__process_comm, |
342 | .ordered_samples = true, | ||
343 | }, | ||
335 | }; | 344 | }; |
336 | 345 | ||
337 | static double fragmentation(unsigned long n_req, unsigned long n_alloc) | 346 | static double fragmentation(unsigned long n_req, unsigned long n_alloc) |
@@ -486,11 +495,15 @@ static void sort_result(void) | |||
486 | static int __cmd_kmem(void) | 495 | static int __cmd_kmem(void) |
487 | { | 496 | { |
488 | int err = -EINVAL; | 497 | int err = -EINVAL; |
489 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, | 498 | struct perf_session *session; |
490 | 0, false, &perf_kmem); | 499 | |
500 | session = perf_session__new(input_name, O_RDONLY, 0, false, | ||
501 | &perf_kmem.tool); | ||
491 | if (session == NULL) | 502 | if (session == NULL) |
492 | return -ENOMEM; | 503 | return -ENOMEM; |
493 | 504 | ||
505 | perf_kmem.session = session; | ||
506 | |||
494 | if (perf_session__create_kernel_maps(session) < 0) | 507 | if (perf_session__create_kernel_maps(session) < 0) |
495 | goto out_delete; | 508 | goto out_delete; |
496 | 509 | ||
@@ -498,7 +511,7 @@ static int __cmd_kmem(void) | |||
498 | goto out_delete; | 511 | goto out_delete; |
499 | 512 | ||
500 | setup_pager(); | 513 | setup_pager(); |
501 | err = perf_session__process_events(session, &perf_kmem); | 514 | err = perf_session__process_events(session, &perf_kmem.tool); |
502 | if (err != 0) | 515 | if (err != 0) |
503 | goto out_delete; | 516 | goto out_delete; |
504 | sort_result(); | 517 | sort_result(); |
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index fd53319de20d..b3c428548868 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
@@ -724,8 +724,8 @@ process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread) | |||
724 | struct event_format *event; | 724 | struct event_format *event; |
725 | int type; | 725 | int type; |
726 | 726 | ||
727 | type = trace_parse_common_type(data); | 727 | type = trace_parse_common_type(session->pevent, data); |
728 | event = trace_find_event(type); | 728 | event = pevent_find_event(session->pevent, type); |
729 | 729 | ||
730 | if (!strcmp(event->name, "lock_acquire")) | 730 | if (!strcmp(event->name, "lock_acquire")) |
731 | process_lock_acquire_event(data, event, cpu, timestamp, thread); | 731 | process_lock_acquire_event(data, event, cpu, timestamp, thread); |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f95840d04e4c..f5a6452931e6 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -265,7 +265,7 @@ try_again: | |||
265 | 265 | ||
266 | if (err == ENOENT) { | 266 | if (err == ENOENT) { |
267 | ui__error("The %s event is not supported.\n", | 267 | ui__error("The %s event is not supported.\n", |
268 | event_name(pos)); | 268 | perf_evsel__name(pos)); |
269 | exit(EXIT_FAILURE); | 269 | exit(EXIT_FAILURE); |
270 | } | 270 | } |
271 | 271 | ||
@@ -916,7 +916,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) | |||
916 | usage_with_options(record_usage, record_options); | 916 | usage_with_options(record_usage, record_options); |
917 | 917 | ||
918 | list_for_each_entry(pos, &evsel_list->entries, node) { | 918 | list_for_each_entry(pos, &evsel_list->entries, node) { |
919 | if (perf_header__push_event(pos->attr.config, event_name(pos))) | 919 | if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos))) |
920 | goto out_free_fd; | 920 | goto out_free_fd; |
921 | } | 921 | } |
922 | 922 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 25249f76329d..69b1c1185159 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -69,7 +69,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | |||
69 | 69 | ||
70 | if ((sort__has_parent || symbol_conf.use_callchain) | 70 | if ((sort__has_parent || symbol_conf.use_callchain) |
71 | && sample->callchain) { | 71 | && sample->callchain) { |
72 | err = machine__resolve_callchain(machine, evsel, al->thread, | 72 | err = machine__resolve_callchain(machine, al->thread, |
73 | sample->callchain, &parent); | 73 | sample->callchain, &parent); |
74 | if (err) | 74 | if (err) |
75 | return err; | 75 | return err; |
@@ -140,7 +140,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, | |||
140 | struct hist_entry *he; | 140 | struct hist_entry *he; |
141 | 141 | ||
142 | if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { | 142 | if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { |
143 | err = machine__resolve_callchain(machine, evsel, al->thread, | 143 | err = machine__resolve_callchain(machine, al->thread, |
144 | sample->callchain, &parent); | 144 | sample->callchain, &parent); |
145 | if (err) | 145 | if (err) |
146 | return err; | 146 | return err; |
@@ -230,7 +230,7 @@ static int process_read_event(struct perf_tool *tool, | |||
230 | struct perf_report *rep = container_of(tool, struct perf_report, tool); | 230 | struct perf_report *rep = container_of(tool, struct perf_report, tool); |
231 | 231 | ||
232 | if (rep->show_threads) { | 232 | if (rep->show_threads) { |
233 | const char *name = evsel ? event_name(evsel) : "unknown"; | 233 | const char *name = evsel ? perf_evsel__name(evsel) : "unknown"; |
234 | perf_read_values_add_value(&rep->show_threads_values, | 234 | perf_read_values_add_value(&rep->show_threads_values, |
235 | event->read.pid, event->read.tid, | 235 | event->read.pid, event->read.tid, |
236 | event->read.id, | 236 | event->read.id, |
@@ -239,17 +239,18 @@ static int process_read_event(struct perf_tool *tool, | |||
239 | } | 239 | } |
240 | 240 | ||
241 | dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid, | 241 | dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid, |
242 | evsel ? event_name(evsel) : "FAIL", | 242 | evsel ? perf_evsel__name(evsel) : "FAIL", |
243 | event->read.value); | 243 | event->read.value); |
244 | 244 | ||
245 | return 0; | 245 | return 0; |
246 | } | 246 | } |
247 | 247 | ||
248 | /* For pipe mode, sample_type is not currently set */ | ||
248 | static int perf_report__setup_sample_type(struct perf_report *rep) | 249 | static int perf_report__setup_sample_type(struct perf_report *rep) |
249 | { | 250 | { |
250 | struct perf_session *self = rep->session; | 251 | struct perf_session *self = rep->session; |
251 | 252 | ||
252 | if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { | 253 | if (!self->fd_pipe && !(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { |
253 | if (sort__has_parent) { | 254 | if (sort__has_parent) { |
254 | ui__error("Selected --sort parent, but no " | 255 | ui__error("Selected --sort parent, but no " |
255 | "callchain data. Did you call " | 256 | "callchain data. Did you call " |
@@ -272,7 +273,8 @@ static int perf_report__setup_sample_type(struct perf_report *rep) | |||
272 | } | 273 | } |
273 | 274 | ||
274 | if (sort__branch_mode == 1) { | 275 | if (sort__branch_mode == 1) { |
275 | if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) { | 276 | if (!self->fd_pipe && |
277 | !(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) { | ||
276 | ui__error("Selected -b but no branch data. " | 278 | ui__error("Selected -b but no branch data. " |
277 | "Did you call perf record without -b?\n"); | 279 | "Did you call perf record without -b?\n"); |
278 | return -1; | 280 | return -1; |
@@ -314,7 +316,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
314 | 316 | ||
315 | list_for_each_entry(pos, &evlist->entries, node) { | 317 | list_for_each_entry(pos, &evlist->entries, node) { |
316 | struct hists *hists = &pos->hists; | 318 | struct hists *hists = &pos->hists; |
317 | const char *evname = event_name(pos); | 319 | const char *evname = perf_evsel__name(pos); |
318 | 320 | ||
319 | hists__fprintf_nr_sample_events(hists, evname, stdout); | 321 | hists__fprintf_nr_sample_events(hists, evname, stdout); |
320 | hists__fprintf(hists, NULL, false, true, 0, 0, stdout); | 322 | hists__fprintf(hists, NULL, false, true, 0, 0, stdout); |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index b125e07eb399..7a9ad2b1ee76 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -43,6 +43,11 @@ static u64 sleep_measurement_overhead; | |||
43 | 43 | ||
44 | static unsigned long nr_tasks; | 44 | static unsigned long nr_tasks; |
45 | 45 | ||
46 | struct perf_sched { | ||
47 | struct perf_tool tool; | ||
48 | struct perf_session *session; | ||
49 | }; | ||
50 | |||
46 | struct sched_atom; | 51 | struct sched_atom; |
47 | 52 | ||
48 | struct task_desc { | 53 | struct task_desc { |
@@ -1597,11 +1602,13 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool, | |||
1597 | struct perf_evsel *evsel, | 1602 | struct perf_evsel *evsel, |
1598 | struct machine *machine) | 1603 | struct machine *machine) |
1599 | { | 1604 | { |
1605 | struct perf_sched *sched = container_of(tool, struct perf_sched, tool); | ||
1606 | struct pevent *pevent = sched->session->pevent; | ||
1600 | struct thread *thread = machine__findnew_thread(machine, sample->pid); | 1607 | struct thread *thread = machine__findnew_thread(machine, sample->pid); |
1601 | 1608 | ||
1602 | if (thread == NULL) { | 1609 | if (thread == NULL) { |
1603 | pr_debug("problem processing %s event, skipping it.\n", | 1610 | pr_debug("problem processing %s event, skipping it.\n", |
1604 | evsel->name); | 1611 | perf_evsel__name(evsel)); |
1605 | return -1; | 1612 | return -1; |
1606 | } | 1613 | } |
1607 | 1614 | ||
@@ -1612,7 +1619,8 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool, | |||
1612 | tracepoint_handler f = evsel->handler.func; | 1619 | tracepoint_handler f = evsel->handler.func; |
1613 | 1620 | ||
1614 | if (evsel->handler.data == NULL) | 1621 | if (evsel->handler.data == NULL) |
1615 | evsel->handler.data = trace_find_event(evsel->attr.config); | 1622 | evsel->handler.data = pevent_find_event(pevent, |
1623 | evsel->attr.config); | ||
1616 | 1624 | ||
1617 | f(tool, evsel->handler.data, sample, machine, thread); | 1625 | f(tool, evsel->handler.data, sample, machine, thread); |
1618 | } | 1626 | } |
@@ -1620,12 +1628,14 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool, | |||
1620 | return 0; | 1628 | return 0; |
1621 | } | 1629 | } |
1622 | 1630 | ||
1623 | static struct perf_tool perf_sched = { | 1631 | static struct perf_sched perf_sched = { |
1624 | .sample = perf_sched__process_tracepoint_sample, | 1632 | .tool = { |
1625 | .comm = perf_event__process_comm, | 1633 | .sample = perf_sched__process_tracepoint_sample, |
1626 | .lost = perf_event__process_lost, | 1634 | .comm = perf_event__process_comm, |
1627 | .fork = perf_event__process_task, | 1635 | .lost = perf_event__process_lost, |
1628 | .ordered_samples = true, | 1636 | .fork = perf_event__process_task, |
1637 | .ordered_samples = true, | ||
1638 | }, | ||
1629 | }; | 1639 | }; |
1630 | 1640 | ||
1631 | static void read_events(bool destroy, struct perf_session **psession) | 1641 | static void read_events(bool destroy, struct perf_session **psession) |
@@ -1640,16 +1650,20 @@ static void read_events(bool destroy, struct perf_session **psession) | |||
1640 | { "sched:sched_process_exit", process_sched_exit_event, }, | 1650 | { "sched:sched_process_exit", process_sched_exit_event, }, |
1641 | { "sched:sched_migrate_task", process_sched_migrate_task_event, }, | 1651 | { "sched:sched_migrate_task", process_sched_migrate_task_event, }, |
1642 | }; | 1652 | }; |
1643 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, | 1653 | struct perf_session *session; |
1644 | 0, false, &perf_sched); | 1654 | |
1655 | session = perf_session__new(input_name, O_RDONLY, 0, false, | ||
1656 | &perf_sched.tool); | ||
1645 | if (session == NULL) | 1657 | if (session == NULL) |
1646 | die("No Memory"); | 1658 | die("No Memory"); |
1647 | 1659 | ||
1648 | err = perf_evlist__set_tracepoints_handlers_array(session->evlist, handlers); | 1660 | perf_sched.session = session; |
1661 | |||
1662 | err = perf_session__set_tracepoints_handlers(session, handlers); | ||
1649 | assert(err == 0); | 1663 | assert(err == 0); |
1650 | 1664 | ||
1651 | if (perf_session__has_traces(session, "record -R")) { | 1665 | if (perf_session__has_traces(session, "record -R")) { |
1652 | err = perf_session__process_events(session, &perf_sched); | 1666 | err = perf_session__process_events(session, &perf_sched.tool); |
1653 | if (err) | 1667 | if (err) |
1654 | die("Failed to process events, error %d", err); | 1668 | die("Failed to process events, error %d", err); |
1655 | 1669 | ||
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 8e395a538eb9..1e60ab70b2b1 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -28,6 +28,11 @@ static bool system_wide; | |||
28 | static const char *cpu_list; | 28 | static const char *cpu_list; |
29 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 29 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
30 | 30 | ||
31 | struct perf_script { | ||
32 | struct perf_tool tool; | ||
33 | struct perf_session *session; | ||
34 | }; | ||
35 | |||
31 | enum perf_output_field { | 36 | enum perf_output_field { |
32 | PERF_OUTPUT_COMM = 1U << 0, | 37 | PERF_OUTPUT_COMM = 1U << 0, |
33 | PERF_OUTPUT_TID = 1U << 1, | 38 | PERF_OUTPUT_TID = 1U << 1, |
@@ -137,10 +142,11 @@ static const char *output_field2str(enum perf_output_field field) | |||
137 | 142 | ||
138 | #define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) | 143 | #define PRINT_FIELD(x) (output[attr->type].fields & PERF_OUTPUT_##x) |
139 | 144 | ||
140 | static int perf_event_attr__check_stype(struct perf_event_attr *attr, | 145 | static int perf_evsel__check_stype(struct perf_evsel *evsel, |
141 | u64 sample_type, const char *sample_msg, | 146 | u64 sample_type, const char *sample_msg, |
142 | enum perf_output_field field) | 147 | enum perf_output_field field) |
143 | { | 148 | { |
149 | struct perf_event_attr *attr = &evsel->attr; | ||
144 | int type = attr->type; | 150 | int type = attr->type; |
145 | const char *evname; | 151 | const char *evname; |
146 | 152 | ||
@@ -148,7 +154,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr, | |||
148 | return 0; | 154 | return 0; |
149 | 155 | ||
150 | if (output[type].user_set) { | 156 | if (output[type].user_set) { |
151 | evname = __event_name(attr->type, attr->config); | 157 | evname = perf_evsel__name(evsel); |
152 | pr_err("Samples for '%s' event do not have %s attribute set. " | 158 | pr_err("Samples for '%s' event do not have %s attribute set. " |
153 | "Cannot print '%s' field.\n", | 159 | "Cannot print '%s' field.\n", |
154 | evname, sample_msg, output_field2str(field)); | 160 | evname, sample_msg, output_field2str(field)); |
@@ -157,7 +163,7 @@ static int perf_event_attr__check_stype(struct perf_event_attr *attr, | |||
157 | 163 | ||
158 | /* user did not ask for it explicitly so remove from the default list */ | 164 | /* user did not ask for it explicitly so remove from the default list */ |
159 | output[type].fields &= ~field; | 165 | output[type].fields &= ~field; |
160 | evname = __event_name(attr->type, attr->config); | 166 | evname = perf_evsel__name(evsel); |
161 | pr_debug("Samples for '%s' event do not have %s attribute set. " | 167 | pr_debug("Samples for '%s' event do not have %s attribute set. " |
162 | "Skipping '%s' field.\n", | 168 | "Skipping '%s' field.\n", |
163 | evname, sample_msg, output_field2str(field)); | 169 | evname, sample_msg, output_field2str(field)); |
@@ -175,8 +181,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
175 | return -EINVAL; | 181 | return -EINVAL; |
176 | 182 | ||
177 | if (PRINT_FIELD(IP)) { | 183 | if (PRINT_FIELD(IP)) { |
178 | if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP", | 184 | if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", |
179 | PERF_OUTPUT_IP)) | 185 | PERF_OUTPUT_IP)) |
180 | return -EINVAL; | 186 | return -EINVAL; |
181 | 187 | ||
182 | if (!no_callchain && | 188 | if (!no_callchain && |
@@ -185,8 +191,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
185 | } | 191 | } |
186 | 192 | ||
187 | if (PRINT_FIELD(ADDR) && | 193 | if (PRINT_FIELD(ADDR) && |
188 | perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR", | 194 | perf_evsel__check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR", |
189 | PERF_OUTPUT_ADDR)) | 195 | PERF_OUTPUT_ADDR)) |
190 | return -EINVAL; | 196 | return -EINVAL; |
191 | 197 | ||
192 | if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { | 198 | if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { |
@@ -208,18 +214,18 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
208 | } | 214 | } |
209 | 215 | ||
210 | if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && | 216 | if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && |
211 | perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID", | 217 | perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", |
212 | PERF_OUTPUT_TID|PERF_OUTPUT_PID)) | 218 | PERF_OUTPUT_TID|PERF_OUTPUT_PID)) |
213 | return -EINVAL; | 219 | return -EINVAL; |
214 | 220 | ||
215 | if (PRINT_FIELD(TIME) && | 221 | if (PRINT_FIELD(TIME) && |
216 | perf_event_attr__check_stype(attr, PERF_SAMPLE_TIME, "TIME", | 222 | perf_evsel__check_stype(evsel, PERF_SAMPLE_TIME, "TIME", |
217 | PERF_OUTPUT_TIME)) | 223 | PERF_OUTPUT_TIME)) |
218 | return -EINVAL; | 224 | return -EINVAL; |
219 | 225 | ||
220 | if (PRINT_FIELD(CPU) && | 226 | if (PRINT_FIELD(CPU) && |
221 | perf_event_attr__check_stype(attr, PERF_SAMPLE_CPU, "CPU", | 227 | perf_evsel__check_stype(evsel, PERF_SAMPLE_CPU, "CPU", |
222 | PERF_OUTPUT_CPU)) | 228 | PERF_OUTPUT_CPU)) |
223 | return -EINVAL; | 229 | return -EINVAL; |
224 | 230 | ||
225 | return 0; | 231 | return 0; |
@@ -256,11 +262,13 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
256 | return 0; | 262 | return 0; |
257 | } | 263 | } |
258 | 264 | ||
259 | static void print_sample_start(struct perf_sample *sample, | 265 | static void print_sample_start(struct pevent *pevent, |
266 | struct perf_sample *sample, | ||
260 | struct thread *thread, | 267 | struct thread *thread, |
261 | struct perf_event_attr *attr) | 268 | struct perf_evsel *evsel) |
262 | { | 269 | { |
263 | int type; | 270 | int type; |
271 | struct perf_event_attr *attr = &evsel->attr; | ||
264 | struct event_format *event; | 272 | struct event_format *event; |
265 | const char *evname = NULL; | 273 | const char *evname = NULL; |
266 | unsigned long secs; | 274 | unsigned long secs; |
@@ -300,12 +308,18 @@ static void print_sample_start(struct perf_sample *sample, | |||
300 | 308 | ||
301 | if (PRINT_FIELD(EVNAME)) { | 309 | if (PRINT_FIELD(EVNAME)) { |
302 | if (attr->type == PERF_TYPE_TRACEPOINT) { | 310 | if (attr->type == PERF_TYPE_TRACEPOINT) { |
303 | type = trace_parse_common_type(sample->raw_data); | 311 | /* |
304 | event = trace_find_event(type); | 312 | * XXX Do we really need this here? |
313 | * perf_evlist__set_tracepoint_names should have done | ||
314 | * this already | ||
315 | */ | ||
316 | type = trace_parse_common_type(pevent, | ||
317 | sample->raw_data); | ||
318 | event = pevent_find_event(pevent, type); | ||
305 | if (event) | 319 | if (event) |
306 | evname = event->name; | 320 | evname = event->name; |
307 | } else | 321 | } else |
308 | evname = __event_name(attr->type, attr->config); | 322 | evname = perf_evsel__name(evsel); |
309 | 323 | ||
310 | printf("%s: ", evname ? evname : "[unknown]"); | 324 | printf("%s: ", evname ? evname : "[unknown]"); |
311 | } | 325 | } |
@@ -387,7 +401,7 @@ static void print_sample_bts(union perf_event *event, | |||
387 | printf(" "); | 401 | printf(" "); |
388 | else | 402 | else |
389 | printf("\n"); | 403 | printf("\n"); |
390 | perf_event__print_ip(event, sample, machine, evsel, | 404 | perf_event__print_ip(event, sample, machine, |
391 | PRINT_FIELD(SYM), PRINT_FIELD(DSO), | 405 | PRINT_FIELD(SYM), PRINT_FIELD(DSO), |
392 | PRINT_FIELD(SYMOFFSET)); | 406 | PRINT_FIELD(SYMOFFSET)); |
393 | } | 407 | } |
@@ -402,6 +416,7 @@ static void print_sample_bts(union perf_event *event, | |||
402 | } | 416 | } |
403 | 417 | ||
404 | static void process_event(union perf_event *event __unused, | 418 | static void process_event(union perf_event *event __unused, |
419 | struct pevent *pevent, | ||
405 | struct perf_sample *sample, | 420 | struct perf_sample *sample, |
406 | struct perf_evsel *evsel, | 421 | struct perf_evsel *evsel, |
407 | struct machine *machine, | 422 | struct machine *machine, |
@@ -412,7 +427,7 @@ static void process_event(union perf_event *event __unused, | |||
412 | if (output[attr->type].fields == 0) | 427 | if (output[attr->type].fields == 0) |
413 | return; | 428 | return; |
414 | 429 | ||
415 | print_sample_start(sample, thread, attr); | 430 | print_sample_start(pevent, sample, thread, evsel); |
416 | 431 | ||
417 | if (is_bts_event(attr)) { | 432 | if (is_bts_event(attr)) { |
418 | print_sample_bts(event, sample, evsel, machine, thread); | 433 | print_sample_bts(event, sample, evsel, machine, thread); |
@@ -420,7 +435,7 @@ static void process_event(union perf_event *event __unused, | |||
420 | } | 435 | } |
421 | 436 | ||
422 | if (PRINT_FIELD(TRACE)) | 437 | if (PRINT_FIELD(TRACE)) |
423 | print_trace_event(sample->cpu, sample->raw_data, | 438 | print_trace_event(pevent, sample->cpu, sample->raw_data, |
424 | sample->raw_size); | 439 | sample->raw_size); |
425 | 440 | ||
426 | if (PRINT_FIELD(ADDR)) | 441 | if (PRINT_FIELD(ADDR)) |
@@ -431,7 +446,7 @@ static void process_event(union perf_event *event __unused, | |||
431 | printf(" "); | 446 | printf(" "); |
432 | else | 447 | else |
433 | printf("\n"); | 448 | printf("\n"); |
434 | perf_event__print_ip(event, sample, machine, evsel, | 449 | perf_event__print_ip(event, sample, machine, |
435 | PRINT_FIELD(SYM), PRINT_FIELD(DSO), | 450 | PRINT_FIELD(SYM), PRINT_FIELD(DSO), |
436 | PRINT_FIELD(SYMOFFSET)); | 451 | PRINT_FIELD(SYMOFFSET)); |
437 | } | 452 | } |
@@ -451,7 +466,8 @@ static int default_stop_script(void) | |||
451 | return 0; | 466 | return 0; |
452 | } | 467 | } |
453 | 468 | ||
454 | static int default_generate_script(const char *outfile __unused) | 469 | static int default_generate_script(struct pevent *pevent __unused, |
470 | const char *outfile __unused) | ||
455 | { | 471 | { |
456 | return 0; | 472 | return 0; |
457 | } | 473 | } |
@@ -489,6 +505,7 @@ static int process_sample_event(struct perf_tool *tool __used, | |||
489 | struct machine *machine) | 505 | struct machine *machine) |
490 | { | 506 | { |
491 | struct addr_location al; | 507 | struct addr_location al; |
508 | struct perf_script *scr = container_of(tool, struct perf_script, tool); | ||
492 | struct thread *thread = machine__findnew_thread(machine, event->ip.tid); | 509 | struct thread *thread = machine__findnew_thread(machine, event->ip.tid); |
493 | 510 | ||
494 | if (thread == NULL) { | 511 | if (thread == NULL) { |
@@ -520,24 +537,27 @@ static int process_sample_event(struct perf_tool *tool __used, | |||
520 | if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) | 537 | if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) |
521 | return 0; | 538 | return 0; |
522 | 539 | ||
523 | scripting_ops->process_event(event, sample, evsel, machine, thread); | 540 | scripting_ops->process_event(event, scr->session->pevent, |
541 | sample, evsel, machine, thread); | ||
524 | 542 | ||
525 | evsel->hists.stats.total_period += sample->period; | 543 | evsel->hists.stats.total_period += sample->period; |
526 | return 0; | 544 | return 0; |
527 | } | 545 | } |
528 | 546 | ||
529 | static struct perf_tool perf_script = { | 547 | static struct perf_script perf_script = { |
530 | .sample = process_sample_event, | 548 | .tool = { |
531 | .mmap = perf_event__process_mmap, | 549 | .sample = process_sample_event, |
532 | .comm = perf_event__process_comm, | 550 | .mmap = perf_event__process_mmap, |
533 | .exit = perf_event__process_task, | 551 | .comm = perf_event__process_comm, |
534 | .fork = perf_event__process_task, | 552 | .exit = perf_event__process_task, |
535 | .attr = perf_event__process_attr, | 553 | .fork = perf_event__process_task, |
536 | .event_type = perf_event__process_event_type, | 554 | .attr = perf_event__process_attr, |
537 | .tracing_data = perf_event__process_tracing_data, | 555 | .event_type = perf_event__process_event_type, |
538 | .build_id = perf_event__process_build_id, | 556 | .tracing_data = perf_event__process_tracing_data, |
539 | .ordered_samples = true, | 557 | .build_id = perf_event__process_build_id, |
540 | .ordering_requires_timestamps = true, | 558 | .ordered_samples = true, |
559 | .ordering_requires_timestamps = true, | ||
560 | }, | ||
541 | }; | 561 | }; |
542 | 562 | ||
543 | extern volatile int session_done; | 563 | extern volatile int session_done; |
@@ -553,7 +573,7 @@ static int __cmd_script(struct perf_session *session) | |||
553 | 573 | ||
554 | signal(SIGINT, sig_handler); | 574 | signal(SIGINT, sig_handler); |
555 | 575 | ||
556 | ret = perf_session__process_events(session, &perf_script); | 576 | ret = perf_session__process_events(session, &perf_script.tool); |
557 | 577 | ||
558 | if (debug_mode) | 578 | if (debug_mode) |
559 | pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); | 579 | pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); |
@@ -1335,10 +1355,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
1335 | if (!script_name) | 1355 | if (!script_name) |
1336 | setup_pager(); | 1356 | setup_pager(); |
1337 | 1357 | ||
1338 | session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_script); | 1358 | session = perf_session__new(input_name, O_RDONLY, 0, false, |
1359 | &perf_script.tool); | ||
1339 | if (session == NULL) | 1360 | if (session == NULL) |
1340 | return -ENOMEM; | 1361 | return -ENOMEM; |
1341 | 1362 | ||
1363 | perf_script.session = session; | ||
1364 | |||
1342 | if (cpu_list) { | 1365 | if (cpu_list) { |
1343 | if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) | 1366 | if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) |
1344 | return -1; | 1367 | return -1; |
@@ -1384,7 +1407,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) | |||
1384 | return -1; | 1407 | return -1; |
1385 | } | 1408 | } |
1386 | 1409 | ||
1387 | err = scripting_ops->generate_script("perf-script"); | 1410 | err = scripting_ops->generate_script(session->pevent, |
1411 | "perf-script"); | ||
1388 | goto out; | 1412 | goto out; |
1389 | } | 1413 | } |
1390 | 1414 | ||
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 07b5c7703dd1..861f0aec77ae 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -391,7 +391,7 @@ static int read_counter_aggr(struct perf_evsel *counter) | |||
391 | 391 | ||
392 | if (verbose) { | 392 | if (verbose) { |
393 | fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", | 393 | fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", |
394 | event_name(counter), count[0], count[1], count[2]); | 394 | perf_evsel__name(counter), count[0], count[1], count[2]); |
395 | } | 395 | } |
396 | 396 | ||
397 | /* | 397 | /* |
@@ -496,7 +496,7 @@ static int run_perf_stat(int argc __used, const char **argv) | |||
496 | errno == ENXIO) { | 496 | errno == ENXIO) { |
497 | if (verbose) | 497 | if (verbose) |
498 | ui__warning("%s event is not supported by the kernel.\n", | 498 | ui__warning("%s event is not supported by the kernel.\n", |
499 | event_name(counter)); | 499 | perf_evsel__name(counter)); |
500 | counter->supported = false; | 500 | counter->supported = false; |
501 | continue; | 501 | continue; |
502 | } | 502 | } |
@@ -594,7 +594,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
594 | csv_output ? 0 : -4, | 594 | csv_output ? 0 : -4, |
595 | evsel_list->cpus->map[cpu], csv_sep); | 595 | evsel_list->cpus->map[cpu], csv_sep); |
596 | 596 | ||
597 | fprintf(output, fmt, cpustr, msecs, csv_sep, event_name(evsel)); | 597 | fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel)); |
598 | 598 | ||
599 | if (evsel->cgrp) | 599 | if (evsel->cgrp) |
600 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); | 600 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); |
@@ -792,7 +792,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
792 | else | 792 | else |
793 | cpu = 0; | 793 | cpu = 0; |
794 | 794 | ||
795 | fprintf(output, fmt, cpustr, avg, csv_sep, event_name(evsel)); | 795 | fprintf(output, fmt, cpustr, avg, csv_sep, perf_evsel__name(evsel)); |
796 | 796 | ||
797 | if (evsel->cgrp) | 797 | if (evsel->cgrp) |
798 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); | 798 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); |
@@ -908,7 +908,7 @@ static void print_counter_aggr(struct perf_evsel *counter) | |||
908 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, | 908 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, |
909 | csv_sep, | 909 | csv_sep, |
910 | csv_output ? 0 : -24, | 910 | csv_output ? 0 : -24, |
911 | event_name(counter)); | 911 | perf_evsel__name(counter)); |
912 | 912 | ||
913 | if (counter->cgrp) | 913 | if (counter->cgrp) |
914 | fprintf(output, "%s%s", csv_sep, counter->cgrp->name); | 914 | fprintf(output, "%s%s", csv_sep, counter->cgrp->name); |
@@ -961,7 +961,7 @@ static void print_counter(struct perf_evsel *counter) | |||
961 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, | 961 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, |
962 | csv_sep, | 962 | csv_sep, |
963 | csv_output ? 0 : -24, | 963 | csv_output ? 0 : -24, |
964 | event_name(counter)); | 964 | perf_evsel__name(counter)); |
965 | 965 | ||
966 | if (counter->cgrp) | 966 | if (counter->cgrp) |
967 | fprintf(output, "%s%s", | 967 | fprintf(output, "%s%s", |
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 5a8727c08757..5ce30305462b 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
@@ -583,7 +583,7 @@ static int test__basic_mmap(void) | |||
583 | if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { | 583 | if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { |
584 | pr_debug("expected %d %s events, got %d\n", | 584 | pr_debug("expected %d %s events, got %d\n", |
585 | expected_nr_events[evsel->idx], | 585 | expected_nr_events[evsel->idx], |
586 | event_name(evsel), nr_events[evsel->idx]); | 586 | perf_evsel__name(evsel), nr_events[evsel->idx]); |
587 | goto out_munmap; | 587 | goto out_munmap; |
588 | } | 588 | } |
589 | } | 589 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 6bb0277b7dfe..e3cab5f088f8 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -245,7 +245,7 @@ static void perf_top__show_details(struct perf_top *top) | |||
245 | if (notes->src == NULL) | 245 | if (notes->src == NULL) |
246 | goto out_unlock; | 246 | goto out_unlock; |
247 | 247 | ||
248 | printf("Showing %s for %s\n", event_name(top->sym_evsel), symbol->name); | 248 | printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); |
249 | printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); | 249 | printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); |
250 | 250 | ||
251 | more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx, | 251 | more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx, |
@@ -408,7 +408,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top) | |||
408 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries); | 408 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries); |
409 | 409 | ||
410 | if (top->evlist->nr_entries > 1) | 410 | if (top->evlist->nr_entries > 1) |
411 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top->sym_evsel)); | 411 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", perf_evsel__name(top->sym_evsel)); |
412 | 412 | ||
413 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); | 413 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); |
414 | 414 | ||
@@ -503,13 +503,13 @@ static void perf_top__handle_keypress(struct perf_top *top, int c) | |||
503 | fprintf(stderr, "\nAvailable events:"); | 503 | fprintf(stderr, "\nAvailable events:"); |
504 | 504 | ||
505 | list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) | 505 | list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) |
506 | fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, event_name(top->sym_evsel)); | 506 | fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel)); |
507 | 507 | ||
508 | prompt_integer(&counter, "Enter details event counter"); | 508 | prompt_integer(&counter, "Enter details event counter"); |
509 | 509 | ||
510 | if (counter >= top->evlist->nr_entries) { | 510 | if (counter >= top->evlist->nr_entries) { |
511 | top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node); | 511 | top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node); |
512 | fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top->sym_evsel)); | 512 | fprintf(stderr, "Sorry, no such event, using %s.\n", perf_evsel__name(top->sym_evsel)); |
513 | sleep(1); | 513 | sleep(1); |
514 | break; | 514 | break; |
515 | } | 515 | } |
@@ -774,7 +774,7 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
774 | 774 | ||
775 | if ((sort__has_parent || symbol_conf.use_callchain) && | 775 | if ((sort__has_parent || symbol_conf.use_callchain) && |
776 | sample->callchain) { | 776 | sample->callchain) { |
777 | err = machine__resolve_callchain(machine, evsel, al.thread, | 777 | err = machine__resolve_callchain(machine, al.thread, |
778 | sample->callchain, &parent); | 778 | sample->callchain, &parent); |
779 | if (err) | 779 | if (err) |
780 | return; | 780 | return; |
@@ -960,7 +960,7 @@ try_again: | |||
960 | 960 | ||
961 | if (err == ENOENT) { | 961 | if (err == ENOENT) { |
962 | ui__error("The %s event is not supported.\n", | 962 | ui__error("The %s event is not supported.\n", |
963 | event_name(counter)); | 963 | perf_evsel__name(counter)); |
964 | goto out_err; | 964 | goto out_err; |
965 | } else if (err == EMFILE) { | 965 | } else if (err == EMFILE) { |
966 | ui__error("Too many events are opened.\n" | 966 | ui__error("Too many events are opened.\n" |
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak index d9084e03ce56..6c18785a6417 100644 --- a/tools/perf/config/feature-tests.mak +++ b/tools/perf/config/feature-tests.mak | |||
@@ -78,6 +78,19 @@ int main(int argc, char *argv[]) | |||
78 | return 0; | 78 | return 0; |
79 | } | 79 | } |
80 | endef | 80 | endef |
81 | |||
82 | define SOURCE_GTK2_INFOBAR | ||
83 | #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" | ||
84 | #include <gtk/gtk.h> | ||
85 | #pragma GCC diagnostic error \"-Wstrict-prototypes\" | ||
86 | |||
87 | int main(void) | ||
88 | { | ||
89 | gtk_info_bar_new(); | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | endef | ||
81 | endif | 94 | endif |
82 | 95 | ||
83 | ifndef NO_LIBPERL | 96 | ifndef NO_LIBPERL |
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 34b1c46eaf42..67a2703e666a 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -814,7 +814,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
814 | { | 814 | { |
815 | struct disasm_line *pos, *n; | 815 | struct disasm_line *pos, *n; |
816 | struct annotation *notes; | 816 | struct annotation *notes; |
817 | const size_t size = symbol__size(sym); | 817 | size_t size; |
818 | struct map_symbol ms = { | 818 | struct map_symbol ms = { |
819 | .map = map, | 819 | .map = map, |
820 | .sym = sym, | 820 | .sym = sym, |
@@ -834,6 +834,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
834 | if (sym == NULL) | 834 | if (sym == NULL) |
835 | return -1; | 835 | return -1; |
836 | 836 | ||
837 | size = symbol__size(sym); | ||
838 | |||
837 | if (map->dso->annotate_warned) | 839 | if (map->dso->annotate_warned) |
838 | return -1; | 840 | return -1; |
839 | 841 | ||
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 53f6697d014e..482f0517b61e 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -23,6 +23,7 @@ struct hist_browser { | |||
23 | struct hists *hists; | 23 | struct hists *hists; |
24 | struct hist_entry *he_selection; | 24 | struct hist_entry *he_selection; |
25 | struct map_symbol *selection; | 25 | struct map_symbol *selection; |
26 | int print_seq; | ||
26 | bool has_symbols; | 27 | bool has_symbols; |
27 | }; | 28 | }; |
28 | 29 | ||
@@ -800,6 +801,196 @@ do_offset: | |||
800 | } | 801 | } |
801 | } | 802 | } |
802 | 803 | ||
804 | static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser, | ||
805 | struct callchain_node *chain_node, | ||
806 | u64 total, int level, | ||
807 | FILE *fp) | ||
808 | { | ||
809 | struct rb_node *node; | ||
810 | int offset = level * LEVEL_OFFSET_STEP; | ||
811 | u64 new_total, remaining; | ||
812 | int printed = 0; | ||
813 | |||
814 | if (callchain_param.mode == CHAIN_GRAPH_REL) | ||
815 | new_total = chain_node->children_hit; | ||
816 | else | ||
817 | new_total = total; | ||
818 | |||
819 | remaining = new_total; | ||
820 | node = rb_first(&chain_node->rb_root); | ||
821 | while (node) { | ||
822 | struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); | ||
823 | struct rb_node *next = rb_next(node); | ||
824 | u64 cumul = callchain_cumul_hits(child); | ||
825 | struct callchain_list *chain; | ||
826 | char folded_sign = ' '; | ||
827 | int first = true; | ||
828 | int extra_offset = 0; | ||
829 | |||
830 | remaining -= cumul; | ||
831 | |||
832 | list_for_each_entry(chain, &child->val, list) { | ||
833 | char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str; | ||
834 | const char *str; | ||
835 | bool was_first = first; | ||
836 | |||
837 | if (first) | ||
838 | first = false; | ||
839 | else | ||
840 | extra_offset = LEVEL_OFFSET_STEP; | ||
841 | |||
842 | folded_sign = callchain_list__folded(chain); | ||
843 | |||
844 | alloc_str = NULL; | ||
845 | str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr)); | ||
846 | if (was_first) { | ||
847 | double percent = cumul * 100.0 / new_total; | ||
848 | |||
849 | if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) | ||
850 | str = "Not enough memory!"; | ||
851 | else | ||
852 | str = alloc_str; | ||
853 | } | ||
854 | |||
855 | printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str); | ||
856 | free(alloc_str); | ||
857 | if (folded_sign == '+') | ||
858 | break; | ||
859 | } | ||
860 | |||
861 | if (folded_sign == '-') { | ||
862 | const int new_level = level + (extra_offset ? 2 : 1); | ||
863 | printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total, | ||
864 | new_level, fp); | ||
865 | } | ||
866 | |||
867 | node = next; | ||
868 | } | ||
869 | |||
870 | return printed; | ||
871 | } | ||
872 | |||
873 | static int hist_browser__fprintf_callchain_node(struct hist_browser *browser, | ||
874 | struct callchain_node *node, | ||
875 | int level, FILE *fp) | ||
876 | { | ||
877 | struct callchain_list *chain; | ||
878 | int offset = level * LEVEL_OFFSET_STEP; | ||
879 | char folded_sign = ' '; | ||
880 | int printed = 0; | ||
881 | |||
882 | list_for_each_entry(chain, &node->val, list) { | ||
883 | char ipstr[BITS_PER_LONG / 4 + 1], *s; | ||
884 | |||
885 | folded_sign = callchain_list__folded(chain); | ||
886 | s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr)); | ||
887 | printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s); | ||
888 | } | ||
889 | |||
890 | if (folded_sign == '-') | ||
891 | printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node, | ||
892 | browser->hists->stats.total_period, | ||
893 | level + 1, fp); | ||
894 | return printed; | ||
895 | } | ||
896 | |||
897 | static int hist_browser__fprintf_callchain(struct hist_browser *browser, | ||
898 | struct rb_root *chain, int level, FILE *fp) | ||
899 | { | ||
900 | struct rb_node *nd; | ||
901 | int printed = 0; | ||
902 | |||
903 | for (nd = rb_first(chain); nd; nd = rb_next(nd)) { | ||
904 | struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); | ||
905 | |||
906 | printed += hist_browser__fprintf_callchain_node(browser, node, level, fp); | ||
907 | } | ||
908 | |||
909 | return printed; | ||
910 | } | ||
911 | |||
912 | static int hist_browser__fprintf_entry(struct hist_browser *browser, | ||
913 | struct hist_entry *he, FILE *fp) | ||
914 | { | ||
915 | char s[8192]; | ||
916 | double percent; | ||
917 | int printed = 0; | ||
918 | char folded_sign = ' '; | ||
919 | |||
920 | if (symbol_conf.use_callchain) | ||
921 | folded_sign = hist_entry__folded(he); | ||
922 | |||
923 | hist_entry__snprintf(he, s, sizeof(s), browser->hists); | ||
924 | percent = (he->period * 100.0) / browser->hists->stats.total_period; | ||
925 | |||
926 | if (symbol_conf.use_callchain) | ||
927 | printed += fprintf(fp, "%c ", folded_sign); | ||
928 | |||
929 | printed += fprintf(fp, " %5.2f%%", percent); | ||
930 | |||
931 | if (symbol_conf.show_nr_samples) | ||
932 | printed += fprintf(fp, " %11u", he->nr_events); | ||
933 | |||
934 | if (symbol_conf.show_total_period) | ||
935 | printed += fprintf(fp, " %12" PRIu64, he->period); | ||
936 | |||
937 | printed += fprintf(fp, "%s\n", rtrim(s)); | ||
938 | |||
939 | if (folded_sign == '-') | ||
940 | printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp); | ||
941 | |||
942 | return printed; | ||
943 | } | ||
944 | |||
945 | static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) | ||
946 | { | ||
947 | struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries)); | ||
948 | int printed = 0; | ||
949 | |||
950 | while (nd) { | ||
951 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | ||
952 | |||
953 | printed += hist_browser__fprintf_entry(browser, h, fp); | ||
954 | nd = hists__filter_entries(rb_next(nd)); | ||
955 | } | ||
956 | |||
957 | return printed; | ||
958 | } | ||
959 | |||
960 | static int hist_browser__dump(struct hist_browser *browser) | ||
961 | { | ||
962 | char filename[64]; | ||
963 | FILE *fp; | ||
964 | |||
965 | while (1) { | ||
966 | scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq); | ||
967 | if (access(filename, F_OK)) | ||
968 | break; | ||
969 | /* | ||
970 | * XXX: Just an arbitrary lazy upper limit | ||
971 | */ | ||
972 | if (++browser->print_seq == 8192) { | ||
973 | ui_helpline__fpush("Too many perf.hist.N files, nothing written!"); | ||
974 | return -1; | ||
975 | } | ||
976 | } | ||
977 | |||
978 | fp = fopen(filename, "w"); | ||
979 | if (fp == NULL) { | ||
980 | char bf[64]; | ||
981 | strerror_r(errno, bf, sizeof(bf)); | ||
982 | ui_helpline__fpush("Couldn't write to %s: %s", filename, bf); | ||
983 | return -1; | ||
984 | } | ||
985 | |||
986 | ++browser->print_seq; | ||
987 | hist_browser__fprintf(browser, fp); | ||
988 | fclose(fp); | ||
989 | ui_helpline__fpush("%s written!", filename); | ||
990 | |||
991 | return 0; | ||
992 | } | ||
993 | |||
803 | static struct hist_browser *hist_browser__new(struct hists *hists) | 994 | static struct hist_browser *hist_browser__new(struct hists *hists) |
804 | { | 995 | { |
805 | struct hist_browser *browser = zalloc(sizeof(*browser)); | 996 | struct hist_browser *browser = zalloc(sizeof(*browser)); |
@@ -937,6 +1128,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
937 | browser->selection->map->dso->annotate_warned) | 1128 | browser->selection->map->dso->annotate_warned) |
938 | continue; | 1129 | continue; |
939 | goto do_annotate; | 1130 | goto do_annotate; |
1131 | case 'P': | ||
1132 | hist_browser__dump(browser); | ||
1133 | continue; | ||
940 | case 'd': | 1134 | case 'd': |
941 | goto zoom_dso; | 1135 | goto zoom_dso; |
942 | case 't': | 1136 | case 't': |
@@ -969,6 +1163,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
969 | "E Expand all callchains\n" | 1163 | "E Expand all callchains\n" |
970 | "d Zoom into current DSO\n" | 1164 | "d Zoom into current DSO\n" |
971 | "t Zoom into current Thread\n" | 1165 | "t Zoom into current Thread\n" |
1166 | "P Print histograms to perf.hist.N\n" | ||
972 | "/ Filter symbol by name"); | 1167 | "/ Filter symbol by name"); |
973 | continue; | 1168 | continue; |
974 | case K_ENTER: | 1169 | case K_ENTER: |
@@ -1172,7 +1367,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser, | |||
1172 | struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); | 1367 | struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); |
1173 | bool current_entry = ui_browser__is_current_entry(browser, row); | 1368 | bool current_entry = ui_browser__is_current_entry(browser, row); |
1174 | unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; | 1369 | unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; |
1175 | const char *ev_name = event_name(evsel); | 1370 | const char *ev_name = perf_evsel__name(evsel); |
1176 | char bf[256], unit; | 1371 | char bf[256], unit; |
1177 | const char *warn = " "; | 1372 | const char *warn = " "; |
1178 | size_t printed; | 1373 | size_t printed; |
@@ -1240,7 +1435,7 @@ browse_hists: | |||
1240 | */ | 1435 | */ |
1241 | if (timer) | 1436 | if (timer) |
1242 | timer(arg); | 1437 | timer(arg); |
1243 | ev_name = event_name(pos); | 1438 | ev_name = perf_evsel__name(pos); |
1244 | key = perf_evsel__hists_browse(pos, nr_events, help, | 1439 | key = perf_evsel__hists_browse(pos, nr_events, help, |
1245 | ev_name, true, timer, | 1440 | ev_name, true, timer, |
1246 | arg, delay_secs); | 1441 | arg, delay_secs); |
@@ -1309,17 +1504,11 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | |||
1309 | ui_helpline__push("Press ESC to exit"); | 1504 | ui_helpline__push("Press ESC to exit"); |
1310 | 1505 | ||
1311 | list_for_each_entry(pos, &evlist->entries, node) { | 1506 | list_for_each_entry(pos, &evlist->entries, node) { |
1312 | const char *ev_name = event_name(pos); | 1507 | const char *ev_name = perf_evsel__name(pos); |
1313 | size_t line_len = strlen(ev_name) + 7; | 1508 | size_t line_len = strlen(ev_name) + 7; |
1314 | 1509 | ||
1315 | if (menu.b.width < line_len) | 1510 | if (menu.b.width < line_len) |
1316 | menu.b.width = line_len; | 1511 | menu.b.width = line_len; |
1317 | /* | ||
1318 | * Cache the evsel name, tracepoints have a _high_ cost per | ||
1319 | * event_name() call. | ||
1320 | */ | ||
1321 | if (pos->name == NULL) | ||
1322 | pos->name = strdup(ev_name); | ||
1323 | } | 1512 | } |
1324 | 1513 | ||
1325 | return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer, | 1514 | return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer, |
@@ -1330,11 +1519,10 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | |||
1330 | void(*timer)(void *arg), void *arg, | 1519 | void(*timer)(void *arg), void *arg, |
1331 | int delay_secs) | 1520 | int delay_secs) |
1332 | { | 1521 | { |
1333 | |||
1334 | if (evlist->nr_entries == 1) { | 1522 | if (evlist->nr_entries == 1) { |
1335 | struct perf_evsel *first = list_entry(evlist->entries.next, | 1523 | struct perf_evsel *first = list_entry(evlist->entries.next, |
1336 | struct perf_evsel, node); | 1524 | struct perf_evsel, node); |
1337 | const char *ev_name = event_name(first); | 1525 | const char *ev_name = perf_evsel__name(first); |
1338 | return perf_evsel__hists_browse(first, evlist->nr_entries, help, | 1526 | return perf_evsel__hists_browse(first, evlist->nr_entries, help, |
1339 | ev_name, false, timer, arg, | 1527 | ev_name, false, timer, arg, |
1340 | delay_secs); | 1528 | delay_secs); |
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index 0656c381a89c..ec12e0b4ded6 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c | |||
@@ -11,8 +11,8 @@ | |||
11 | 11 | ||
12 | static void perf_gtk__signal(int sig) | 12 | static void perf_gtk__signal(int sig) |
13 | { | 13 | { |
14 | perf_gtk__exit(false); | ||
14 | psignal(sig, "perf"); | 15 | psignal(sig, "perf"); |
15 | gtk_main_quit(); | ||
16 | } | 16 | } |
17 | 17 | ||
18 | static void perf_gtk__resize_window(GtkWidget *window) | 18 | static void perf_gtk__resize_window(GtkWidget *window) |
@@ -122,13 +122,59 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | |||
122 | gtk_container_add(GTK_CONTAINER(window), view); | 122 | gtk_container_add(GTK_CONTAINER(window), view); |
123 | } | 123 | } |
124 | 124 | ||
125 | #ifdef HAVE_GTK_INFO_BAR | ||
126 | static GtkWidget *perf_gtk__setup_info_bar(void) | ||
127 | { | ||
128 | GtkWidget *info_bar; | ||
129 | GtkWidget *label; | ||
130 | GtkWidget *content_area; | ||
131 | |||
132 | info_bar = gtk_info_bar_new(); | ||
133 | gtk_widget_set_no_show_all(info_bar, TRUE); | ||
134 | |||
135 | label = gtk_label_new(""); | ||
136 | gtk_widget_show(label); | ||
137 | |||
138 | content_area = gtk_info_bar_get_content_area(GTK_INFO_BAR(info_bar)); | ||
139 | gtk_container_add(GTK_CONTAINER(content_area), label); | ||
140 | |||
141 | gtk_info_bar_add_button(GTK_INFO_BAR(info_bar), GTK_STOCK_OK, | ||
142 | GTK_RESPONSE_OK); | ||
143 | g_signal_connect(info_bar, "response", | ||
144 | G_CALLBACK(gtk_widget_hide), NULL); | ||
145 | |||
146 | pgctx->info_bar = info_bar; | ||
147 | pgctx->message_label = label; | ||
148 | |||
149 | return info_bar; | ||
150 | } | ||
151 | #endif | ||
152 | |||
153 | static GtkWidget *perf_gtk__setup_statusbar(void) | ||
154 | { | ||
155 | GtkWidget *stbar; | ||
156 | unsigned ctxid; | ||
157 | |||
158 | stbar = gtk_statusbar_new(); | ||
159 | |||
160 | ctxid = gtk_statusbar_get_context_id(GTK_STATUSBAR(stbar), | ||
161 | "perf report"); | ||
162 | pgctx->statbar = stbar; | ||
163 | pgctx->statbar_ctx_id = ctxid; | ||
164 | |||
165 | return stbar; | ||
166 | } | ||
167 | |||
125 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | 168 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, |
126 | const char *help __used, | 169 | const char *help __used, |
127 | void (*timer) (void *arg)__used, | 170 | void (*timer) (void *arg)__used, |
128 | void *arg __used, int delay_secs __used) | 171 | void *arg __used, int delay_secs __used) |
129 | { | 172 | { |
130 | struct perf_evsel *pos; | 173 | struct perf_evsel *pos; |
174 | GtkWidget *vbox; | ||
131 | GtkWidget *notebook; | 175 | GtkWidget *notebook; |
176 | GtkWidget *info_bar; | ||
177 | GtkWidget *statbar; | ||
132 | GtkWidget *window; | 178 | GtkWidget *window; |
133 | 179 | ||
134 | signal(SIGSEGV, perf_gtk__signal); | 180 | signal(SIGSEGV, perf_gtk__signal); |
@@ -143,11 +189,17 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | |||
143 | 189 | ||
144 | g_signal_connect(window, "delete_event", gtk_main_quit, NULL); | 190 | g_signal_connect(window, "delete_event", gtk_main_quit, NULL); |
145 | 191 | ||
192 | pgctx = perf_gtk__activate_context(window); | ||
193 | if (!pgctx) | ||
194 | return -1; | ||
195 | |||
196 | vbox = gtk_vbox_new(FALSE, 0); | ||
197 | |||
146 | notebook = gtk_notebook_new(); | 198 | notebook = gtk_notebook_new(); |
147 | 199 | ||
148 | list_for_each_entry(pos, &evlist->entries, node) { | 200 | list_for_each_entry(pos, &evlist->entries, node) { |
149 | struct hists *hists = &pos->hists; | 201 | struct hists *hists = &pos->hists; |
150 | const char *evname = event_name(pos); | 202 | const char *evname = perf_evsel__name(pos); |
151 | GtkWidget *scrolled_window; | 203 | GtkWidget *scrolled_window; |
152 | GtkWidget *tab_label; | 204 | GtkWidget *tab_label; |
153 | 205 | ||
@@ -164,7 +216,16 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | |||
164 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); | 216 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); |
165 | } | 217 | } |
166 | 218 | ||
167 | gtk_container_add(GTK_CONTAINER(window), notebook); | 219 | gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); |
220 | |||
221 | info_bar = perf_gtk__setup_info_bar(); | ||
222 | if (info_bar) | ||
223 | gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0); | ||
224 | |||
225 | statbar = perf_gtk__setup_statusbar(); | ||
226 | gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); | ||
227 | |||
228 | gtk_container_add(GTK_CONTAINER(window), vbox); | ||
168 | 229 | ||
169 | gtk_widget_show_all(window); | 230 | gtk_widget_show_all(window); |
170 | 231 | ||
@@ -174,5 +235,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | |||
174 | 235 | ||
175 | gtk_main(); | 236 | gtk_main(); |
176 | 237 | ||
238 | perf_gtk__deactivate_context(&pgctx); | ||
239 | |||
177 | return 0; | 240 | return 0; |
178 | } | 241 | } |
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h index 75177ee04032..a4d0f2b4a2dc 100644 --- a/tools/perf/ui/gtk/gtk.h +++ b/tools/perf/ui/gtk/gtk.h | |||
@@ -1,8 +1,39 @@ | |||
1 | #ifndef _PERF_GTK_H_ | 1 | #ifndef _PERF_GTK_H_ |
2 | #define _PERF_GTK_H_ 1 | 2 | #define _PERF_GTK_H_ 1 |
3 | 3 | ||
4 | #include <stdbool.h> | ||
5 | |||
4 | #pragma GCC diagnostic ignored "-Wstrict-prototypes" | 6 | #pragma GCC diagnostic ignored "-Wstrict-prototypes" |
5 | #include <gtk/gtk.h> | 7 | #include <gtk/gtk.h> |
6 | #pragma GCC diagnostic error "-Wstrict-prototypes" | 8 | #pragma GCC diagnostic error "-Wstrict-prototypes" |
7 | 9 | ||
10 | |||
11 | struct perf_gtk_context { | ||
12 | GtkWidget *main_window; | ||
13 | |||
14 | #ifdef HAVE_GTK_INFO_BAR | ||
15 | GtkWidget *info_bar; | ||
16 | GtkWidget *message_label; | ||
17 | #endif | ||
18 | GtkWidget *statbar; | ||
19 | guint statbar_ctx_id; | ||
20 | }; | ||
21 | |||
22 | extern struct perf_gtk_context *pgctx; | ||
23 | |||
24 | static inline bool perf_gtk__is_active_context(struct perf_gtk_context *ctx) | ||
25 | { | ||
26 | return ctx && ctx->main_window; | ||
27 | } | ||
28 | |||
29 | struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window); | ||
30 | int perf_gtk__deactivate_context(struct perf_gtk_context **ctx); | ||
31 | |||
32 | #ifndef HAVE_GTK_INFO_BAR | ||
33 | static inline GtkWidget *perf_gtk__setup_info_bar(void) | ||
34 | { | ||
35 | return NULL; | ||
36 | } | ||
37 | #endif | ||
38 | |||
8 | #endif /* _PERF_GTK_H_ */ | 39 | #endif /* _PERF_GTK_H_ */ |
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c index 829529957766..92879ce61e2f 100644 --- a/tools/perf/ui/gtk/setup.c +++ b/tools/perf/ui/gtk/setup.c | |||
@@ -1,12 +1,17 @@ | |||
1 | #include "gtk.h" | 1 | #include "gtk.h" |
2 | #include "../../util/cache.h" | 2 | #include "../../util/cache.h" |
3 | #include "../../util/debug.h" | ||
4 | |||
5 | extern struct perf_error_ops perf_gtk_eops; | ||
3 | 6 | ||
4 | int perf_gtk__init(void) | 7 | int perf_gtk__init(void) |
5 | { | 8 | { |
9 | perf_error__register(&perf_gtk_eops); | ||
6 | return gtk_init_check(NULL, NULL) ? 0 : -1; | 10 | return gtk_init_check(NULL, NULL) ? 0 : -1; |
7 | } | 11 | } |
8 | 12 | ||
9 | void perf_gtk__exit(bool wait_for_ok __used) | 13 | void perf_gtk__exit(bool wait_for_ok __used) |
10 | { | 14 | { |
15 | perf_error__unregister(&perf_gtk_eops); | ||
11 | gtk_main_quit(); | 16 | gtk_main_quit(); |
12 | } | 17 | } |
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c new file mode 100644 index 000000000000..0ead373c0dfb --- /dev/null +++ b/tools/perf/ui/gtk/util.c | |||
@@ -0,0 +1,129 @@ | |||
1 | #include "../util.h" | ||
2 | #include "../../util/debug.h" | ||
3 | #include "gtk.h" | ||
4 | |||
5 | #include <string.h> | ||
6 | |||
7 | |||
8 | struct perf_gtk_context *pgctx; | ||
9 | |||
10 | struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window) | ||
11 | { | ||
12 | struct perf_gtk_context *ctx; | ||
13 | |||
14 | ctx = malloc(sizeof(*pgctx)); | ||
15 | if (ctx) | ||
16 | ctx->main_window = window; | ||
17 | |||
18 | return ctx; | ||
19 | } | ||
20 | |||
21 | int perf_gtk__deactivate_context(struct perf_gtk_context **ctx) | ||
22 | { | ||
23 | if (!perf_gtk__is_active_context(*ctx)) | ||
24 | return -1; | ||
25 | |||
26 | free(*ctx); | ||
27 | *ctx = NULL; | ||
28 | return 0; | ||
29 | } | ||
30 | |||
31 | static int perf_gtk__error(const char *format, va_list args) | ||
32 | { | ||
33 | char *msg; | ||
34 | GtkWidget *dialog; | ||
35 | |||
36 | if (!perf_gtk__is_active_context(pgctx) || | ||
37 | vasprintf(&msg, format, args) < 0) { | ||
38 | fprintf(stderr, "Error:\n"); | ||
39 | vfprintf(stderr, format, args); | ||
40 | fprintf(stderr, "\n"); | ||
41 | return -1; | ||
42 | } | ||
43 | |||
44 | dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(pgctx->main_window), | ||
45 | GTK_DIALOG_DESTROY_WITH_PARENT, | ||
46 | GTK_MESSAGE_ERROR, | ||
47 | GTK_BUTTONS_CLOSE, | ||
48 | "<b>Error</b>\n\n%s", msg); | ||
49 | gtk_dialog_run(GTK_DIALOG(dialog)); | ||
50 | |||
51 | gtk_widget_destroy(dialog); | ||
52 | free(msg); | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | #ifdef HAVE_GTK_INFO_BAR | ||
57 | static int perf_gtk__warning_info_bar(const char *format, va_list args) | ||
58 | { | ||
59 | char *msg; | ||
60 | |||
61 | if (!perf_gtk__is_active_context(pgctx) || | ||
62 | vasprintf(&msg, format, args) < 0) { | ||
63 | fprintf(stderr, "Warning:\n"); | ||
64 | vfprintf(stderr, format, args); | ||
65 | fprintf(stderr, "\n"); | ||
66 | return -1; | ||
67 | } | ||
68 | |||
69 | gtk_label_set_text(GTK_LABEL(pgctx->message_label), msg); | ||
70 | gtk_info_bar_set_message_type(GTK_INFO_BAR(pgctx->info_bar), | ||
71 | GTK_MESSAGE_WARNING); | ||
72 | gtk_widget_show(pgctx->info_bar); | ||
73 | |||
74 | free(msg); | ||
75 | return 0; | ||
76 | } | ||
77 | #else | ||
78 | static int perf_gtk__warning_statusbar(const char *format, va_list args) | ||
79 | { | ||
80 | char *msg, *p; | ||
81 | |||
82 | if (!perf_gtk__is_active_context(pgctx) || | ||
83 | vasprintf(&msg, format, args) < 0) { | ||
84 | fprintf(stderr, "Warning:\n"); | ||
85 | vfprintf(stderr, format, args); | ||
86 | fprintf(stderr, "\n"); | ||
87 | return -1; | ||
88 | } | ||
89 | |||
90 | gtk_statusbar_pop(GTK_STATUSBAR(pgctx->statbar), | ||
91 | pgctx->statbar_ctx_id); | ||
92 | |||
93 | /* Only first line can be displayed */ | ||
94 | p = strchr(msg, '\n'); | ||
95 | if (p) | ||
96 | *p = '\0'; | ||
97 | |||
98 | gtk_statusbar_push(GTK_STATUSBAR(pgctx->statbar), | ||
99 | pgctx->statbar_ctx_id, msg); | ||
100 | |||
101 | free(msg); | ||
102 | return 0; | ||
103 | } | ||
104 | #endif | ||
105 | |||
106 | struct perf_error_ops perf_gtk_eops = { | ||
107 | .error = perf_gtk__error, | ||
108 | #ifdef HAVE_GTK_INFO_BAR | ||
109 | .warning = perf_gtk__warning_info_bar, | ||
110 | #else | ||
111 | .warning = perf_gtk__warning_statusbar, | ||
112 | #endif | ||
113 | }; | ||
114 | |||
115 | /* | ||
116 | * FIXME: Functions below should be implemented properly. | ||
117 | * For now, just add stubs for NO_NEWT=1 build. | ||
118 | */ | ||
119 | #ifdef NO_NEWT_SUPPORT | ||
120 | int ui_helpline__show_help(const char *format __used, va_list ap __used) | ||
121 | { | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | void ui_progress__update(u64 curr __used, u64 total __used, | ||
126 | const char *title __used) | ||
127 | { | ||
128 | } | ||
129 | #endif | ||
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c index d33e943ac434..e813c1d17346 100644 --- a/tools/perf/ui/tui/setup.c +++ b/tools/perf/ui/tui/setup.c | |||
@@ -15,6 +15,8 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; | |||
15 | 15 | ||
16 | static volatile int ui__need_resize; | 16 | static volatile int ui__need_resize; |
17 | 17 | ||
18 | extern struct perf_error_ops perf_tui_eops; | ||
19 | |||
18 | void ui__refresh_dimensions(bool force) | 20 | void ui__refresh_dimensions(bool force) |
19 | { | 21 | { |
20 | if (force || ui__need_resize) { | 22 | if (force || ui__need_resize) { |
@@ -122,6 +124,8 @@ int ui__init(void) | |||
122 | signal(SIGINT, ui__signal); | 124 | signal(SIGINT, ui__signal); |
123 | signal(SIGQUIT, ui__signal); | 125 | signal(SIGQUIT, ui__signal); |
124 | signal(SIGTERM, ui__signal); | 126 | signal(SIGTERM, ui__signal); |
127 | |||
128 | perf_error__register(&perf_tui_eops); | ||
125 | out: | 129 | out: |
126 | return err; | 130 | return err; |
127 | } | 131 | } |
@@ -137,4 +141,6 @@ void ui__exit(bool wait_for_ok) | |||
137 | SLsmg_refresh(); | 141 | SLsmg_refresh(); |
138 | SLsmg_reset_smg(); | 142 | SLsmg_reset_smg(); |
139 | SLang_reset_tty(); | 143 | SLang_reset_tty(); |
144 | |||
145 | perf_error__unregister(&perf_tui_eops); | ||
140 | } | 146 | } |
diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c new file mode 100644 index 000000000000..092902e30cee --- /dev/null +++ b/tools/perf/ui/tui/util.c | |||
@@ -0,0 +1,243 @@ | |||
1 | #include "../../util/util.h" | ||
2 | #include <signal.h> | ||
3 | #include <stdbool.h> | ||
4 | #include <string.h> | ||
5 | #include <sys/ttydefaults.h> | ||
6 | |||
7 | #include "../../util/cache.h" | ||
8 | #include "../../util/debug.h" | ||
9 | #include "../browser.h" | ||
10 | #include "../keysyms.h" | ||
11 | #include "../helpline.h" | ||
12 | #include "../ui.h" | ||
13 | #include "../util.h" | ||
14 | #include "../libslang.h" | ||
15 | |||
16 | static void ui_browser__argv_write(struct ui_browser *browser, | ||
17 | void *entry, int row) | ||
18 | { | ||
19 | char **arg = entry; | ||
20 | bool current_entry = ui_browser__is_current_entry(browser, row); | ||
21 | |||
22 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : | ||
23 | HE_COLORSET_NORMAL); | ||
24 | slsmg_write_nstring(*arg, browser->width); | ||
25 | } | ||
26 | |||
27 | static int popup_menu__run(struct ui_browser *menu) | ||
28 | { | ||
29 | int key; | ||
30 | |||
31 | if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0) | ||
32 | return -1; | ||
33 | |||
34 | while (1) { | ||
35 | key = ui_browser__run(menu, 0); | ||
36 | |||
37 | switch (key) { | ||
38 | case K_RIGHT: | ||
39 | case K_ENTER: | ||
40 | key = menu->index; | ||
41 | break; | ||
42 | case K_LEFT: | ||
43 | case K_ESC: | ||
44 | case 'q': | ||
45 | case CTRL('c'): | ||
46 | key = -1; | ||
47 | break; | ||
48 | default: | ||
49 | continue; | ||
50 | } | ||
51 | |||
52 | break; | ||
53 | } | ||
54 | |||
55 | ui_browser__hide(menu); | ||
56 | return key; | ||
57 | } | ||
58 | |||
59 | int ui__popup_menu(int argc, char * const argv[]) | ||
60 | { | ||
61 | struct ui_browser menu = { | ||
62 | .entries = (void *)argv, | ||
63 | .refresh = ui_browser__argv_refresh, | ||
64 | .seek = ui_browser__argv_seek, | ||
65 | .write = ui_browser__argv_write, | ||
66 | .nr_entries = argc, | ||
67 | }; | ||
68 | |||
69 | return popup_menu__run(&menu); | ||
70 | } | ||
71 | |||
72 | int ui_browser__input_window(const char *title, const char *text, char *input, | ||
73 | const char *exit_msg, int delay_secs) | ||
74 | { | ||
75 | int x, y, len, key; | ||
76 | int max_len = 60, nr_lines = 0; | ||
77 | static char buf[50]; | ||
78 | const char *t; | ||
79 | |||
80 | t = text; | ||
81 | while (1) { | ||
82 | const char *sep = strchr(t, '\n'); | ||
83 | |||
84 | if (sep == NULL) | ||
85 | sep = strchr(t, '\0'); | ||
86 | len = sep - t; | ||
87 | if (max_len < len) | ||
88 | max_len = len; | ||
89 | ++nr_lines; | ||
90 | if (*sep == '\0') | ||
91 | break; | ||
92 | t = sep + 1; | ||
93 | } | ||
94 | |||
95 | max_len += 2; | ||
96 | nr_lines += 8; | ||
97 | y = SLtt_Screen_Rows / 2 - nr_lines / 2; | ||
98 | x = SLtt_Screen_Cols / 2 - max_len / 2; | ||
99 | |||
100 | SLsmg_set_color(0); | ||
101 | SLsmg_draw_box(y, x++, nr_lines, max_len); | ||
102 | if (title) { | ||
103 | SLsmg_gotorc(y, x + 1); | ||
104 | SLsmg_write_string((char *)title); | ||
105 | } | ||
106 | SLsmg_gotorc(++y, x); | ||
107 | nr_lines -= 7; | ||
108 | max_len -= 2; | ||
109 | SLsmg_write_wrapped_string((unsigned char *)text, y, x, | ||
110 | nr_lines, max_len, 1); | ||
111 | y += nr_lines; | ||
112 | len = 5; | ||
113 | while (len--) { | ||
114 | SLsmg_gotorc(y + len - 1, x); | ||
115 | SLsmg_write_nstring((char *)" ", max_len); | ||
116 | } | ||
117 | SLsmg_draw_box(y++, x + 1, 3, max_len - 2); | ||
118 | |||
119 | SLsmg_gotorc(y + 3, x); | ||
120 | SLsmg_write_nstring((char *)exit_msg, max_len); | ||
121 | SLsmg_refresh(); | ||
122 | |||
123 | x += 2; | ||
124 | len = 0; | ||
125 | key = ui__getch(delay_secs); | ||
126 | while (key != K_TIMER && key != K_ENTER && key != K_ESC) { | ||
127 | if (key == K_BKSPC) { | ||
128 | if (len == 0) | ||
129 | goto next_key; | ||
130 | SLsmg_gotorc(y, x + --len); | ||
131 | SLsmg_write_char(' '); | ||
132 | } else { | ||
133 | buf[len] = key; | ||
134 | SLsmg_gotorc(y, x + len++); | ||
135 | SLsmg_write_char(key); | ||
136 | } | ||
137 | SLsmg_refresh(); | ||
138 | |||
139 | /* XXX more graceful overflow handling needed */ | ||
140 | if (len == sizeof(buf) - 1) { | ||
141 | ui_helpline__push("maximum size of symbol name reached!"); | ||
142 | key = K_ENTER; | ||
143 | break; | ||
144 | } | ||
145 | next_key: | ||
146 | key = ui__getch(delay_secs); | ||
147 | } | ||
148 | |||
149 | buf[len] = '\0'; | ||
150 | strncpy(input, buf, len+1); | ||
151 | return key; | ||
152 | } | ||
153 | |||
154 | int ui__question_window(const char *title, const char *text, | ||
155 | const char *exit_msg, int delay_secs) | ||
156 | { | ||
157 | int x, y; | ||
158 | int max_len = 0, nr_lines = 0; | ||
159 | const char *t; | ||
160 | |||
161 | t = text; | ||
162 | while (1) { | ||
163 | const char *sep = strchr(t, '\n'); | ||
164 | int len; | ||
165 | |||
166 | if (sep == NULL) | ||
167 | sep = strchr(t, '\0'); | ||
168 | len = sep - t; | ||
169 | if (max_len < len) | ||
170 | max_len = len; | ||
171 | ++nr_lines; | ||
172 | if (*sep == '\0') | ||
173 | break; | ||
174 | t = sep + 1; | ||
175 | } | ||
176 | |||
177 | max_len += 2; | ||
178 | nr_lines += 4; | ||
179 | y = SLtt_Screen_Rows / 2 - nr_lines / 2, | ||
180 | x = SLtt_Screen_Cols / 2 - max_len / 2; | ||
181 | |||
182 | SLsmg_set_color(0); | ||
183 | SLsmg_draw_box(y, x++, nr_lines, max_len); | ||
184 | if (title) { | ||
185 | SLsmg_gotorc(y, x + 1); | ||
186 | SLsmg_write_string((char *)title); | ||
187 | } | ||
188 | SLsmg_gotorc(++y, x); | ||
189 | nr_lines -= 2; | ||
190 | max_len -= 2; | ||
191 | SLsmg_write_wrapped_string((unsigned char *)text, y, x, | ||
192 | nr_lines, max_len, 1); | ||
193 | SLsmg_gotorc(y + nr_lines - 2, x); | ||
194 | SLsmg_write_nstring((char *)" ", max_len); | ||
195 | SLsmg_gotorc(y + nr_lines - 1, x); | ||
196 | SLsmg_write_nstring((char *)exit_msg, max_len); | ||
197 | SLsmg_refresh(); | ||
198 | return ui__getch(delay_secs); | ||
199 | } | ||
200 | |||
201 | int ui__help_window(const char *text) | ||
202 | { | ||
203 | return ui__question_window("Help", text, "Press any key...", 0); | ||
204 | } | ||
205 | |||
206 | int ui__dialog_yesno(const char *msg) | ||
207 | { | ||
208 | return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0); | ||
209 | } | ||
210 | |||
211 | static int __ui__warning(const char *title, const char *format, va_list args) | ||
212 | { | ||
213 | char *s; | ||
214 | |||
215 | if (vasprintf(&s, format, args) > 0) { | ||
216 | int key; | ||
217 | |||
218 | pthread_mutex_lock(&ui__lock); | ||
219 | key = ui__question_window(title, s, "Press any key...", 0); | ||
220 | pthread_mutex_unlock(&ui__lock); | ||
221 | free(s); | ||
222 | return key; | ||
223 | } | ||
224 | |||
225 | fprintf(stderr, "%s\n", title); | ||
226 | vfprintf(stderr, format, args); | ||
227 | return K_ESC; | ||
228 | } | ||
229 | |||
230 | static int perf_tui__error(const char *format, va_list args) | ||
231 | { | ||
232 | return __ui__warning("Error:", format, args); | ||
233 | } | ||
234 | |||
235 | static int perf_tui__warning(const char *format, va_list args) | ||
236 | { | ||
237 | return __ui__warning("Warning:", format, args); | ||
238 | } | ||
239 | |||
240 | struct perf_error_ops perf_tui_eops = { | ||
241 | .error = perf_tui__error, | ||
242 | .warning = perf_tui__warning, | ||
243 | }; | ||
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c index ad4374a16bb0..4f989774c8c6 100644 --- a/tools/perf/ui/util.c +++ b/tools/perf/ui/util.c | |||
@@ -1,250 +1,85 @@ | |||
1 | #include "../util.h" | ||
2 | #include <signal.h> | ||
3 | #include <stdbool.h> | ||
4 | #include <string.h> | ||
5 | #include <sys/ttydefaults.h> | ||
6 | |||
7 | #include "../cache.h" | ||
8 | #include "../debug.h" | ||
9 | #include "browser.h" | ||
10 | #include "keysyms.h" | ||
11 | #include "helpline.h" | ||
12 | #include "ui.h" | ||
13 | #include "util.h" | 1 | #include "util.h" |
14 | #include "libslang.h" | 2 | #include "../debug.h" |
15 | |||
16 | static void ui_browser__argv_write(struct ui_browser *browser, | ||
17 | void *entry, int row) | ||
18 | { | ||
19 | char **arg = entry; | ||
20 | bool current_entry = ui_browser__is_current_entry(browser, row); | ||
21 | |||
22 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : | ||
23 | HE_COLORSET_NORMAL); | ||
24 | slsmg_write_nstring(*arg, browser->width); | ||
25 | } | ||
26 | |||
27 | static int popup_menu__run(struct ui_browser *menu) | ||
28 | { | ||
29 | int key; | ||
30 | |||
31 | if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0) | ||
32 | return -1; | ||
33 | 3 | ||
34 | while (1) { | ||
35 | key = ui_browser__run(menu, 0); | ||
36 | |||
37 | switch (key) { | ||
38 | case K_RIGHT: | ||
39 | case K_ENTER: | ||
40 | key = menu->index; | ||
41 | break; | ||
42 | case K_LEFT: | ||
43 | case K_ESC: | ||
44 | case 'q': | ||
45 | case CTRL('c'): | ||
46 | key = -1; | ||
47 | break; | ||
48 | default: | ||
49 | continue; | ||
50 | } | ||
51 | |||
52 | break; | ||
53 | } | ||
54 | |||
55 | ui_browser__hide(menu); | ||
56 | return key; | ||
57 | } | ||
58 | 4 | ||
59 | int ui__popup_menu(int argc, char * const argv[]) | 5 | /* |
6 | * Default error logging functions | ||
7 | */ | ||
8 | static int perf_stdio__error(const char *format, va_list args) | ||
60 | { | 9 | { |
61 | struct ui_browser menu = { | 10 | fprintf(stderr, "Error:\n"); |
62 | .entries = (void *)argv, | 11 | vfprintf(stderr, format, args); |
63 | .refresh = ui_browser__argv_refresh, | 12 | return 0; |
64 | .seek = ui_browser__argv_seek, | ||
65 | .write = ui_browser__argv_write, | ||
66 | .nr_entries = argc, | ||
67 | }; | ||
68 | |||
69 | return popup_menu__run(&menu); | ||
70 | } | 13 | } |
71 | 14 | ||
72 | int ui_browser__input_window(const char *title, const char *text, char *input, | 15 | static int perf_stdio__warning(const char *format, va_list args) |
73 | const char *exit_msg, int delay_secs) | ||
74 | { | 16 | { |
75 | int x, y, len, key; | 17 | fprintf(stderr, "Warning:\n"); |
76 | int max_len = 60, nr_lines = 0; | 18 | vfprintf(stderr, format, args); |
77 | static char buf[50]; | 19 | return 0; |
78 | const char *t; | ||
79 | |||
80 | t = text; | ||
81 | while (1) { | ||
82 | const char *sep = strchr(t, '\n'); | ||
83 | |||
84 | if (sep == NULL) | ||
85 | sep = strchr(t, '\0'); | ||
86 | len = sep - t; | ||
87 | if (max_len < len) | ||
88 | max_len = len; | ||
89 | ++nr_lines; | ||
90 | if (*sep == '\0') | ||
91 | break; | ||
92 | t = sep + 1; | ||
93 | } | ||
94 | |||
95 | max_len += 2; | ||
96 | nr_lines += 8; | ||
97 | y = SLtt_Screen_Rows / 2 - nr_lines / 2; | ||
98 | x = SLtt_Screen_Cols / 2 - max_len / 2; | ||
99 | |||
100 | SLsmg_set_color(0); | ||
101 | SLsmg_draw_box(y, x++, nr_lines, max_len); | ||
102 | if (title) { | ||
103 | SLsmg_gotorc(y, x + 1); | ||
104 | SLsmg_write_string((char *)title); | ||
105 | } | ||
106 | SLsmg_gotorc(++y, x); | ||
107 | nr_lines -= 7; | ||
108 | max_len -= 2; | ||
109 | SLsmg_write_wrapped_string((unsigned char *)text, y, x, | ||
110 | nr_lines, max_len, 1); | ||
111 | y += nr_lines; | ||
112 | len = 5; | ||
113 | while (len--) { | ||
114 | SLsmg_gotorc(y + len - 1, x); | ||
115 | SLsmg_write_nstring((char *)" ", max_len); | ||
116 | } | ||
117 | SLsmg_draw_box(y++, x + 1, 3, max_len - 2); | ||
118 | |||
119 | SLsmg_gotorc(y + 3, x); | ||
120 | SLsmg_write_nstring((char *)exit_msg, max_len); | ||
121 | SLsmg_refresh(); | ||
122 | |||
123 | x += 2; | ||
124 | len = 0; | ||
125 | key = ui__getch(delay_secs); | ||
126 | while (key != K_TIMER && key != K_ENTER && key != K_ESC) { | ||
127 | if (key == K_BKSPC) { | ||
128 | if (len == 0) | ||
129 | goto next_key; | ||
130 | SLsmg_gotorc(y, x + --len); | ||
131 | SLsmg_write_char(' '); | ||
132 | } else { | ||
133 | buf[len] = key; | ||
134 | SLsmg_gotorc(y, x + len++); | ||
135 | SLsmg_write_char(key); | ||
136 | } | ||
137 | SLsmg_refresh(); | ||
138 | |||
139 | /* XXX more graceful overflow handling needed */ | ||
140 | if (len == sizeof(buf) - 1) { | ||
141 | ui_helpline__push("maximum size of symbol name reached!"); | ||
142 | key = K_ENTER; | ||
143 | break; | ||
144 | } | ||
145 | next_key: | ||
146 | key = ui__getch(delay_secs); | ||
147 | } | ||
148 | |||
149 | buf[len] = '\0'; | ||
150 | strncpy(input, buf, len+1); | ||
151 | return key; | ||
152 | } | 20 | } |
153 | 21 | ||
154 | int ui__question_window(const char *title, const char *text, | 22 | static struct perf_error_ops default_eops = |
155 | const char *exit_msg, int delay_secs) | ||
156 | { | 23 | { |
157 | int x, y; | 24 | .error = perf_stdio__error, |
158 | int max_len = 0, nr_lines = 0; | 25 | .warning = perf_stdio__warning, |
159 | const char *t; | 26 | }; |
160 | |||
161 | t = text; | ||
162 | while (1) { | ||
163 | const char *sep = strchr(t, '\n'); | ||
164 | int len; | ||
165 | |||
166 | if (sep == NULL) | ||
167 | sep = strchr(t, '\0'); | ||
168 | len = sep - t; | ||
169 | if (max_len < len) | ||
170 | max_len = len; | ||
171 | ++nr_lines; | ||
172 | if (*sep == '\0') | ||
173 | break; | ||
174 | t = sep + 1; | ||
175 | } | ||
176 | |||
177 | max_len += 2; | ||
178 | nr_lines += 4; | ||
179 | y = SLtt_Screen_Rows / 2 - nr_lines / 2, | ||
180 | x = SLtt_Screen_Cols / 2 - max_len / 2; | ||
181 | |||
182 | SLsmg_set_color(0); | ||
183 | SLsmg_draw_box(y, x++, nr_lines, max_len); | ||
184 | if (title) { | ||
185 | SLsmg_gotorc(y, x + 1); | ||
186 | SLsmg_write_string((char *)title); | ||
187 | } | ||
188 | SLsmg_gotorc(++y, x); | ||
189 | nr_lines -= 2; | ||
190 | max_len -= 2; | ||
191 | SLsmg_write_wrapped_string((unsigned char *)text, y, x, | ||
192 | nr_lines, max_len, 1); | ||
193 | SLsmg_gotorc(y + nr_lines - 2, x); | ||
194 | SLsmg_write_nstring((char *)" ", max_len); | ||
195 | SLsmg_gotorc(y + nr_lines - 1, x); | ||
196 | SLsmg_write_nstring((char *)exit_msg, max_len); | ||
197 | SLsmg_refresh(); | ||
198 | return ui__getch(delay_secs); | ||
199 | } | ||
200 | 27 | ||
201 | int ui__help_window(const char *text) | 28 | static struct perf_error_ops *perf_eops = &default_eops; |
202 | { | ||
203 | return ui__question_window("Help", text, "Press any key...", 0); | ||
204 | } | ||
205 | 29 | ||
206 | int ui__dialog_yesno(const char *msg) | ||
207 | { | ||
208 | return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0); | ||
209 | } | ||
210 | 30 | ||
211 | int __ui__warning(const char *title, const char *format, va_list args) | 31 | int ui__error(const char *format, ...) |
212 | { | 32 | { |
213 | char *s; | 33 | int ret; |
214 | 34 | va_list args; | |
215 | if (use_browser > 0 && vasprintf(&s, format, args) > 0) { | ||
216 | int key; | ||
217 | 35 | ||
218 | pthread_mutex_lock(&ui__lock); | 36 | va_start(args, format); |
219 | key = ui__question_window(title, s, "Press any key...", 0); | 37 | ret = perf_eops->error(format, args); |
220 | pthread_mutex_unlock(&ui__lock); | 38 | va_end(args); |
221 | free(s); | ||
222 | return key; | ||
223 | } | ||
224 | 39 | ||
225 | fprintf(stderr, "%s:\n", title); | 40 | return ret; |
226 | vfprintf(stderr, format, args); | ||
227 | return K_ESC; | ||
228 | } | 41 | } |
229 | 42 | ||
230 | int ui__warning(const char *format, ...) | 43 | int ui__warning(const char *format, ...) |
231 | { | 44 | { |
232 | int key; | 45 | int ret; |
233 | va_list args; | 46 | va_list args; |
234 | 47 | ||
235 | va_start(args, format); | 48 | va_start(args, format); |
236 | key = __ui__warning("Warning", format, args); | 49 | ret = perf_eops->warning(format, args); |
237 | va_end(args); | 50 | va_end(args); |
238 | return key; | 51 | |
52 | return ret; | ||
239 | } | 53 | } |
240 | 54 | ||
241 | int ui__error(const char *format, ...) | 55 | |
56 | /** | ||
57 | * perf_error__register - Register error logging functions | ||
58 | * @eops: The pointer to error logging function struct | ||
59 | * | ||
60 | * Register UI-specific error logging functions. Before calling this, | ||
61 | * other logging functions should be unregistered, if any. | ||
62 | */ | ||
63 | int perf_error__register(struct perf_error_ops *eops) | ||
242 | { | 64 | { |
243 | int key; | 65 | if (perf_eops != &default_eops) |
244 | va_list args; | 66 | return -1; |
245 | 67 | ||
246 | va_start(args, format); | 68 | perf_eops = eops; |
247 | key = __ui__warning("Error", format, args); | 69 | return 0; |
248 | va_end(args); | 70 | } |
249 | return key; | 71 | |
72 | /** | ||
73 | * perf_error__unregister - Unregister error logging functions | ||
74 | * @eops: The pointer to error logging function struct | ||
75 | * | ||
76 | * Unregister already registered error logging functions. | ||
77 | */ | ||
78 | int perf_error__unregister(struct perf_error_ops *eops) | ||
79 | { | ||
80 | if (perf_eops != eops) | ||
81 | return -1; | ||
82 | |||
83 | perf_eops = &default_eops; | ||
84 | return 0; | ||
250 | } | 85 | } |
diff --git a/tools/perf/ui/util.h b/tools/perf/ui/util.h index 2d1738bd71c8..361f08c52d37 100644 --- a/tools/perf/ui/util.h +++ b/tools/perf/ui/util.h | |||
@@ -9,6 +9,13 @@ int ui__help_window(const char *text); | |||
9 | int ui__dialog_yesno(const char *msg); | 9 | int ui__dialog_yesno(const char *msg); |
10 | int ui__question_window(const char *title, const char *text, | 10 | int ui__question_window(const char *title, const char *text, |
11 | const char *exit_msg, int delay_secs); | 11 | const char *exit_msg, int delay_secs); |
12 | int __ui__warning(const char *title, const char *format, va_list args); | 12 | |
13 | struct perf_error_ops { | ||
14 | int (*error)(const char *format, va_list args); | ||
15 | int (*warning)(const char *format, va_list args); | ||
16 | }; | ||
17 | |||
18 | int perf_error__register(struct perf_error_ops *eops); | ||
19 | int perf_error__unregister(struct perf_error_ops *eops); | ||
13 | 20 | ||
14 | #endif /* _PERF_UI_UTIL_H_ */ | 21 | #endif /* _PERF_UI_UTIL_H_ */ |
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index efb1fce259a4..4dfe0bb3c322 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -47,7 +47,7 @@ int dump_printf(const char *fmt, ...) | |||
47 | return ret; | 47 | return ret; |
48 | } | 48 | } |
49 | 49 | ||
50 | #ifdef NO_NEWT_SUPPORT | 50 | #if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT) |
51 | int ui__warning(const char *format, ...) | 51 | int ui__warning(const char *format, ...) |
52 | { | 52 | { |
53 | va_list args; | 53 | va_list args; |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 6bebe7f0a20c..015c91dbc096 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -12,8 +12,9 @@ int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); | |||
12 | void trace_event(union perf_event *event); | 12 | void trace_event(union perf_event *event); |
13 | 13 | ||
14 | struct ui_progress; | 14 | struct ui_progress; |
15 | struct perf_error_ops; | ||
15 | 16 | ||
16 | #ifdef NO_NEWT_SUPPORT | 17 | #if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT) |
17 | static inline int ui_helpline__show_help(const char *format __used, va_list ap __used) | 18 | static inline int ui_helpline__show_help(const char *format __used, va_list ap __used) |
18 | { | 19 | { |
19 | return 0; | 20 | return 0; |
@@ -23,12 +24,28 @@ static inline void ui_progress__update(u64 curr __used, u64 total __used, | |||
23 | const char *title __used) {} | 24 | const char *title __used) {} |
24 | 25 | ||
25 | #define ui__error(format, arg...) ui__warning(format, ##arg) | 26 | #define ui__error(format, arg...) ui__warning(format, ##arg) |
26 | #else | 27 | |
28 | static inline int | ||
29 | perf_error__register(struct perf_error_ops *eops __used) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | static inline int | ||
35 | perf_error__unregister(struct perf_error_ops *eops __used) | ||
36 | { | ||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | #else /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */ | ||
41 | |||
27 | extern char ui_helpline__last_msg[]; | 42 | extern char ui_helpline__last_msg[]; |
28 | int ui_helpline__show_help(const char *format, va_list ap); | 43 | int ui_helpline__show_help(const char *format, va_list ap); |
29 | #include "../ui/progress.h" | 44 | #include "../ui/progress.h" |
30 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | 45 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); |
31 | #endif | 46 | #include "../ui/util.h" |
47 | |||
48 | #endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */ | ||
32 | 49 | ||
33 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 50 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
34 | int ui__error_paranoid(void); | 51 | int ui__error_paranoid(void); |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 7400fb3fc50c..f74e9560350e 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -224,8 +224,8 @@ out_free_attrs: | |||
224 | return err; | 224 | return err; |
225 | } | 225 | } |
226 | 226 | ||
227 | static struct perf_evsel * | 227 | struct perf_evsel * |
228 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) | 228 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) |
229 | { | 229 | { |
230 | struct perf_evsel *evsel; | 230 | struct perf_evsel *evsel; |
231 | 231 | ||
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 989bee9624c2..40d4d3cdced0 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -73,6 +73,9 @@ int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, | |||
73 | #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ | 73 | #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ |
74 | perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) | 74 | perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) |
75 | 75 | ||
76 | struct perf_evsel * | ||
77 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); | ||
78 | |||
76 | void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, | 79 | void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, |
77 | int cpu, int thread, u64 id); | 80 | int cpu, int thread, u64 id); |
78 | 81 | ||
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 9f6cebd798ee..e81771364867 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include "cpumap.h" | 15 | #include "cpumap.h" |
16 | #include "thread_map.h" | 16 | #include "thread_map.h" |
17 | #include "target.h" | 17 | #include "target.h" |
18 | #include "../../include/linux/perf_event.h" | 18 | #include "../../../include/linux/hw_breakpoint.h" |
19 | 19 | ||
20 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 20 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
21 | #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) | 21 | #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) |
@@ -78,7 +78,7 @@ static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = { | |||
78 | "ref-cycles", | 78 | "ref-cycles", |
79 | }; | 79 | }; |
80 | 80 | ||
81 | const char *__perf_evsel__hw_name(u64 config) | 81 | static const char *__perf_evsel__hw_name(u64 config) |
82 | { | 82 | { |
83 | if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config]) | 83 | if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config]) |
84 | return perf_evsel__hw_names[config]; | 84 | return perf_evsel__hw_names[config]; |
@@ -86,16 +86,15 @@ const char *__perf_evsel__hw_name(u64 config) | |||
86 | return "unknown-hardware"; | 86 | return "unknown-hardware"; |
87 | } | 87 | } |
88 | 88 | ||
89 | static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) | 89 | static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size) |
90 | { | 90 | { |
91 | int colon = 0; | 91 | int colon = 0, r = 0; |
92 | struct perf_event_attr *attr = &evsel->attr; | 92 | struct perf_event_attr *attr = &evsel->attr; |
93 | int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(attr->config)); | ||
94 | bool exclude_guest_default = false; | 93 | bool exclude_guest_default = false; |
95 | 94 | ||
96 | #define MOD_PRINT(context, mod) do { \ | 95 | #define MOD_PRINT(context, mod) do { \ |
97 | if (!attr->exclude_##context) { \ | 96 | if (!attr->exclude_##context) { \ |
98 | if (!colon) colon = r++; \ | 97 | if (!colon) colon = ++r; \ |
99 | r += scnprintf(bf + r, size - r, "%c", mod); \ | 98 | r += scnprintf(bf + r, size - r, "%c", mod); \ |
100 | } } while(0) | 99 | } } while(0) |
101 | 100 | ||
@@ -108,7 +107,7 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) | |||
108 | 107 | ||
109 | if (attr->precise_ip) { | 108 | if (attr->precise_ip) { |
110 | if (!colon) | 109 | if (!colon) |
111 | colon = r++; | 110 | colon = ++r; |
112 | r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp"); | 111 | r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp"); |
113 | exclude_guest_default = true; | 112 | exclude_guest_default = true; |
114 | } | 113 | } |
@@ -119,39 +118,211 @@ static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) | |||
119 | } | 118 | } |
120 | #undef MOD_PRINT | 119 | #undef MOD_PRINT |
121 | if (colon) | 120 | if (colon) |
122 | bf[colon] = ':'; | 121 | bf[colon - 1] = ':'; |
123 | return r; | 122 | return r; |
124 | } | 123 | } |
125 | 124 | ||
126 | int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size) | 125 | static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) |
126 | { | ||
127 | int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config)); | ||
128 | return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); | ||
129 | } | ||
130 | |||
131 | static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = { | ||
132 | "cpu-clock", | ||
133 | "task-clock", | ||
134 | "page-faults", | ||
135 | "context-switches", | ||
136 | "CPU-migrations", | ||
137 | "minor-faults", | ||
138 | "major-faults", | ||
139 | "alignment-faults", | ||
140 | "emulation-faults", | ||
141 | }; | ||
142 | |||
143 | static const char *__perf_evsel__sw_name(u64 config) | ||
127 | { | 144 | { |
128 | int ret; | 145 | if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config]) |
146 | return perf_evsel__sw_names[config]; | ||
147 | return "unknown-software"; | ||
148 | } | ||
149 | |||
150 | static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size) | ||
151 | { | ||
152 | int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config)); | ||
153 | return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); | ||
154 | } | ||
155 | |||
156 | static int __perf_evsel__bp_name(char *bf, size_t size, u64 addr, u64 type) | ||
157 | { | ||
158 | int r; | ||
159 | |||
160 | r = scnprintf(bf, size, "mem:0x%" PRIx64 ":", addr); | ||
161 | |||
162 | if (type & HW_BREAKPOINT_R) | ||
163 | r += scnprintf(bf + r, size - r, "r"); | ||
164 | |||
165 | if (type & HW_BREAKPOINT_W) | ||
166 | r += scnprintf(bf + r, size - r, "w"); | ||
167 | |||
168 | if (type & HW_BREAKPOINT_X) | ||
169 | r += scnprintf(bf + r, size - r, "x"); | ||
170 | |||
171 | return r; | ||
172 | } | ||
173 | |||
174 | static int perf_evsel__bp_name(struct perf_evsel *evsel, char *bf, size_t size) | ||
175 | { | ||
176 | struct perf_event_attr *attr = &evsel->attr; | ||
177 | int r = __perf_evsel__bp_name(bf, size, attr->bp_addr, attr->bp_type); | ||
178 | return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); | ||
179 | } | ||
180 | |||
181 | const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] | ||
182 | [PERF_EVSEL__MAX_ALIASES] = { | ||
183 | { "L1-dcache", "l1-d", "l1d", "L1-data", }, | ||
184 | { "L1-icache", "l1-i", "l1i", "L1-instruction", }, | ||
185 | { "LLC", "L2", }, | ||
186 | { "dTLB", "d-tlb", "Data-TLB", }, | ||
187 | { "iTLB", "i-tlb", "Instruction-TLB", }, | ||
188 | { "branch", "branches", "bpu", "btb", "bpc", }, | ||
189 | { "node", }, | ||
190 | }; | ||
191 | |||
192 | const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX] | ||
193 | [PERF_EVSEL__MAX_ALIASES] = { | ||
194 | { "load", "loads", "read", }, | ||
195 | { "store", "stores", "write", }, | ||
196 | { "prefetch", "prefetches", "speculative-read", "speculative-load", }, | ||
197 | }; | ||
198 | |||
199 | const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] | ||
200 | [PERF_EVSEL__MAX_ALIASES] = { | ||
201 | { "refs", "Reference", "ops", "access", }, | ||
202 | { "misses", "miss", }, | ||
203 | }; | ||
204 | |||
205 | #define C(x) PERF_COUNT_HW_CACHE_##x | ||
206 | #define CACHE_READ (1 << C(OP_READ)) | ||
207 | #define CACHE_WRITE (1 << C(OP_WRITE)) | ||
208 | #define CACHE_PREFETCH (1 << C(OP_PREFETCH)) | ||
209 | #define COP(x) (1 << x) | ||
210 | |||
211 | /* | ||
212 | * cache operartion stat | ||
213 | * L1I : Read and prefetch only | ||
214 | * ITLB and BPU : Read-only | ||
215 | */ | ||
216 | static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = { | ||
217 | [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | ||
218 | [C(L1I)] = (CACHE_READ | CACHE_PREFETCH), | ||
219 | [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | ||
220 | [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | ||
221 | [C(ITLB)] = (CACHE_READ), | ||
222 | [C(BPU)] = (CACHE_READ), | ||
223 | [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | ||
224 | }; | ||
225 | |||
226 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op) | ||
227 | { | ||
228 | if (perf_evsel__hw_cache_stat[type] & COP(op)) | ||
229 | return true; /* valid */ | ||
230 | else | ||
231 | return false; /* invalid */ | ||
232 | } | ||
233 | |||
234 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, | ||
235 | char *bf, size_t size) | ||
236 | { | ||
237 | if (result) { | ||
238 | return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0], | ||
239 | perf_evsel__hw_cache_op[op][0], | ||
240 | perf_evsel__hw_cache_result[result][0]); | ||
241 | } | ||
242 | |||
243 | return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0], | ||
244 | perf_evsel__hw_cache_op[op][1]); | ||
245 | } | ||
246 | |||
247 | static int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size) | ||
248 | { | ||
249 | u8 op, result, type = (config >> 0) & 0xff; | ||
250 | const char *err = "unknown-ext-hardware-cache-type"; | ||
251 | |||
252 | if (type > PERF_COUNT_HW_CACHE_MAX) | ||
253 | goto out_err; | ||
254 | |||
255 | op = (config >> 8) & 0xff; | ||
256 | err = "unknown-ext-hardware-cache-op"; | ||
257 | if (op > PERF_COUNT_HW_CACHE_OP_MAX) | ||
258 | goto out_err; | ||
259 | |||
260 | result = (config >> 16) & 0xff; | ||
261 | err = "unknown-ext-hardware-cache-result"; | ||
262 | if (result > PERF_COUNT_HW_CACHE_RESULT_MAX) | ||
263 | goto out_err; | ||
264 | |||
265 | err = "invalid-cache"; | ||
266 | if (!perf_evsel__is_cache_op_valid(type, op)) | ||
267 | goto out_err; | ||
268 | |||
269 | return __perf_evsel__hw_cache_type_op_res_name(type, op, result, bf, size); | ||
270 | out_err: | ||
271 | return scnprintf(bf, size, "%s", err); | ||
272 | } | ||
273 | |||
274 | static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size) | ||
275 | { | ||
276 | int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size); | ||
277 | return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); | ||
278 | } | ||
279 | |||
280 | static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size) | ||
281 | { | ||
282 | int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config); | ||
283 | return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); | ||
284 | } | ||
285 | |||
286 | const char *perf_evsel__name(struct perf_evsel *evsel) | ||
287 | { | ||
288 | char bf[128]; | ||
289 | |||
290 | if (evsel->name) | ||
291 | return evsel->name; | ||
129 | 292 | ||
130 | switch (evsel->attr.type) { | 293 | switch (evsel->attr.type) { |
131 | case PERF_TYPE_RAW: | 294 | case PERF_TYPE_RAW: |
132 | ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config); | 295 | perf_evsel__raw_name(evsel, bf, sizeof(bf)); |
133 | break; | 296 | break; |
134 | 297 | ||
135 | case PERF_TYPE_HARDWARE: | 298 | case PERF_TYPE_HARDWARE: |
136 | ret = perf_evsel__hw_name(evsel, bf, size); | 299 | perf_evsel__hw_name(evsel, bf, sizeof(bf)); |
300 | break; | ||
301 | |||
302 | case PERF_TYPE_HW_CACHE: | ||
303 | perf_evsel__hw_cache_name(evsel, bf, sizeof(bf)); | ||
304 | break; | ||
305 | |||
306 | case PERF_TYPE_SOFTWARE: | ||
307 | perf_evsel__sw_name(evsel, bf, sizeof(bf)); | ||
137 | break; | 308 | break; |
309 | |||
310 | case PERF_TYPE_TRACEPOINT: | ||
311 | scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint"); | ||
312 | break; | ||
313 | |||
314 | case PERF_TYPE_BREAKPOINT: | ||
315 | perf_evsel__bp_name(evsel, bf, sizeof(bf)); | ||
316 | break; | ||
317 | |||
138 | default: | 318 | default: |
139 | /* | 319 | scnprintf(bf, sizeof(bf), "%s", "unknown attr type"); |
140 | * FIXME | 320 | break; |
141 | * | 321 | } |
142 | * This is the minimal perf_evsel__name so that we can | 322 | |
143 | * reconstruct event names taking into account event modifiers. | 323 | evsel->name = strdup(bf); |
144 | * | 324 | |
145 | * The old event_name uses it now for raw anr hw events, so that | 325 | return evsel->name ?: "unknown"; |
146 | * we don't drag all the parsing stuff into the python binding. | ||
147 | * | ||
148 | * On the next devel cycle the rest of the event naming will be | ||
149 | * brought here. | ||
150 | */ | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | return ret; | ||
155 | } | 326 | } |
156 | 327 | ||
157 | void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, | 328 | void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 4ba8b564e6f4..67cc5033d192 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -83,8 +83,19 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
83 | struct perf_record_opts *opts, | 83 | struct perf_record_opts *opts, |
84 | struct perf_evsel *first); | 84 | struct perf_evsel *first); |
85 | 85 | ||
86 | const char* __perf_evsel__hw_name(u64 config); | 86 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op); |
87 | int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size); | 87 | |
88 | #define PERF_EVSEL__MAX_ALIASES 8 | ||
89 | |||
90 | extern const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] | ||
91 | [PERF_EVSEL__MAX_ALIASES]; | ||
92 | extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX] | ||
93 | [PERF_EVSEL__MAX_ALIASES]; | ||
94 | const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] | ||
95 | [PERF_EVSEL__MAX_ALIASES]; | ||
96 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, | ||
97 | char *bf, size_t size); | ||
98 | const char *perf_evsel__name(struct perf_evsel *evsel); | ||
88 | 99 | ||
89 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 100 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
90 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); | 101 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index e909d43cf542..5a47aba46759 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -641,7 +641,7 @@ static int write_event_desc(int fd, struct perf_header *h __used, | |||
641 | /* | 641 | /* |
642 | * write event string as passed on cmdline | 642 | * write event string as passed on cmdline |
643 | */ | 643 | */ |
644 | ret = do_write_string(fd, event_name(attr)); | 644 | ret = do_write_string(fd, perf_evsel__name(attr)); |
645 | if (ret < 0) | 645 | if (ret < 0) |
646 | return ret; | 646 | return ret; |
647 | /* | 647 | /* |
@@ -1474,15 +1474,15 @@ out: | |||
1474 | 1474 | ||
1475 | static int process_tracing_data(struct perf_file_section *section __unused, | 1475 | static int process_tracing_data(struct perf_file_section *section __unused, |
1476 | struct perf_header *ph __unused, | 1476 | struct perf_header *ph __unused, |
1477 | int feat __unused, int fd) | 1477 | int feat __unused, int fd, void *data) |
1478 | { | 1478 | { |
1479 | trace_report(fd, false); | 1479 | trace_report(fd, data, false); |
1480 | return 0; | 1480 | return 0; |
1481 | } | 1481 | } |
1482 | 1482 | ||
1483 | static int process_build_id(struct perf_file_section *section, | 1483 | static int process_build_id(struct perf_file_section *section, |
1484 | struct perf_header *ph, | 1484 | struct perf_header *ph, |
1485 | int feat __unused, int fd) | 1485 | int feat __unused, int fd, void *data __used) |
1486 | { | 1486 | { |
1487 | if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) | 1487 | if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) |
1488 | pr_debug("Failed to read buildids, continuing...\n"); | 1488 | pr_debug("Failed to read buildids, continuing...\n"); |
@@ -1493,7 +1493,7 @@ struct feature_ops { | |||
1493 | int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); | 1493 | int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); |
1494 | void (*print)(struct perf_header *h, int fd, FILE *fp); | 1494 | void (*print)(struct perf_header *h, int fd, FILE *fp); |
1495 | int (*process)(struct perf_file_section *section, | 1495 | int (*process)(struct perf_file_section *section, |
1496 | struct perf_header *h, int feat, int fd); | 1496 | struct perf_header *h, int feat, int fd, void *data); |
1497 | const char *name; | 1497 | const char *name; |
1498 | bool full_only; | 1498 | bool full_only; |
1499 | }; | 1499 | }; |
@@ -1988,7 +1988,7 @@ int perf_file_header__read(struct perf_file_header *header, | |||
1988 | 1988 | ||
1989 | static int perf_file_section__process(struct perf_file_section *section, | 1989 | static int perf_file_section__process(struct perf_file_section *section, |
1990 | struct perf_header *ph, | 1990 | struct perf_header *ph, |
1991 | int feat, int fd, void *data __used) | 1991 | int feat, int fd, void *data) |
1992 | { | 1992 | { |
1993 | if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { | 1993 | if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { |
1994 | pr_debug("Failed to lseek to %" PRIu64 " offset for feature " | 1994 | pr_debug("Failed to lseek to %" PRIu64 " offset for feature " |
@@ -2004,7 +2004,7 @@ static int perf_file_section__process(struct perf_file_section *section, | |||
2004 | if (!feat_ops[feat].process) | 2004 | if (!feat_ops[feat].process) |
2005 | return 0; | 2005 | return 0; |
2006 | 2006 | ||
2007 | return feat_ops[feat].process(section, ph, feat, fd); | 2007 | return feat_ops[feat].process(section, ph, feat, fd, data); |
2008 | } | 2008 | } |
2009 | 2009 | ||
2010 | static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, | 2010 | static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, |
@@ -2093,9 +2093,11 @@ static int read_attr(int fd, struct perf_header *ph, | |||
2093 | return ret <= 0 ? -1 : 0; | 2093 | return ret <= 0 ? -1 : 0; |
2094 | } | 2094 | } |
2095 | 2095 | ||
2096 | static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel) | 2096 | static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel, |
2097 | struct pevent *pevent) | ||
2097 | { | 2098 | { |
2098 | struct event_format *event = trace_find_event(evsel->attr.config); | 2099 | struct event_format *event = pevent_find_event(pevent, |
2100 | evsel->attr.config); | ||
2099 | char bf[128]; | 2101 | char bf[128]; |
2100 | 2102 | ||
2101 | if (event == NULL) | 2103 | if (event == NULL) |
@@ -2109,13 +2111,14 @@ static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel) | |||
2109 | return 0; | 2111 | return 0; |
2110 | } | 2112 | } |
2111 | 2113 | ||
2112 | static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist) | 2114 | static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist, |
2115 | struct pevent *pevent) | ||
2113 | { | 2116 | { |
2114 | struct perf_evsel *pos; | 2117 | struct perf_evsel *pos; |
2115 | 2118 | ||
2116 | list_for_each_entry(pos, &evlist->entries, node) { | 2119 | list_for_each_entry(pos, &evlist->entries, node) { |
2117 | if (pos->attr.type == PERF_TYPE_TRACEPOINT && | 2120 | if (pos->attr.type == PERF_TYPE_TRACEPOINT && |
2118 | perf_evsel__set_tracepoint_name(pos)) | 2121 | perf_evsel__set_tracepoint_name(pos, pevent)) |
2119 | return -1; | 2122 | return -1; |
2120 | } | 2123 | } |
2121 | 2124 | ||
@@ -2198,12 +2201,12 @@ int perf_session__read_header(struct perf_session *session, int fd) | |||
2198 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); | 2201 | event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); |
2199 | } | 2202 | } |
2200 | 2203 | ||
2201 | perf_header__process_sections(header, fd, NULL, | 2204 | perf_header__process_sections(header, fd, &session->pevent, |
2202 | perf_file_section__process); | 2205 | perf_file_section__process); |
2203 | 2206 | ||
2204 | lseek(fd, header->data_offset, SEEK_SET); | 2207 | lseek(fd, header->data_offset, SEEK_SET); |
2205 | 2208 | ||
2206 | if (perf_evlist__set_tracepoint_names(session->evlist)) | 2209 | if (perf_evlist__set_tracepoint_names(session->evlist, session->pevent)) |
2207 | goto out_delete_evlist; | 2210 | goto out_delete_evlist; |
2208 | 2211 | ||
2209 | header->frozen = 1; | 2212 | header->frozen = 1; |
@@ -2419,8 +2422,8 @@ int perf_event__process_tracing_data(union perf_event *event, | |||
2419 | lseek(session->fd, offset + sizeof(struct tracing_data_event), | 2422 | lseek(session->fd, offset + sizeof(struct tracing_data_event), |
2420 | SEEK_SET); | 2423 | SEEK_SET); |
2421 | 2424 | ||
2422 | size_read = trace_report(session->fd, session->repipe); | 2425 | size_read = trace_report(session->fd, &session->pevent, |
2423 | 2426 | session->repipe); | |
2424 | padding = ALIGN(size_read, sizeof(u64)) - size_read; | 2427 | padding = ALIGN(size_read, sizeof(u64)) - size_read; |
2425 | 2428 | ||
2426 | if (read(session->fd, buf, padding) < 0) | 2429 | if (read(session->fd, buf, padding) < 0) |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 34bb556d6219..0b096c27a419 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -47,6 +47,7 @@ enum hist_column { | |||
47 | HISTC_SYMBOL_TO, | 47 | HISTC_SYMBOL_TO, |
48 | HISTC_DSO_FROM, | 48 | HISTC_DSO_FROM, |
49 | HISTC_DSO_TO, | 49 | HISTC_DSO_TO, |
50 | HISTC_SRCLINE, | ||
50 | HISTC_NR_COLS, /* Last entry */ | 51 | HISTC_NR_COLS, /* Last entry */ |
51 | }; | 52 | }; |
52 | 53 | ||
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h index 1eb804fd3fbf..b6842c1d02a8 100644 --- a/tools/perf/util/include/linux/kernel.h +++ b/tools/perf/util/include/linux/kernel.h | |||
@@ -108,4 +108,14 @@ int eprintf(int level, | |||
108 | #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) | 108 | #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) |
109 | #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) | 109 | #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) |
110 | 110 | ||
111 | /* | ||
112 | * This looks more complex than it should be. But we need to | ||
113 | * get the type for the ~ right in round_down (it needs to be | ||
114 | * as wide as the result!), and we want to evaluate the macro | ||
115 | * arguments just once each. | ||
116 | */ | ||
117 | #define __round_mask(x, y) ((__typeof__(x))((y)-1)) | ||
118 | #define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) | ||
119 | #define round_down(x, y) ((x) & ~__round_mask(x, y)) | ||
120 | |||
111 | #endif | 121 | #endif |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 81371bad4ef0..c14c665d9a25 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -157,7 +157,7 @@ void machine__exit(struct machine *self); | |||
157 | void machine__delete(struct machine *self); | 157 | void machine__delete(struct machine *self); |
158 | 158 | ||
159 | int machine__resolve_callchain(struct machine *machine, | 159 | int machine__resolve_callchain(struct machine *machine, |
160 | struct perf_evsel *evsel, struct thread *thread, | 160 | struct thread *thread, |
161 | struct ip_callchain *chain, | 161 | struct ip_callchain *chain, |
162 | struct symbol **parent); | 162 | struct symbol **parent); |
163 | int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, | 163 | int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, |
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c index 76b98e2a587d..1b997d2b89ce 100644 --- a/tools/perf/util/parse-events-test.c +++ b/tools/perf/util/parse-events-test.c | |||
@@ -181,6 +181,22 @@ static int test__checkevent_breakpoint_w(struct perf_evlist *evlist) | |||
181 | return 0; | 181 | return 0; |
182 | } | 182 | } |
183 | 183 | ||
184 | static int test__checkevent_breakpoint_rw(struct perf_evlist *evlist) | ||
185 | { | ||
186 | struct perf_evsel *evsel = list_entry(evlist->entries.next, | ||
187 | struct perf_evsel, node); | ||
188 | |||
189 | TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); | ||
190 | TEST_ASSERT_VAL("wrong type", | ||
191 | PERF_TYPE_BREAKPOINT == evsel->attr.type); | ||
192 | TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config); | ||
193 | TEST_ASSERT_VAL("wrong bp_type", | ||
194 | (HW_BREAKPOINT_R|HW_BREAKPOINT_W) == evsel->attr.bp_type); | ||
195 | TEST_ASSERT_VAL("wrong bp_len", | ||
196 | HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
184 | static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist) | 200 | static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist) |
185 | { | 201 | { |
186 | struct perf_evsel *evsel = list_entry(evlist->entries.next, | 202 | struct perf_evsel *evsel = list_entry(evlist->entries.next, |
@@ -309,6 +325,8 @@ static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist) | |||
309 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | 325 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); |
310 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 326 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
311 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 327 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
328 | TEST_ASSERT_VAL("wrong name", | ||
329 | !strcmp(perf_evsel__name(evsel), "mem:0x0:rw:u")); | ||
312 | 330 | ||
313 | return test__checkevent_breakpoint(evlist); | 331 | return test__checkevent_breakpoint(evlist); |
314 | } | 332 | } |
@@ -322,6 +340,8 @@ static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist) | |||
322 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | 340 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); |
323 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 341 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
324 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 342 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
343 | TEST_ASSERT_VAL("wrong name", | ||
344 | !strcmp(perf_evsel__name(evsel), "mem:0x0:x:k")); | ||
325 | 345 | ||
326 | return test__checkevent_breakpoint_x(evlist); | 346 | return test__checkevent_breakpoint_x(evlist); |
327 | } | 347 | } |
@@ -335,6 +355,8 @@ static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist) | |||
335 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | 355 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); |
336 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | 356 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); |
337 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | 357 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); |
358 | TEST_ASSERT_VAL("wrong name", | ||
359 | !strcmp(perf_evsel__name(evsel), "mem:0x0:r:hp")); | ||
338 | 360 | ||
339 | return test__checkevent_breakpoint_r(evlist); | 361 | return test__checkevent_breakpoint_r(evlist); |
340 | } | 362 | } |
@@ -348,10 +370,27 @@ static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist) | |||
348 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | 370 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); |
349 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 371 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
350 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | 372 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); |
373 | TEST_ASSERT_VAL("wrong name", | ||
374 | !strcmp(perf_evsel__name(evsel), "mem:0x0:w:up")); | ||
351 | 375 | ||
352 | return test__checkevent_breakpoint_w(evlist); | 376 | return test__checkevent_breakpoint_w(evlist); |
353 | } | 377 | } |
354 | 378 | ||
379 | static int test__checkevent_breakpoint_rw_modifier(struct perf_evlist *evlist) | ||
380 | { | ||
381 | struct perf_evsel *evsel = list_entry(evlist->entries.next, | ||
382 | struct perf_evsel, node); | ||
383 | |||
384 | TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); | ||
385 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
386 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
387 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | ||
388 | TEST_ASSERT_VAL("wrong name", | ||
389 | !strcmp(perf_evsel__name(evsel), "mem:0x0:rw:kp")); | ||
390 | |||
391 | return test__checkevent_breakpoint_rw(evlist); | ||
392 | } | ||
393 | |||
355 | static int test__checkevent_pmu(struct perf_evlist *evlist) | 394 | static int test__checkevent_pmu(struct perf_evlist *evlist) |
356 | { | 395 | { |
357 | 396 | ||
@@ -413,19 +452,63 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist) | |||
413 | { | 452 | { |
414 | struct perf_evsel *evsel; | 453 | struct perf_evsel *evsel; |
415 | 454 | ||
416 | /* cpu/config=1,name=krava1/u */ | 455 | /* cpu/config=1,name=krava/u */ |
417 | evsel = list_entry(evlist->entries.next, struct perf_evsel, node); | 456 | evsel = list_entry(evlist->entries.next, struct perf_evsel, node); |
418 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | 457 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); |
419 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); | 458 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); |
420 | TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); | 459 | TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); |
421 | TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava")); | 460 | TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "krava")); |
422 | 461 | ||
423 | /* cpu/config=2/" */ | 462 | /* cpu/config=2/u" */ |
424 | evsel = list_entry(evsel->node.next, struct perf_evsel, node); | 463 | evsel = list_entry(evsel->node.next, struct perf_evsel, node); |
425 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | 464 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); |
426 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); | 465 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); |
427 | TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config); | 466 | TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config); |
428 | TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2")); | 467 | TEST_ASSERT_VAL("wrong name", |
468 | !strcmp(perf_evsel__name(evsel), "raw 0x2:u")); | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static int test__checkterms_simple(struct list_head *terms) | ||
474 | { | ||
475 | struct parse_events__term *term; | ||
476 | |||
477 | /* config=10 */ | ||
478 | term = list_entry(terms->next, struct parse_events__term, list); | ||
479 | TEST_ASSERT_VAL("wrong type term", | ||
480 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); | ||
481 | TEST_ASSERT_VAL("wrong type val", | ||
482 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
483 | TEST_ASSERT_VAL("wrong val", term->val.num == 10); | ||
484 | TEST_ASSERT_VAL("wrong config", !term->config); | ||
485 | |||
486 | /* config1 */ | ||
487 | term = list_entry(term->list.next, struct parse_events__term, list); | ||
488 | TEST_ASSERT_VAL("wrong type term", | ||
489 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); | ||
490 | TEST_ASSERT_VAL("wrong type val", | ||
491 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
492 | TEST_ASSERT_VAL("wrong val", term->val.num == 1); | ||
493 | TEST_ASSERT_VAL("wrong config", !term->config); | ||
494 | |||
495 | /* config2=3 */ | ||
496 | term = list_entry(term->list.next, struct parse_events__term, list); | ||
497 | TEST_ASSERT_VAL("wrong type term", | ||
498 | term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); | ||
499 | TEST_ASSERT_VAL("wrong type val", | ||
500 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
501 | TEST_ASSERT_VAL("wrong val", term->val.num == 3); | ||
502 | TEST_ASSERT_VAL("wrong config", !term->config); | ||
503 | |||
504 | /* umask=1*/ | ||
505 | term = list_entry(term->list.next, struct parse_events__term, list); | ||
506 | TEST_ASSERT_VAL("wrong type term", | ||
507 | term->type_term == PARSE_EVENTS__TERM_TYPE_USER); | ||
508 | TEST_ASSERT_VAL("wrong type val", | ||
509 | term->type_val == PARSE_EVENTS__TERM_TYPE_NUM); | ||
510 | TEST_ASSERT_VAL("wrong val", term->val.num == 1); | ||
511 | TEST_ASSERT_VAL("wrong config", !strcmp(term->config, "umask")); | ||
429 | 512 | ||
430 | return 0; | 513 | return 0; |
431 | } | 514 | } |
@@ -541,10 +624,16 @@ static struct test__event_st test__events[] = { | |||
541 | .name = "instructions:H", | 624 | .name = "instructions:H", |
542 | .check = test__checkevent_exclude_guest_modifier, | 625 | .check = test__checkevent_exclude_guest_modifier, |
543 | }, | 626 | }, |
627 | [26] = { | ||
628 | .name = "mem:0:rw", | ||
629 | .check = test__checkevent_breakpoint_rw, | ||
630 | }, | ||
631 | [27] = { | ||
632 | .name = "mem:0:rw:kp", | ||
633 | .check = test__checkevent_breakpoint_rw_modifier, | ||
634 | }, | ||
544 | }; | 635 | }; |
545 | 636 | ||
546 | #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st)) | ||
547 | |||
548 | static struct test__event_st test__events_pmu[] = { | 637 | static struct test__event_st test__events_pmu[] = { |
549 | [0] = { | 638 | [0] = { |
550 | .name = "cpu/config=10,config1,config2=3,period=1000/u", | 639 | .name = "cpu/config=10,config1,config2=3,period=1000/u", |
@@ -556,10 +645,23 @@ static struct test__event_st test__events_pmu[] = { | |||
556 | }, | 645 | }, |
557 | }; | 646 | }; |
558 | 647 | ||
559 | #define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \ | 648 | struct test__term { |
560 | sizeof(struct test__event_st)) | 649 | const char *str; |
650 | __u32 type; | ||
651 | int (*check)(struct list_head *terms); | ||
652 | }; | ||
653 | |||
654 | static struct test__term test__terms[] = { | ||
655 | [0] = { | ||
656 | .str = "config=10,config1,config2=3,umask=1", | ||
657 | .check = test__checkterms_simple, | ||
658 | }, | ||
659 | }; | ||
660 | |||
661 | #define TEST__TERMS_CNT (sizeof(test__terms) / \ | ||
662 | sizeof(struct test__term)) | ||
561 | 663 | ||
562 | static int test(struct test__event_st *e) | 664 | static int test_event(struct test__event_st *e) |
563 | { | 665 | { |
564 | struct perf_evlist *evlist; | 666 | struct perf_evlist *evlist; |
565 | int ret; | 667 | int ret; |
@@ -590,7 +692,48 @@ static int test_events(struct test__event_st *events, unsigned cnt) | |||
590 | struct test__event_st *e = &events[i]; | 692 | struct test__event_st *e = &events[i]; |
591 | 693 | ||
592 | pr_debug("running test %d '%s'\n", i, e->name); | 694 | pr_debug("running test %d '%s'\n", i, e->name); |
593 | ret = test(e); | 695 | ret = test_event(e); |
696 | if (ret) | ||
697 | break; | ||
698 | } | ||
699 | |||
700 | return ret; | ||
701 | } | ||
702 | |||
703 | static int test_term(struct test__term *t) | ||
704 | { | ||
705 | struct list_head *terms; | ||
706 | int ret; | ||
707 | |||
708 | terms = malloc(sizeof(*terms)); | ||
709 | if (!terms) | ||
710 | return -ENOMEM; | ||
711 | |||
712 | INIT_LIST_HEAD(terms); | ||
713 | |||
714 | ret = parse_events_terms(terms, t->str); | ||
715 | if (ret) { | ||
716 | pr_debug("failed to parse terms '%s', err %d\n", | ||
717 | t->str , ret); | ||
718 | return ret; | ||
719 | } | ||
720 | |||
721 | ret = t->check(terms); | ||
722 | parse_events__free_terms(terms); | ||
723 | |||
724 | return ret; | ||
725 | } | ||
726 | |||
727 | static int test_terms(struct test__term *terms, unsigned cnt) | ||
728 | { | ||
729 | int ret = 0; | ||
730 | unsigned i; | ||
731 | |||
732 | for (i = 0; i < cnt; i++) { | ||
733 | struct test__term *t = &terms[i]; | ||
734 | |||
735 | pr_debug("running test %d '%s'\n", i, t->str); | ||
736 | ret = test_term(t); | ||
594 | if (ret) | 737 | if (ret) |
595 | break; | 738 | break; |
596 | } | 739 | } |
@@ -617,9 +760,17 @@ int parse_events__test(void) | |||
617 | { | 760 | { |
618 | int ret; | 761 | int ret; |
619 | 762 | ||
620 | ret = test_events(test__events, TEST__EVENTS_CNT); | 763 | #define TEST_EVENTS(tests) \ |
621 | if (!ret && test_pmu()) | 764 | do { \ |
622 | ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT); | 765 | ret = test_events(tests, ARRAY_SIZE(tests)); \ |
766 | if (ret) \ | ||
767 | return ret; \ | ||
768 | } while (0) | ||
623 | 769 | ||
624 | return ret; | 770 | TEST_EVENTS(test__events); |
771 | |||
772 | if (test_pmu()) | ||
773 | TEST_EVENTS(test__events_pmu); | ||
774 | |||
775 | return test_terms(test__terms, ARRAY_SIZE(test__terms)); | ||
625 | } | 776 | } |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 05dbc8b3c767..1aa721d7c10f 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -11,14 +11,14 @@ | |||
11 | #include "cache.h" | 11 | #include "cache.h" |
12 | #include "header.h" | 12 | #include "header.h" |
13 | #include "debugfs.h" | 13 | #include "debugfs.h" |
14 | #include "parse-events-bison.h" | ||
15 | #define YY_EXTRA_TYPE int | ||
14 | #include "parse-events-flex.h" | 16 | #include "parse-events-flex.h" |
15 | #include "pmu.h" | 17 | #include "pmu.h" |
16 | 18 | ||
17 | #define MAX_NAME_LEN 100 | 19 | #define MAX_NAME_LEN 100 |
18 | 20 | ||
19 | struct event_symbol { | 21 | struct event_symbol { |
20 | u8 type; | ||
21 | u64 config; | ||
22 | const char *symbol; | 22 | const char *symbol; |
23 | const char *alias; | 23 | const char *alias; |
24 | }; | 24 | }; |
@@ -26,32 +26,88 @@ struct event_symbol { | |||
26 | #ifdef PARSER_DEBUG | 26 | #ifdef PARSER_DEBUG |
27 | extern int parse_events_debug; | 27 | extern int parse_events_debug; |
28 | #endif | 28 | #endif |
29 | int parse_events_parse(struct list_head *list, int *idx); | 29 | int parse_events_parse(void *data, void *scanner); |
30 | 30 | ||
31 | #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x | 31 | static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = { |
32 | #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x | 32 | [PERF_COUNT_HW_CPU_CYCLES] = { |
33 | 33 | .symbol = "cpu-cycles", | |
34 | static struct event_symbol event_symbols[] = { | 34 | .alias = "cycles", |
35 | { CHW(CPU_CYCLES), "cpu-cycles", "cycles" }, | 35 | }, |
36 | { CHW(STALLED_CYCLES_FRONTEND), "stalled-cycles-frontend", "idle-cycles-frontend" }, | 36 | [PERF_COUNT_HW_INSTRUCTIONS] = { |
37 | { CHW(STALLED_CYCLES_BACKEND), "stalled-cycles-backend", "idle-cycles-backend" }, | 37 | .symbol = "instructions", |
38 | { CHW(INSTRUCTIONS), "instructions", "" }, | 38 | .alias = "", |
39 | { CHW(CACHE_REFERENCES), "cache-references", "" }, | 39 | }, |
40 | { CHW(CACHE_MISSES), "cache-misses", "" }, | 40 | [PERF_COUNT_HW_CACHE_REFERENCES] = { |
41 | { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, | 41 | .symbol = "cache-references", |
42 | { CHW(BRANCH_MISSES), "branch-misses", "" }, | 42 | .alias = "", |
43 | { CHW(BUS_CYCLES), "bus-cycles", "" }, | 43 | }, |
44 | { CHW(REF_CPU_CYCLES), "ref-cycles", "" }, | 44 | [PERF_COUNT_HW_CACHE_MISSES] = { |
45 | 45 | .symbol = "cache-misses", | |
46 | { CSW(CPU_CLOCK), "cpu-clock", "" }, | 46 | .alias = "", |
47 | { CSW(TASK_CLOCK), "task-clock", "" }, | 47 | }, |
48 | { CSW(PAGE_FAULTS), "page-faults", "faults" }, | 48 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { |
49 | { CSW(PAGE_FAULTS_MIN), "minor-faults", "" }, | 49 | .symbol = "branch-instructions", |
50 | { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, | 50 | .alias = "branches", |
51 | { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, | 51 | }, |
52 | { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, | 52 | [PERF_COUNT_HW_BRANCH_MISSES] = { |
53 | { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" }, | 53 | .symbol = "branch-misses", |
54 | { CSW(EMULATION_FAULTS), "emulation-faults", "" }, | 54 | .alias = "", |
55 | }, | ||
56 | [PERF_COUNT_HW_BUS_CYCLES] = { | ||
57 | .symbol = "bus-cycles", | ||
58 | .alias = "", | ||
59 | }, | ||
60 | [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = { | ||
61 | .symbol = "stalled-cycles-frontend", | ||
62 | .alias = "idle-cycles-frontend", | ||
63 | }, | ||
64 | [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = { | ||
65 | .symbol = "stalled-cycles-backend", | ||
66 | .alias = "idle-cycles-backend", | ||
67 | }, | ||
68 | [PERF_COUNT_HW_REF_CPU_CYCLES] = { | ||
69 | .symbol = "ref-cycles", | ||
70 | .alias = "", | ||
71 | }, | ||
72 | }; | ||
73 | |||
74 | static struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { | ||
75 | [PERF_COUNT_SW_CPU_CLOCK] = { | ||
76 | .symbol = "cpu-clock", | ||
77 | .alias = "", | ||
78 | }, | ||
79 | [PERF_COUNT_SW_TASK_CLOCK] = { | ||
80 | .symbol = "task-clock", | ||
81 | .alias = "", | ||
82 | }, | ||
83 | [PERF_COUNT_SW_PAGE_FAULTS] = { | ||
84 | .symbol = "page-faults", | ||
85 | .alias = "faults", | ||
86 | }, | ||
87 | [PERF_COUNT_SW_CONTEXT_SWITCHES] = { | ||
88 | .symbol = "context-switches", | ||
89 | .alias = "cs", | ||
90 | }, | ||
91 | [PERF_COUNT_SW_CPU_MIGRATIONS] = { | ||
92 | .symbol = "cpu-migrations", | ||
93 | .alias = "migrations", | ||
94 | }, | ||
95 | [PERF_COUNT_SW_PAGE_FAULTS_MIN] = { | ||
96 | .symbol = "minor-faults", | ||
97 | .alias = "", | ||
98 | }, | ||
99 | [PERF_COUNT_SW_PAGE_FAULTS_MAJ] = { | ||
100 | .symbol = "major-faults", | ||
101 | .alias = "", | ||
102 | }, | ||
103 | [PERF_COUNT_SW_ALIGNMENT_FAULTS] = { | ||
104 | .symbol = "alignment-faults", | ||
105 | .alias = "", | ||
106 | }, | ||
107 | [PERF_COUNT_SW_EMULATION_FAULTS] = { | ||
108 | .symbol = "emulation-faults", | ||
109 | .alias = "", | ||
110 | }, | ||
55 | }; | 111 | }; |
56 | 112 | ||
57 | #define __PERF_EVENT_FIELD(config, name) \ | 113 | #define __PERF_EVENT_FIELD(config, name) \ |
@@ -62,63 +118,6 @@ static struct event_symbol event_symbols[] = { | |||
62 | #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) | 118 | #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) |
63 | #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) | 119 | #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) |
64 | 120 | ||
65 | static const char *sw_event_names[PERF_COUNT_SW_MAX] = { | ||
66 | "cpu-clock", | ||
67 | "task-clock", | ||
68 | "page-faults", | ||
69 | "context-switches", | ||
70 | "CPU-migrations", | ||
71 | "minor-faults", | ||
72 | "major-faults", | ||
73 | "alignment-faults", | ||
74 | "emulation-faults", | ||
75 | }; | ||
76 | |||
77 | #define MAX_ALIASES 8 | ||
78 | |||
79 | static const char *hw_cache[PERF_COUNT_HW_CACHE_MAX][MAX_ALIASES] = { | ||
80 | { "L1-dcache", "l1-d", "l1d", "L1-data", }, | ||
81 | { "L1-icache", "l1-i", "l1i", "L1-instruction", }, | ||
82 | { "LLC", "L2", }, | ||
83 | { "dTLB", "d-tlb", "Data-TLB", }, | ||
84 | { "iTLB", "i-tlb", "Instruction-TLB", }, | ||
85 | { "branch", "branches", "bpu", "btb", "bpc", }, | ||
86 | { "node", }, | ||
87 | }; | ||
88 | |||
89 | static const char *hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][MAX_ALIASES] = { | ||
90 | { "load", "loads", "read", }, | ||
91 | { "store", "stores", "write", }, | ||
92 | { "prefetch", "prefetches", "speculative-read", "speculative-load", }, | ||
93 | }; | ||
94 | |||
95 | static const char *hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] | ||
96 | [MAX_ALIASES] = { | ||
97 | { "refs", "Reference", "ops", "access", }, | ||
98 | { "misses", "miss", }, | ||
99 | }; | ||
100 | |||
101 | #define C(x) PERF_COUNT_HW_CACHE_##x | ||
102 | #define CACHE_READ (1 << C(OP_READ)) | ||
103 | #define CACHE_WRITE (1 << C(OP_WRITE)) | ||
104 | #define CACHE_PREFETCH (1 << C(OP_PREFETCH)) | ||
105 | #define COP(x) (1 << x) | ||
106 | |||
107 | /* | ||
108 | * cache operartion stat | ||
109 | * L1I : Read and prefetch only | ||
110 | * ITLB and BPU : Read-only | ||
111 | */ | ||
112 | static unsigned long hw_cache_stat[C(MAX)] = { | ||
113 | [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | ||
114 | [C(L1I)] = (CACHE_READ | CACHE_PREFETCH), | ||
115 | [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | ||
116 | [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | ||
117 | [C(ITLB)] = (CACHE_READ), | ||
118 | [C(BPU)] = (CACHE_READ), | ||
119 | [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | ||
120 | }; | ||
121 | |||
122 | #define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ | 121 | #define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ |
123 | while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ | 122 | while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ |
124 | if (sys_dirent.d_type == DT_DIR && \ | 123 | if (sys_dirent.d_type == DT_DIR && \ |
@@ -218,48 +217,6 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
218 | return NULL; | 217 | return NULL; |
219 | } | 218 | } |
220 | 219 | ||
221 | #define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1) | ||
222 | static const char *tracepoint_id_to_name(u64 config) | ||
223 | { | ||
224 | static char buf[TP_PATH_LEN]; | ||
225 | struct tracepoint_path *path; | ||
226 | |||
227 | path = tracepoint_id_to_path(config); | ||
228 | if (path) { | ||
229 | snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name); | ||
230 | free(path->name); | ||
231 | free(path->system); | ||
232 | free(path); | ||
233 | } else | ||
234 | snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown"); | ||
235 | |||
236 | return buf; | ||
237 | } | ||
238 | |||
239 | static int is_cache_op_valid(u8 cache_type, u8 cache_op) | ||
240 | { | ||
241 | if (hw_cache_stat[cache_type] & COP(cache_op)) | ||
242 | return 1; /* valid */ | ||
243 | else | ||
244 | return 0; /* invalid */ | ||
245 | } | ||
246 | |||
247 | static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result) | ||
248 | { | ||
249 | static char name[50]; | ||
250 | |||
251 | if (cache_result) { | ||
252 | sprintf(name, "%s-%s-%s", hw_cache[cache_type][0], | ||
253 | hw_cache_op[cache_op][0], | ||
254 | hw_cache_result[cache_result][0]); | ||
255 | } else { | ||
256 | sprintf(name, "%s-%s", hw_cache[cache_type][0], | ||
257 | hw_cache_op[cache_op][1]); | ||
258 | } | ||
259 | |||
260 | return name; | ||
261 | } | ||
262 | |||
263 | const char *event_type(int type) | 220 | const char *event_type(int type) |
264 | { | 221 | { |
265 | switch (type) { | 222 | switch (type) { |
@@ -282,76 +239,6 @@ const char *event_type(int type) | |||
282 | return "unknown"; | 239 | return "unknown"; |
283 | } | 240 | } |
284 | 241 | ||
285 | const char *event_name(struct perf_evsel *evsel) | ||
286 | { | ||
287 | u64 config = evsel->attr.config; | ||
288 | int type = evsel->attr.type; | ||
289 | |||
290 | if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE) { | ||
291 | /* | ||
292 | * XXX minimal fix, see comment on perf_evsen__name, this static buffer | ||
293 | * will go away together with event_name in the next devel cycle. | ||
294 | */ | ||
295 | static char bf[128]; | ||
296 | perf_evsel__name(evsel, bf, sizeof(bf)); | ||
297 | return bf; | ||
298 | } | ||
299 | |||
300 | if (evsel->name) | ||
301 | return evsel->name; | ||
302 | |||
303 | return __event_name(type, config); | ||
304 | } | ||
305 | |||
306 | const char *__event_name(int type, u64 config) | ||
307 | { | ||
308 | static char buf[32]; | ||
309 | |||
310 | if (type == PERF_TYPE_RAW) { | ||
311 | sprintf(buf, "raw 0x%" PRIx64, config); | ||
312 | return buf; | ||
313 | } | ||
314 | |||
315 | switch (type) { | ||
316 | case PERF_TYPE_HARDWARE: | ||
317 | return __perf_evsel__hw_name(config); | ||
318 | |||
319 | case PERF_TYPE_HW_CACHE: { | ||
320 | u8 cache_type, cache_op, cache_result; | ||
321 | |||
322 | cache_type = (config >> 0) & 0xff; | ||
323 | if (cache_type > PERF_COUNT_HW_CACHE_MAX) | ||
324 | return "unknown-ext-hardware-cache-type"; | ||
325 | |||
326 | cache_op = (config >> 8) & 0xff; | ||
327 | if (cache_op > PERF_COUNT_HW_CACHE_OP_MAX) | ||
328 | return "unknown-ext-hardware-cache-op"; | ||
329 | |||
330 | cache_result = (config >> 16) & 0xff; | ||
331 | if (cache_result > PERF_COUNT_HW_CACHE_RESULT_MAX) | ||
332 | return "unknown-ext-hardware-cache-result"; | ||
333 | |||
334 | if (!is_cache_op_valid(cache_type, cache_op)) | ||
335 | return "invalid-cache"; | ||
336 | |||
337 | return event_cache_name(cache_type, cache_op, cache_result); | ||
338 | } | ||
339 | |||
340 | case PERF_TYPE_SOFTWARE: | ||
341 | if (config < PERF_COUNT_SW_MAX && sw_event_names[config]) | ||
342 | return sw_event_names[config]; | ||
343 | return "unknown-software"; | ||
344 | |||
345 | case PERF_TYPE_TRACEPOINT: | ||
346 | return tracepoint_id_to_name(config); | ||
347 | |||
348 | default: | ||
349 | break; | ||
350 | } | ||
351 | |||
352 | return "unknown"; | ||
353 | } | ||
354 | |||
355 | static int add_event(struct list_head **_list, int *idx, | 242 | static int add_event(struct list_head **_list, int *idx, |
356 | struct perf_event_attr *attr, char *name) | 243 | struct perf_event_attr *attr, char *name) |
357 | { | 244 | { |
@@ -373,19 +260,20 @@ static int add_event(struct list_head **_list, int *idx, | |||
373 | return -ENOMEM; | 260 | return -ENOMEM; |
374 | } | 261 | } |
375 | 262 | ||
376 | evsel->name = strdup(name); | 263 | if (name) |
264 | evsel->name = strdup(name); | ||
377 | list_add_tail(&evsel->node, list); | 265 | list_add_tail(&evsel->node, list); |
378 | *_list = list; | 266 | *_list = list; |
379 | return 0; | 267 | return 0; |
380 | } | 268 | } |
381 | 269 | ||
382 | static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size) | 270 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) |
383 | { | 271 | { |
384 | int i, j; | 272 | int i, j; |
385 | int n, longest = -1; | 273 | int n, longest = -1; |
386 | 274 | ||
387 | for (i = 0; i < size; i++) { | 275 | for (i = 0; i < size; i++) { |
388 | for (j = 0; j < MAX_ALIASES && names[i][j]; j++) { | 276 | for (j = 0; j < PERF_EVSEL__MAX_ALIASES && names[i][j]; j++) { |
389 | n = strlen(names[i][j]); | 277 | n = strlen(names[i][j]); |
390 | if (n > longest && !strncasecmp(str, names[i][j], n)) | 278 | if (n > longest && !strncasecmp(str, names[i][j], n)) |
391 | longest = n; | 279 | longest = n; |
@@ -410,7 +298,7 @@ int parse_events_add_cache(struct list_head **list, int *idx, | |||
410 | * No fallback - if we cannot get a clear cache type | 298 | * No fallback - if we cannot get a clear cache type |
411 | * then bail out: | 299 | * then bail out: |
412 | */ | 300 | */ |
413 | cache_type = parse_aliases(type, hw_cache, | 301 | cache_type = parse_aliases(type, perf_evsel__hw_cache, |
414 | PERF_COUNT_HW_CACHE_MAX); | 302 | PERF_COUNT_HW_CACHE_MAX); |
415 | if (cache_type == -1) | 303 | if (cache_type == -1) |
416 | return -EINVAL; | 304 | return -EINVAL; |
@@ -423,18 +311,18 @@ int parse_events_add_cache(struct list_head **list, int *idx, | |||
423 | snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str); | 311 | snprintf(name + n, MAX_NAME_LEN - n, "-%s\n", str); |
424 | 312 | ||
425 | if (cache_op == -1) { | 313 | if (cache_op == -1) { |
426 | cache_op = parse_aliases(str, hw_cache_op, | 314 | cache_op = parse_aliases(str, perf_evsel__hw_cache_op, |
427 | PERF_COUNT_HW_CACHE_OP_MAX); | 315 | PERF_COUNT_HW_CACHE_OP_MAX); |
428 | if (cache_op >= 0) { | 316 | if (cache_op >= 0) { |
429 | if (!is_cache_op_valid(cache_type, cache_op)) | 317 | if (!perf_evsel__is_cache_op_valid(cache_type, cache_op)) |
430 | return -EINVAL; | 318 | return -EINVAL; |
431 | continue; | 319 | continue; |
432 | } | 320 | } |
433 | } | 321 | } |
434 | 322 | ||
435 | if (cache_result == -1) { | 323 | if (cache_result == -1) { |
436 | cache_result = parse_aliases(str, hw_cache_result, | 324 | cache_result = parse_aliases(str, perf_evsel__hw_cache_result, |
437 | PERF_COUNT_HW_CACHE_RESULT_MAX); | 325 | PERF_COUNT_HW_CACHE_RESULT_MAX); |
438 | if (cache_result >= 0) | 326 | if (cache_result >= 0) |
439 | continue; | 327 | continue; |
440 | } | 328 | } |
@@ -549,21 +437,31 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr) | |||
549 | if (!type || !type[i]) | 437 | if (!type || !type[i]) |
550 | break; | 438 | break; |
551 | 439 | ||
440 | #define CHECK_SET_TYPE(bit) \ | ||
441 | do { \ | ||
442 | if (attr->bp_type & bit) \ | ||
443 | return -EINVAL; \ | ||
444 | else \ | ||
445 | attr->bp_type |= bit; \ | ||
446 | } while (0) | ||
447 | |||
552 | switch (type[i]) { | 448 | switch (type[i]) { |
553 | case 'r': | 449 | case 'r': |
554 | attr->bp_type |= HW_BREAKPOINT_R; | 450 | CHECK_SET_TYPE(HW_BREAKPOINT_R); |
555 | break; | 451 | break; |
556 | case 'w': | 452 | case 'w': |
557 | attr->bp_type |= HW_BREAKPOINT_W; | 453 | CHECK_SET_TYPE(HW_BREAKPOINT_W); |
558 | break; | 454 | break; |
559 | case 'x': | 455 | case 'x': |
560 | attr->bp_type |= HW_BREAKPOINT_X; | 456 | CHECK_SET_TYPE(HW_BREAKPOINT_X); |
561 | break; | 457 | break; |
562 | default: | 458 | default: |
563 | return -EINVAL; | 459 | return -EINVAL; |
564 | } | 460 | } |
565 | } | 461 | } |
566 | 462 | ||
463 | #undef CHECK_SET_TYPE | ||
464 | |||
567 | if (!attr->bp_type) /* Default */ | 465 | if (!attr->bp_type) /* Default */ |
568 | attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W; | 466 | attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W; |
569 | 467 | ||
@@ -574,7 +472,6 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx, | |||
574 | void *ptr, char *type) | 472 | void *ptr, char *type) |
575 | { | 473 | { |
576 | struct perf_event_attr attr; | 474 | struct perf_event_attr attr; |
577 | char name[MAX_NAME_LEN]; | ||
578 | 475 | ||
579 | memset(&attr, 0, sizeof(attr)); | 476 | memset(&attr, 0, sizeof(attr)); |
580 | attr.bp_addr = (unsigned long) ptr; | 477 | attr.bp_addr = (unsigned long) ptr; |
@@ -593,8 +490,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx, | |||
593 | 490 | ||
594 | attr.type = PERF_TYPE_BREAKPOINT; | 491 | attr.type = PERF_TYPE_BREAKPOINT; |
595 | 492 | ||
596 | snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw"); | 493 | return add_event(list, idx, &attr, NULL); |
597 | return add_event(list, idx, &attr, name); | ||
598 | } | 494 | } |
599 | 495 | ||
600 | static int config_term(struct perf_event_attr *attr, | 496 | static int config_term(struct perf_event_attr *attr, |
@@ -666,8 +562,7 @@ int parse_events_add_numeric(struct list_head **list, int *idx, | |||
666 | config_attr(&attr, head_config, 1)) | 562 | config_attr(&attr, head_config, 1)) |
667 | return -EINVAL; | 563 | return -EINVAL; |
668 | 564 | ||
669 | return add_event(list, idx, &attr, | 565 | return add_event(list, idx, &attr, NULL); |
670 | (char *) __event_name(type, config)); | ||
671 | } | 566 | } |
672 | 567 | ||
673 | static int parse_events__is_name_term(struct parse_events__term *term) | 568 | static int parse_events__is_name_term(struct parse_events__term *term) |
@@ -675,8 +570,7 @@ static int parse_events__is_name_term(struct parse_events__term *term) | |||
675 | return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; | 570 | return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; |
676 | } | 571 | } |
677 | 572 | ||
678 | static char *pmu_event_name(struct perf_event_attr *attr, | 573 | static char *pmu_event_name(struct list_head *head_terms) |
679 | struct list_head *head_terms) | ||
680 | { | 574 | { |
681 | struct parse_events__term *term; | 575 | struct parse_events__term *term; |
682 | 576 | ||
@@ -684,7 +578,7 @@ static char *pmu_event_name(struct perf_event_attr *attr, | |||
684 | if (parse_events__is_name_term(term)) | 578 | if (parse_events__is_name_term(term)) |
685 | return term->val.str; | 579 | return term->val.str; |
686 | 580 | ||
687 | return (char *) __event_name(PERF_TYPE_RAW, attr->config); | 581 | return NULL; |
688 | } | 582 | } |
689 | 583 | ||
690 | int parse_events_add_pmu(struct list_head **list, int *idx, | 584 | int parse_events_add_pmu(struct list_head **list, int *idx, |
@@ -699,6 +593,9 @@ int parse_events_add_pmu(struct list_head **list, int *idx, | |||
699 | 593 | ||
700 | memset(&attr, 0, sizeof(attr)); | 594 | memset(&attr, 0, sizeof(attr)); |
701 | 595 | ||
596 | if (perf_pmu__check_alias(pmu, head_config)) | ||
597 | return -EINVAL; | ||
598 | |||
702 | /* | 599 | /* |
703 | * Configure hardcoded terms first, no need to check | 600 | * Configure hardcoded terms first, no need to check |
704 | * return value when called with fail == 0 ;) | 601 | * return value when called with fail == 0 ;) |
@@ -709,7 +606,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx, | |||
709 | return -EINVAL; | 606 | return -EINVAL; |
710 | 607 | ||
711 | return add_event(list, idx, &attr, | 608 | return add_event(list, idx, &attr, |
712 | pmu_event_name(&attr, head_config)); | 609 | pmu_event_name(head_config)); |
713 | } | 610 | } |
714 | 611 | ||
715 | void parse_events_update_lists(struct list_head *list_event, | 612 | void parse_events_update_lists(struct list_head *list_event, |
@@ -787,27 +684,62 @@ int parse_events_modifier(struct list_head *list, char *str) | |||
787 | return 0; | 684 | return 0; |
788 | } | 685 | } |
789 | 686 | ||
790 | int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) | 687 | static int parse_events__scanner(const char *str, void *data, int start_token) |
791 | { | 688 | { |
792 | LIST_HEAD(list); | ||
793 | LIST_HEAD(list_tmp); | ||
794 | YY_BUFFER_STATE buffer; | 689 | YY_BUFFER_STATE buffer; |
795 | int ret, idx = evlist->nr_entries; | 690 | void *scanner; |
691 | int ret; | ||
692 | |||
693 | ret = parse_events_lex_init_extra(start_token, &scanner); | ||
694 | if (ret) | ||
695 | return ret; | ||
796 | 696 | ||
797 | buffer = parse_events__scan_string(str); | 697 | buffer = parse_events__scan_string(str, scanner); |
798 | 698 | ||
799 | #ifdef PARSER_DEBUG | 699 | #ifdef PARSER_DEBUG |
800 | parse_events_debug = 1; | 700 | parse_events_debug = 1; |
801 | #endif | 701 | #endif |
802 | ret = parse_events_parse(&list, &idx); | 702 | ret = parse_events_parse(data, scanner); |
803 | 703 | ||
804 | parse_events__flush_buffer(buffer); | 704 | parse_events__flush_buffer(buffer, scanner); |
805 | parse_events__delete_buffer(buffer); | 705 | parse_events__delete_buffer(buffer, scanner); |
806 | parse_events_lex_destroy(); | 706 | parse_events_lex_destroy(scanner); |
707 | return ret; | ||
708 | } | ||
709 | |||
710 | /* | ||
711 | * parse event config string, return a list of event terms. | ||
712 | */ | ||
713 | int parse_events_terms(struct list_head *terms, const char *str) | ||
714 | { | ||
715 | struct parse_events_data__terms data = { | ||
716 | .terms = NULL, | ||
717 | }; | ||
718 | int ret; | ||
807 | 719 | ||
720 | ret = parse_events__scanner(str, &data, PE_START_TERMS); | ||
808 | if (!ret) { | 721 | if (!ret) { |
809 | int entries = idx - evlist->nr_entries; | 722 | list_splice(data.terms, terms); |
810 | perf_evlist__splice_list_tail(evlist, &list, entries); | 723 | free(data.terms); |
724 | return 0; | ||
725 | } | ||
726 | |||
727 | parse_events__free_terms(data.terms); | ||
728 | return ret; | ||
729 | } | ||
730 | |||
731 | int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) | ||
732 | { | ||
733 | struct parse_events_data__events data = { | ||
734 | .list = LIST_HEAD_INIT(data.list), | ||
735 | .idx = evlist->nr_entries, | ||
736 | }; | ||
737 | int ret; | ||
738 | |||
739 | ret = parse_events__scanner(str, &data, PE_START_EVENTS); | ||
740 | if (!ret) { | ||
741 | int entries = data.idx - evlist->nr_entries; | ||
742 | perf_evlist__splice_list_tail(evlist, &data.list, entries); | ||
811 | return 0; | 743 | return 0; |
812 | } | 744 | } |
813 | 745 | ||
@@ -946,16 +878,13 @@ int is_valid_tracepoint(const char *event_string) | |||
946 | return 0; | 878 | return 0; |
947 | } | 879 | } |
948 | 880 | ||
949 | void print_events_type(u8 type) | 881 | static void __print_events_type(u8 type, struct event_symbol *syms, |
882 | unsigned max) | ||
950 | { | 883 | { |
951 | struct event_symbol *syms = event_symbols; | ||
952 | unsigned int i; | ||
953 | char name[64]; | 884 | char name[64]; |
885 | unsigned i; | ||
954 | 886 | ||
955 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { | 887 | for (i = 0; i < max ; i++, syms++) { |
956 | if (type != syms->type) | ||
957 | continue; | ||
958 | |||
959 | if (strlen(syms->alias)) | 888 | if (strlen(syms->alias)) |
960 | snprintf(name, sizeof(name), "%s OR %s", | 889 | snprintf(name, sizeof(name), "%s OR %s", |
961 | syms->symbol, syms->alias); | 890 | syms->symbol, syms->alias); |
@@ -967,19 +896,28 @@ void print_events_type(u8 type) | |||
967 | } | 896 | } |
968 | } | 897 | } |
969 | 898 | ||
899 | void print_events_type(u8 type) | ||
900 | { | ||
901 | if (type == PERF_TYPE_SOFTWARE) | ||
902 | __print_events_type(type, event_symbols_sw, PERF_COUNT_SW_MAX); | ||
903 | else | ||
904 | __print_events_type(type, event_symbols_hw, PERF_COUNT_HW_MAX); | ||
905 | } | ||
906 | |||
970 | int print_hwcache_events(const char *event_glob) | 907 | int print_hwcache_events(const char *event_glob) |
971 | { | 908 | { |
972 | unsigned int type, op, i, printed = 0; | 909 | unsigned int type, op, i, printed = 0; |
910 | char name[64]; | ||
973 | 911 | ||
974 | for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { | 912 | for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { |
975 | for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { | 913 | for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { |
976 | /* skip invalid cache type */ | 914 | /* skip invalid cache type */ |
977 | if (!is_cache_op_valid(type, op)) | 915 | if (!perf_evsel__is_cache_op_valid(type, op)) |
978 | continue; | 916 | continue; |
979 | 917 | ||
980 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { | 918 | for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { |
981 | char *name = event_cache_name(type, op, i); | 919 | __perf_evsel__hw_cache_type_op_res_name(type, op, i, |
982 | 920 | name, sizeof(name)); | |
983 | if (event_glob != NULL && !strglobmatch(name, event_glob)) | 921 | if (event_glob != NULL && !strglobmatch(name, event_glob)) |
984 | continue; | 922 | continue; |
985 | 923 | ||
@@ -993,26 +931,13 @@ int print_hwcache_events(const char *event_glob) | |||
993 | return printed; | 931 | return printed; |
994 | } | 932 | } |
995 | 933 | ||
996 | /* | 934 | static void print_symbol_events(const char *event_glob, unsigned type, |
997 | * Print the help text for the event symbols: | 935 | struct event_symbol *syms, unsigned max) |
998 | */ | ||
999 | void print_events(const char *event_glob) | ||
1000 | { | 936 | { |
1001 | unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0; | 937 | unsigned i, printed = 0; |
1002 | struct event_symbol *syms = event_symbols; | ||
1003 | char name[MAX_NAME_LEN]; | 938 | char name[MAX_NAME_LEN]; |
1004 | 939 | ||
1005 | printf("\n"); | 940 | for (i = 0; i < max; i++, syms++) { |
1006 | printf("List of pre-defined events (to be used in -e):\n"); | ||
1007 | |||
1008 | for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { | ||
1009 | type = syms->type; | ||
1010 | |||
1011 | if (type != prev_type && printed) { | ||
1012 | printf("\n"); | ||
1013 | printed = 0; | ||
1014 | ntypes_printed++; | ||
1015 | } | ||
1016 | 941 | ||
1017 | if (event_glob != NULL && | 942 | if (event_glob != NULL && |
1018 | !(strglobmatch(syms->symbol, event_glob) || | 943 | !(strglobmatch(syms->symbol, event_glob) || |
@@ -1023,17 +948,31 @@ void print_events(const char *event_glob) | |||
1023 | snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); | 948 | snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); |
1024 | else | 949 | else |
1025 | strncpy(name, syms->symbol, MAX_NAME_LEN); | 950 | strncpy(name, syms->symbol, MAX_NAME_LEN); |
1026 | printf(" %-50s [%s]\n", name, | ||
1027 | event_type_descriptors[type]); | ||
1028 | 951 | ||
1029 | prev_type = type; | 952 | printf(" %-50s [%s]\n", name, event_type_descriptors[type]); |
1030 | ++printed; | 953 | |
954 | printed++; | ||
1031 | } | 955 | } |
1032 | 956 | ||
1033 | if (ntypes_printed) { | 957 | if (printed) |
1034 | printed = 0; | ||
1035 | printf("\n"); | 958 | printf("\n"); |
1036 | } | 959 | } |
960 | |||
961 | /* | ||
962 | * Print the help text for the event symbols: | ||
963 | */ | ||
964 | void print_events(const char *event_glob) | ||
965 | { | ||
966 | |||
967 | printf("\n"); | ||
968 | printf("List of pre-defined events (to be used in -e):\n"); | ||
969 | |||
970 | print_symbol_events(event_glob, PERF_TYPE_HARDWARE, | ||
971 | event_symbols_hw, PERF_COUNT_HW_MAX); | ||
972 | |||
973 | print_symbol_events(event_glob, PERF_TYPE_SOFTWARE, | ||
974 | event_symbols_sw, PERF_COUNT_SW_MAX); | ||
975 | |||
1037 | print_hwcache_events(event_glob); | 976 | print_hwcache_events(event_glob); |
1038 | 977 | ||
1039 | if (event_glob != NULL) | 978 | if (event_glob != NULL) |
@@ -1106,6 +1045,13 @@ int parse_events__term_str(struct parse_events__term **term, | |||
1106 | config, str, 0); | 1045 | config, str, 0); |
1107 | } | 1046 | } |
1108 | 1047 | ||
1048 | int parse_events__term_clone(struct parse_events__term **new, | ||
1049 | struct parse_events__term *term) | ||
1050 | { | ||
1051 | return new_term(new, term->type_val, term->type_term, term->config, | ||
1052 | term->val.str, term->val.num); | ||
1053 | } | ||
1054 | |||
1109 | void parse_events__free_terms(struct list_head *terms) | 1055 | void parse_events__free_terms(struct list_head *terms) |
1110 | { | 1056 | { |
1111 | struct parse_events__term *term, *h; | 1057 | struct parse_events__term *term, *h; |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 8cac57ab4ee6..ee9c218a193c 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -26,13 +26,12 @@ extern struct tracepoint_path *tracepoint_id_to_path(u64 config); | |||
26 | extern bool have_tracepoints(struct list_head *evlist); | 26 | extern bool have_tracepoints(struct list_head *evlist); |
27 | 27 | ||
28 | const char *event_type(int type); | 28 | const char *event_type(int type); |
29 | const char *event_name(struct perf_evsel *event); | ||
30 | extern const char *__event_name(int type, u64 config); | ||
31 | 29 | ||
32 | extern int parse_events_option(const struct option *opt, const char *str, | 30 | extern int parse_events_option(const struct option *opt, const char *str, |
33 | int unset); | 31 | int unset); |
34 | extern int parse_events(struct perf_evlist *evlist, const char *str, | 32 | extern int parse_events(struct perf_evlist *evlist, const char *str, |
35 | int unset); | 33 | int unset); |
34 | extern int parse_events_terms(struct list_head *terms, const char *str); | ||
36 | extern int parse_filter(const struct option *opt, const char *str, int unset); | 35 | extern int parse_filter(const struct option *opt, const char *str, int unset); |
37 | 36 | ||
38 | #define EVENTS_HELP_MAX (128*1024) | 37 | #define EVENTS_HELP_MAX (128*1024) |
@@ -63,11 +62,22 @@ struct parse_events__term { | |||
63 | struct list_head list; | 62 | struct list_head list; |
64 | }; | 63 | }; |
65 | 64 | ||
65 | struct parse_events_data__events { | ||
66 | struct list_head list; | ||
67 | int idx; | ||
68 | }; | ||
69 | |||
70 | struct parse_events_data__terms { | ||
71 | struct list_head *terms; | ||
72 | }; | ||
73 | |||
66 | int parse_events__is_hardcoded_term(struct parse_events__term *term); | 74 | int parse_events__is_hardcoded_term(struct parse_events__term *term); |
67 | int parse_events__term_num(struct parse_events__term **_term, | 75 | int parse_events__term_num(struct parse_events__term **_term, |
68 | int type_term, char *config, long num); | 76 | int type_term, char *config, long num); |
69 | int parse_events__term_str(struct parse_events__term **_term, | 77 | int parse_events__term_str(struct parse_events__term **_term, |
70 | int type_term, char *config, char *str); | 78 | int type_term, char *config, char *str); |
79 | int parse_events__term_clone(struct parse_events__term **new, | ||
80 | struct parse_events__term *term); | ||
71 | void parse_events__free_terms(struct list_head *terms); | 81 | void parse_events__free_terms(struct list_head *terms); |
72 | int parse_events_modifier(struct list_head *list, char *str); | 82 | int parse_events_modifier(struct list_head *list, char *str); |
73 | int parse_events_add_tracepoint(struct list_head **list, int *idx, | 83 | int parse_events_add_tracepoint(struct list_head **list, int *idx, |
@@ -83,8 +93,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx, | |||
83 | char *pmu , struct list_head *head_config); | 93 | char *pmu , struct list_head *head_config); |
84 | void parse_events_update_lists(struct list_head *list_event, | 94 | void parse_events_update_lists(struct list_head *list_event, |
85 | struct list_head *list_all); | 95 | struct list_head *list_all); |
86 | void parse_events_error(struct list_head *list_all, | 96 | void parse_events_error(void *data, void *scanner, char const *msg); |
87 | int *idx, char const *msg); | ||
88 | int parse_events__test(void); | 97 | int parse_events__test(void); |
89 | 98 | ||
90 | void print_events(const char *event_glob); | 99 | void print_events(const char *event_glob); |
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 618a8e788399..384ca74c6b22 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -1,4 +1,6 @@ | |||
1 | 1 | ||
2 | %option reentrant | ||
3 | %option bison-bridge | ||
2 | %option prefix="parse_events_" | 4 | %option prefix="parse_events_" |
3 | %option stack | 5 | %option stack |
4 | 6 | ||
@@ -8,7 +10,10 @@ | |||
8 | #include "parse-events-bison.h" | 10 | #include "parse-events-bison.h" |
9 | #include "parse-events.h" | 11 | #include "parse-events.h" |
10 | 12 | ||
11 | static int __value(char *str, int base, int token) | 13 | char *parse_events_get_text(yyscan_t yyscanner); |
14 | YYSTYPE *parse_events_get_lval(yyscan_t yyscanner); | ||
15 | |||
16 | static int __value(YYSTYPE *yylval, char *str, int base, int token) | ||
12 | { | 17 | { |
13 | long num; | 18 | long num; |
14 | 19 | ||
@@ -17,35 +22,48 @@ static int __value(char *str, int base, int token) | |||
17 | if (errno) | 22 | if (errno) |
18 | return PE_ERROR; | 23 | return PE_ERROR; |
19 | 24 | ||
20 | parse_events_lval.num = num; | 25 | yylval->num = num; |
21 | return token; | 26 | return token; |
22 | } | 27 | } |
23 | 28 | ||
24 | static int value(int base) | 29 | static int value(yyscan_t scanner, int base) |
25 | { | 30 | { |
26 | return __value(parse_events_text, base, PE_VALUE); | 31 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
32 | char *text = parse_events_get_text(scanner); | ||
33 | |||
34 | return __value(yylval, text, base, PE_VALUE); | ||
27 | } | 35 | } |
28 | 36 | ||
29 | static int raw(void) | 37 | static int raw(yyscan_t scanner) |
30 | { | 38 | { |
31 | return __value(parse_events_text + 1, 16, PE_RAW); | 39 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
40 | char *text = parse_events_get_text(scanner); | ||
41 | |||
42 | return __value(yylval, text + 1, 16, PE_RAW); | ||
32 | } | 43 | } |
33 | 44 | ||
34 | static int str(int token) | 45 | static int str(yyscan_t scanner, int token) |
35 | { | 46 | { |
36 | parse_events_lval.str = strdup(parse_events_text); | 47 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
48 | char *text = parse_events_get_text(scanner); | ||
49 | |||
50 | yylval->str = strdup(text); | ||
37 | return token; | 51 | return token; |
38 | } | 52 | } |
39 | 53 | ||
40 | static int sym(int type, int config) | 54 | static int sym(yyscan_t scanner, int type, int config) |
41 | { | 55 | { |
42 | parse_events_lval.num = (type << 16) + config; | 56 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
43 | return PE_VALUE_SYM; | 57 | |
58 | yylval->num = (type << 16) + config; | ||
59 | return type == PERF_TYPE_HARDWARE ? PE_VALUE_SYM_HW : PE_VALUE_SYM_SW; | ||
44 | } | 60 | } |
45 | 61 | ||
46 | static int term(int type) | 62 | static int term(yyscan_t scanner, int type) |
47 | { | 63 | { |
48 | parse_events_lval.num = type; | 64 | YYSTYPE *yylval = parse_events_get_lval(scanner); |
65 | |||
66 | yylval->num = type; | ||
49 | return PE_TERM; | 67 | return PE_TERM; |
50 | } | 68 | } |
51 | 69 | ||
@@ -58,28 +76,41 @@ num_hex 0x[a-fA-F0-9]+ | |||
58 | num_raw_hex [a-fA-F0-9]+ | 76 | num_raw_hex [a-fA-F0-9]+ |
59 | name [a-zA-Z_*?][a-zA-Z0-9_*?]* | 77 | name [a-zA-Z_*?][a-zA-Z0-9_*?]* |
60 | modifier_event [ukhpGH]{1,8} | 78 | modifier_event [ukhpGH]{1,8} |
61 | modifier_bp [rwx] | 79 | modifier_bp [rwx]{1,3} |
62 | 80 | ||
63 | %% | 81 | %% |
64 | cpu-cycles|cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } | 82 | |
65 | stalled-cycles-frontend|idle-cycles-frontend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } | 83 | %{ |
66 | stalled-cycles-backend|idle-cycles-backend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } | 84 | { |
67 | instructions { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); } | 85 | int start_token; |
68 | cache-references { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); } | 86 | |
69 | cache-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); } | 87 | start_token = (int) parse_events_get_extra(yyscanner); |
70 | branch-instructions|branches { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } | 88 | if (start_token) { |
71 | branch-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); } | 89 | parse_events_set_extra(NULL, yyscanner); |
72 | bus-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); } | 90 | return start_token; |
73 | ref-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); } | 91 | } |
74 | cpu-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); } | 92 | } |
75 | task-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); } | 93 | %} |
76 | page-faults|faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); } | 94 | |
77 | minor-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); } | 95 | cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } |
78 | major-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); } | 96 | stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } |
79 | context-switches|cs { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); } | 97 | stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } |
80 | cpu-migrations|migrations { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); } | 98 | instructions { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); } |
81 | alignment-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } | 99 | cache-references { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); } |
82 | emulation-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } | 100 | cache-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); } |
101 | branch-instructions|branches { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); } | ||
102 | branch-misses { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); } | ||
103 | bus-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); } | ||
104 | ref-cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); } | ||
105 | cpu-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); } | ||
106 | task-clock { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); } | ||
107 | page-faults|faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); } | ||
108 | minor-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); } | ||
109 | major-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); } | ||
110 | context-switches|cs { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); } | ||
111 | cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); } | ||
112 | alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } | ||
113 | emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } | ||
83 | 114 | ||
84 | L1-dcache|l1-d|l1d|L1-data | | 115 | L1-dcache|l1-d|l1d|L1-data | |
85 | L1-icache|l1-i|l1i|L1-instruction | | 116 | L1-icache|l1-i|l1i|L1-instruction | |
@@ -87,14 +118,14 @@ LLC|L2 | | |||
87 | dTLB|d-tlb|Data-TLB | | 118 | dTLB|d-tlb|Data-TLB | |
88 | iTLB|i-tlb|Instruction-TLB | | 119 | iTLB|i-tlb|Instruction-TLB | |
89 | branch|branches|bpu|btb|bpc | | 120 | branch|branches|bpu|btb|bpc | |
90 | node { return str(PE_NAME_CACHE_TYPE); } | 121 | node { return str(yyscanner, PE_NAME_CACHE_TYPE); } |
91 | 122 | ||
92 | load|loads|read | | 123 | load|loads|read | |
93 | store|stores|write | | 124 | store|stores|write | |
94 | prefetch|prefetches | | 125 | prefetch|prefetches | |
95 | speculative-read|speculative-load | | 126 | speculative-read|speculative-load | |
96 | refs|Reference|ops|access | | 127 | refs|Reference|ops|access | |
97 | misses|miss { return str(PE_NAME_CACHE_OP_RESULT); } | 128 | misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); } |
98 | 129 | ||
99 | /* | 130 | /* |
100 | * These are event config hardcoded term names to be specified | 131 | * These are event config hardcoded term names to be specified |
@@ -102,38 +133,39 @@ misses|miss { return str(PE_NAME_CACHE_OP_RESULT); } | |||
102 | * so we can put them here directly. In case the we have a conflict | 133 | * so we can put them here directly. In case the we have a conflict |
103 | * in future, this needs to go into '//' condition block. | 134 | * in future, this needs to go into '//' condition block. |
104 | */ | 135 | */ |
105 | config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); } | 136 | config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } |
106 | config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); } | 137 | config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } |
107 | config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); } | 138 | config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); } |
108 | name { return term(PARSE_EVENTS__TERM_TYPE_NAME); } | 139 | name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); } |
109 | period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } | 140 | period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } |
110 | branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } | 141 | branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } |
111 | 142 | ||
112 | mem: { BEGIN(mem); return PE_PREFIX_MEM; } | 143 | mem: { BEGIN(mem); return PE_PREFIX_MEM; } |
113 | r{num_raw_hex} { return raw(); } | 144 | r{num_raw_hex} { return raw(yyscanner); } |
114 | {num_dec} { return value(10); } | 145 | {num_dec} { return value(yyscanner, 10); } |
115 | {num_hex} { return value(16); } | 146 | {num_hex} { return value(yyscanner, 16); } |
116 | 147 | ||
117 | {modifier_event} { return str(PE_MODIFIER_EVENT); } | 148 | {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } |
118 | {name} { return str(PE_NAME); } | 149 | {name} { return str(yyscanner, PE_NAME); } |
119 | "/" { return '/'; } | 150 | "/" { return '/'; } |
120 | - { return '-'; } | 151 | - { return '-'; } |
121 | , { return ','; } | 152 | , { return ','; } |
122 | : { return ':'; } | 153 | : { return ':'; } |
123 | = { return '='; } | 154 | = { return '='; } |
155 | \n { } | ||
124 | 156 | ||
125 | <mem>{ | 157 | <mem>{ |
126 | {modifier_bp} { return str(PE_MODIFIER_BP); } | 158 | {modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); } |
127 | : { return ':'; } | 159 | : { return ':'; } |
128 | {num_dec} { return value(10); } | 160 | {num_dec} { return value(yyscanner, 10); } |
129 | {num_hex} { return value(16); } | 161 | {num_hex} { return value(yyscanner, 16); } |
130 | /* | 162 | /* |
131 | * We need to separate 'mem:' scanner part, in order to get specific | 163 | * We need to separate 'mem:' scanner part, in order to get specific |
132 | * modifier bits parsed out. Otherwise we would need to handle PE_NAME | 164 | * modifier bits parsed out. Otherwise we would need to handle PE_NAME |
133 | * and we'd need to parse it manually. During the escape from <mem> | 165 | * and we'd need to parse it manually. During the escape from <mem> |
134 | * state we need to put the escaping char back, so we dont miss it. | 166 | * state we need to put the escaping char back, so we dont miss it. |
135 | */ | 167 | */ |
136 | . { unput(*parse_events_text); BEGIN(INITIAL); } | 168 | . { unput(*yytext); BEGIN(INITIAL); } |
137 | /* | 169 | /* |
138 | * We destroy the scanner after reaching EOF, | 170 | * We destroy the scanner after reaching EOF, |
139 | * but anyway just to be sure get back to INIT state. | 171 | * but anyway just to be sure get back to INIT state. |
@@ -143,7 +175,7 @@ r{num_raw_hex} { return raw(); } | |||
143 | 175 | ||
144 | %% | 176 | %% |
145 | 177 | ||
146 | int parse_events_wrap(void) | 178 | int parse_events_wrap(void *scanner __used) |
147 | { | 179 | { |
148 | return 1; | 180 | return 1; |
149 | } | 181 | } |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 362cc59332ae..2bc5fbff2b5d 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -1,7 +1,8 @@ | |||
1 | 1 | %pure-parser | |
2 | %name-prefix "parse_events_" | 2 | %name-prefix "parse_events_" |
3 | %parse-param {struct list_head *list_all} | 3 | %parse-param {void *_data} |
4 | %parse-param {int *idx} | 4 | %parse-param {void *scanner} |
5 | %lex-param {void* scanner} | ||
5 | 6 | ||
6 | %{ | 7 | %{ |
7 | 8 | ||
@@ -12,8 +13,9 @@ | |||
12 | #include "types.h" | 13 | #include "types.h" |
13 | #include "util.h" | 14 | #include "util.h" |
14 | #include "parse-events.h" | 15 | #include "parse-events.h" |
16 | #include "parse-events-bison.h" | ||
15 | 17 | ||
16 | extern int parse_events_lex (void); | 18 | extern int parse_events_lex (YYSTYPE* lvalp, void* scanner); |
17 | 19 | ||
18 | #define ABORT_ON(val) \ | 20 | #define ABORT_ON(val) \ |
19 | do { \ | 21 | do { \ |
@@ -23,14 +25,16 @@ do { \ | |||
23 | 25 | ||
24 | %} | 26 | %} |
25 | 27 | ||
26 | %token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM | 28 | %token PE_START_EVENTS PE_START_TERMS |
29 | %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM | ||
27 | %token PE_NAME | 30 | %token PE_NAME |
28 | %token PE_MODIFIER_EVENT PE_MODIFIER_BP | 31 | %token PE_MODIFIER_EVENT PE_MODIFIER_BP |
29 | %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT | 32 | %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT |
30 | %token PE_PREFIX_MEM PE_PREFIX_RAW | 33 | %token PE_PREFIX_MEM PE_PREFIX_RAW |
31 | %token PE_ERROR | 34 | %token PE_ERROR |
32 | %type <num> PE_VALUE | 35 | %type <num> PE_VALUE |
33 | %type <num> PE_VALUE_SYM | 36 | %type <num> PE_VALUE_SYM_HW |
37 | %type <num> PE_VALUE_SYM_SW | ||
34 | %type <num> PE_RAW | 38 | %type <num> PE_RAW |
35 | %type <num> PE_TERM | 39 | %type <num> PE_TERM |
36 | %type <str> PE_NAME | 40 | %type <str> PE_NAME |
@@ -38,6 +42,7 @@ do { \ | |||
38 | %type <str> PE_NAME_CACHE_OP_RESULT | 42 | %type <str> PE_NAME_CACHE_OP_RESULT |
39 | %type <str> PE_MODIFIER_EVENT | 43 | %type <str> PE_MODIFIER_EVENT |
40 | %type <str> PE_MODIFIER_BP | 44 | %type <str> PE_MODIFIER_BP |
45 | %type <num> value_sym | ||
41 | %type <head> event_config | 46 | %type <head> event_config |
42 | %type <term> event_term | 47 | %type <term> event_term |
43 | %type <head> event_pmu | 48 | %type <head> event_pmu |
@@ -58,24 +63,33 @@ do { \ | |||
58 | } | 63 | } |
59 | %% | 64 | %% |
60 | 65 | ||
66 | start: | ||
67 | PE_START_EVENTS events | ||
68 | | | ||
69 | PE_START_TERMS terms | ||
70 | |||
61 | events: | 71 | events: |
62 | events ',' event | event | 72 | events ',' event | event |
63 | 73 | ||
64 | event: | 74 | event: |
65 | event_def PE_MODIFIER_EVENT | 75 | event_def PE_MODIFIER_EVENT |
66 | { | 76 | { |
77 | struct parse_events_data__events *data = _data; | ||
78 | |||
67 | /* | 79 | /* |
68 | * Apply modifier on all events added by single event definition | 80 | * Apply modifier on all events added by single event definition |
69 | * (there could be more events added for multiple tracepoint | 81 | * (there could be more events added for multiple tracepoint |
70 | * definitions via '*?'. | 82 | * definitions via '*?'. |
71 | */ | 83 | */ |
72 | ABORT_ON(parse_events_modifier($1, $2)); | 84 | ABORT_ON(parse_events_modifier($1, $2)); |
73 | parse_events_update_lists($1, list_all); | 85 | parse_events_update_lists($1, &data->list); |
74 | } | 86 | } |
75 | | | 87 | | |
76 | event_def | 88 | event_def |
77 | { | 89 | { |
78 | parse_events_update_lists($1, list_all); | 90 | struct parse_events_data__events *data = _data; |
91 | |||
92 | parse_events_update_lists($1, &data->list); | ||
79 | } | 93 | } |
80 | 94 | ||
81 | event_def: event_pmu | | 95 | event_def: event_pmu | |
@@ -89,104 +103,131 @@ event_def: event_pmu | | |||
89 | event_pmu: | 103 | event_pmu: |
90 | PE_NAME '/' event_config '/' | 104 | PE_NAME '/' event_config '/' |
91 | { | 105 | { |
106 | struct parse_events_data__events *data = _data; | ||
92 | struct list_head *list = NULL; | 107 | struct list_head *list = NULL; |
93 | 108 | ||
94 | ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3)); | 109 | ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); |
95 | parse_events__free_terms($3); | 110 | parse_events__free_terms($3); |
96 | $$ = list; | 111 | $$ = list; |
97 | } | 112 | } |
98 | 113 | ||
114 | value_sym: | ||
115 | PE_VALUE_SYM_HW | ||
116 | | | ||
117 | PE_VALUE_SYM_SW | ||
118 | |||
99 | event_legacy_symbol: | 119 | event_legacy_symbol: |
100 | PE_VALUE_SYM '/' event_config '/' | 120 | value_sym '/' event_config '/' |
101 | { | 121 | { |
122 | struct parse_events_data__events *data = _data; | ||
102 | struct list_head *list = NULL; | 123 | struct list_head *list = NULL; |
103 | int type = $1 >> 16; | 124 | int type = $1 >> 16; |
104 | int config = $1 & 255; | 125 | int config = $1 & 255; |
105 | 126 | ||
106 | ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3)); | 127 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, |
128 | type, config, $3)); | ||
107 | parse_events__free_terms($3); | 129 | parse_events__free_terms($3); |
108 | $$ = list; | 130 | $$ = list; |
109 | } | 131 | } |
110 | | | 132 | | |
111 | PE_VALUE_SYM sep_slash_dc | 133 | value_sym sep_slash_dc |
112 | { | 134 | { |
135 | struct parse_events_data__events *data = _data; | ||
113 | struct list_head *list = NULL; | 136 | struct list_head *list = NULL; |
114 | int type = $1 >> 16; | 137 | int type = $1 >> 16; |
115 | int config = $1 & 255; | 138 | int config = $1 & 255; |
116 | 139 | ||
117 | ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL)); | 140 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, |
141 | type, config, NULL)); | ||
118 | $$ = list; | 142 | $$ = list; |
119 | } | 143 | } |
120 | 144 | ||
121 | event_legacy_cache: | 145 | event_legacy_cache: |
122 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT | 146 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT |
123 | { | 147 | { |
148 | struct parse_events_data__events *data = _data; | ||
124 | struct list_head *list = NULL; | 149 | struct list_head *list = NULL; |
125 | 150 | ||
126 | ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5)); | 151 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); |
127 | $$ = list; | 152 | $$ = list; |
128 | } | 153 | } |
129 | | | 154 | | |
130 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT | 155 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT |
131 | { | 156 | { |
157 | struct parse_events_data__events *data = _data; | ||
132 | struct list_head *list = NULL; | 158 | struct list_head *list = NULL; |
133 | 159 | ||
134 | ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL)); | 160 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); |
135 | $$ = list; | 161 | $$ = list; |
136 | } | 162 | } |
137 | | | 163 | | |
138 | PE_NAME_CACHE_TYPE | 164 | PE_NAME_CACHE_TYPE |
139 | { | 165 | { |
166 | struct parse_events_data__events *data = _data; | ||
140 | struct list_head *list = NULL; | 167 | struct list_head *list = NULL; |
141 | 168 | ||
142 | ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL)); | 169 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); |
143 | $$ = list; | 170 | $$ = list; |
144 | } | 171 | } |
145 | 172 | ||
146 | event_legacy_mem: | 173 | event_legacy_mem: |
147 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc | 174 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc |
148 | { | 175 | { |
176 | struct parse_events_data__events *data = _data; | ||
149 | struct list_head *list = NULL; | 177 | struct list_head *list = NULL; |
150 | 178 | ||
151 | ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4)); | 179 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, |
180 | (void *) $2, $4)); | ||
152 | $$ = list; | 181 | $$ = list; |
153 | } | 182 | } |
154 | | | 183 | | |
155 | PE_PREFIX_MEM PE_VALUE sep_dc | 184 | PE_PREFIX_MEM PE_VALUE sep_dc |
156 | { | 185 | { |
186 | struct parse_events_data__events *data = _data; | ||
157 | struct list_head *list = NULL; | 187 | struct list_head *list = NULL; |
158 | 188 | ||
159 | ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL)); | 189 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, |
190 | (void *) $2, NULL)); | ||
160 | $$ = list; | 191 | $$ = list; |
161 | } | 192 | } |
162 | 193 | ||
163 | event_legacy_tracepoint: | 194 | event_legacy_tracepoint: |
164 | PE_NAME ':' PE_NAME | 195 | PE_NAME ':' PE_NAME |
165 | { | 196 | { |
197 | struct parse_events_data__events *data = _data; | ||
166 | struct list_head *list = NULL; | 198 | struct list_head *list = NULL; |
167 | 199 | ||
168 | ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3)); | 200 | ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); |
169 | $$ = list; | 201 | $$ = list; |
170 | } | 202 | } |
171 | 203 | ||
172 | event_legacy_numeric: | 204 | event_legacy_numeric: |
173 | PE_VALUE ':' PE_VALUE | 205 | PE_VALUE ':' PE_VALUE |
174 | { | 206 | { |
207 | struct parse_events_data__events *data = _data; | ||
175 | struct list_head *list = NULL; | 208 | struct list_head *list = NULL; |
176 | 209 | ||
177 | ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL)); | 210 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, $1, $3, NULL)); |
178 | $$ = list; | 211 | $$ = list; |
179 | } | 212 | } |
180 | 213 | ||
181 | event_legacy_raw: | 214 | event_legacy_raw: |
182 | PE_RAW | 215 | PE_RAW |
183 | { | 216 | { |
217 | struct parse_events_data__events *data = _data; | ||
184 | struct list_head *list = NULL; | 218 | struct list_head *list = NULL; |
185 | 219 | ||
186 | ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL)); | 220 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, |
221 | PERF_TYPE_RAW, $1, NULL)); | ||
187 | $$ = list; | 222 | $$ = list; |
188 | } | 223 | } |
189 | 224 | ||
225 | terms: event_config | ||
226 | { | ||
227 | struct parse_events_data__terms *data = _data; | ||
228 | data->terms = $1; | ||
229 | } | ||
230 | |||
190 | event_config: | 231 | event_config: |
191 | event_config ',' event_term | 232 | event_config ',' event_term |
192 | { | 233 | { |
@@ -267,8 +308,7 @@ sep_slash_dc: '/' | ':' | | |||
267 | 308 | ||
268 | %% | 309 | %% |
269 | 310 | ||
270 | void parse_events_error(struct list_head *list_all __used, | 311 | void parse_events_error(void *data __used, void *scanner __used, |
271 | int *idx __used, | ||
272 | char const *msg __used) | 312 | char const *msg __used) |
273 | { | 313 | { |
274 | } | 314 | } |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index a119a5371699..67715a42cd6d 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -72,7 +72,7 @@ static int pmu_format(char *name, struct list_head *format) | |||
72 | "%s/bus/event_source/devices/%s/format", sysfs, name); | 72 | "%s/bus/event_source/devices/%s/format", sysfs, name); |
73 | 73 | ||
74 | if (stat(path, &st) < 0) | 74 | if (stat(path, &st) < 0) |
75 | return -1; | 75 | return 0; /* no error if format does not exist */ |
76 | 76 | ||
77 | if (pmu_format_parse(path, format)) | 77 | if (pmu_format_parse(path, format)) |
78 | return -1; | 78 | return -1; |
@@ -80,6 +80,114 @@ static int pmu_format(char *name, struct list_head *format) | |||
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) | ||
84 | { | ||
85 | struct perf_pmu__alias *alias; | ||
86 | char buf[256]; | ||
87 | int ret; | ||
88 | |||
89 | ret = fread(buf, 1, sizeof(buf), file); | ||
90 | if (ret == 0) | ||
91 | return -EINVAL; | ||
92 | buf[ret] = 0; | ||
93 | |||
94 | alias = malloc(sizeof(*alias)); | ||
95 | if (!alias) | ||
96 | return -ENOMEM; | ||
97 | |||
98 | INIT_LIST_HEAD(&alias->terms); | ||
99 | ret = parse_events_terms(&alias->terms, buf); | ||
100 | if (ret) { | ||
101 | free(alias); | ||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | alias->name = strdup(name); | ||
106 | list_add_tail(&alias->list, list); | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Process all the sysfs attributes located under the directory | ||
112 | * specified in 'dir' parameter. | ||
113 | */ | ||
114 | static int pmu_aliases_parse(char *dir, struct list_head *head) | ||
115 | { | ||
116 | struct dirent *evt_ent; | ||
117 | DIR *event_dir; | ||
118 | int ret = 0; | ||
119 | |||
120 | event_dir = opendir(dir); | ||
121 | if (!event_dir) | ||
122 | return -EINVAL; | ||
123 | |||
124 | while (!ret && (evt_ent = readdir(event_dir))) { | ||
125 | char path[PATH_MAX]; | ||
126 | char *name = evt_ent->d_name; | ||
127 | FILE *file; | ||
128 | |||
129 | if (!strcmp(name, ".") || !strcmp(name, "..")) | ||
130 | continue; | ||
131 | |||
132 | snprintf(path, PATH_MAX, "%s/%s", dir, name); | ||
133 | |||
134 | ret = -EINVAL; | ||
135 | file = fopen(path, "r"); | ||
136 | if (!file) | ||
137 | break; | ||
138 | ret = perf_pmu__new_alias(head, name, file); | ||
139 | fclose(file); | ||
140 | } | ||
141 | |||
142 | closedir(event_dir); | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * Reading the pmu event aliases definition, which should be located at: | ||
148 | * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. | ||
149 | */ | ||
150 | static int pmu_aliases(char *name, struct list_head *head) | ||
151 | { | ||
152 | struct stat st; | ||
153 | char path[PATH_MAX]; | ||
154 | const char *sysfs; | ||
155 | |||
156 | sysfs = sysfs_find_mountpoint(); | ||
157 | if (!sysfs) | ||
158 | return -1; | ||
159 | |||
160 | snprintf(path, PATH_MAX, | ||
161 | "%s/bus/event_source/devices/%s/events", sysfs, name); | ||
162 | |||
163 | if (stat(path, &st) < 0) | ||
164 | return -1; | ||
165 | |||
166 | if (pmu_aliases_parse(path, head)) | ||
167 | return -1; | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int pmu_alias_terms(struct perf_pmu__alias *alias, | ||
173 | struct list_head *terms) | ||
174 | { | ||
175 | struct parse_events__term *term, *clone; | ||
176 | LIST_HEAD(list); | ||
177 | int ret; | ||
178 | |||
179 | list_for_each_entry(term, &alias->terms, list) { | ||
180 | ret = parse_events__term_clone(&clone, term); | ||
181 | if (ret) { | ||
182 | parse_events__free_terms(&list); | ||
183 | return ret; | ||
184 | } | ||
185 | list_add_tail(&clone->list, &list); | ||
186 | } | ||
187 | list_splice(&list, terms); | ||
188 | return 0; | ||
189 | } | ||
190 | |||
83 | /* | 191 | /* |
84 | * Reading/parsing the default pmu type value, which should be | 192 | * Reading/parsing the default pmu type value, which should be |
85 | * located at: | 193 | * located at: |
@@ -118,6 +226,7 @@ static struct perf_pmu *pmu_lookup(char *name) | |||
118 | { | 226 | { |
119 | struct perf_pmu *pmu; | 227 | struct perf_pmu *pmu; |
120 | LIST_HEAD(format); | 228 | LIST_HEAD(format); |
229 | LIST_HEAD(aliases); | ||
121 | __u32 type; | 230 | __u32 type; |
122 | 231 | ||
123 | /* | 232 | /* |
@@ -135,10 +244,15 @@ static struct perf_pmu *pmu_lookup(char *name) | |||
135 | if (!pmu) | 244 | if (!pmu) |
136 | return NULL; | 245 | return NULL; |
137 | 246 | ||
247 | pmu_aliases(name, &aliases); | ||
248 | |||
138 | INIT_LIST_HEAD(&pmu->format); | 249 | INIT_LIST_HEAD(&pmu->format); |
250 | INIT_LIST_HEAD(&pmu->aliases); | ||
139 | list_splice(&format, &pmu->format); | 251 | list_splice(&format, &pmu->format); |
252 | list_splice(&aliases, &pmu->aliases); | ||
140 | pmu->name = strdup(name); | 253 | pmu->name = strdup(name); |
141 | pmu->type = type; | 254 | pmu->type = type; |
255 | list_add_tail(&pmu->list, &pmus); | ||
142 | return pmu; | 256 | return pmu; |
143 | } | 257 | } |
144 | 258 | ||
@@ -279,6 +393,59 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | |||
279 | return pmu_config(&pmu->format, attr, head_terms); | 393 | return pmu_config(&pmu->format, attr, head_terms); |
280 | } | 394 | } |
281 | 395 | ||
396 | static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, | ||
397 | struct parse_events__term *term) | ||
398 | { | ||
399 | struct perf_pmu__alias *alias; | ||
400 | char *name; | ||
401 | |||
402 | if (parse_events__is_hardcoded_term(term)) | ||
403 | return NULL; | ||
404 | |||
405 | if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) { | ||
406 | if (term->val.num != 1) | ||
407 | return NULL; | ||
408 | if (pmu_find_format(&pmu->format, term->config)) | ||
409 | return NULL; | ||
410 | name = term->config; | ||
411 | } else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) { | ||
412 | if (strcasecmp(term->config, "event")) | ||
413 | return NULL; | ||
414 | name = term->val.str; | ||
415 | } else { | ||
416 | return NULL; | ||
417 | } | ||
418 | |||
419 | list_for_each_entry(alias, &pmu->aliases, list) { | ||
420 | if (!strcasecmp(alias->name, name)) | ||
421 | return alias; | ||
422 | } | ||
423 | return NULL; | ||
424 | } | ||
425 | |||
426 | /* | ||
427 | * Find alias in the terms list and replace it with the terms | ||
428 | * defined for the alias | ||
429 | */ | ||
430 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) | ||
431 | { | ||
432 | struct parse_events__term *term, *h; | ||
433 | struct perf_pmu__alias *alias; | ||
434 | int ret; | ||
435 | |||
436 | list_for_each_entry_safe(term, h, head_terms, list) { | ||
437 | alias = pmu_find_alias(pmu, term); | ||
438 | if (!alias) | ||
439 | continue; | ||
440 | ret = pmu_alias_terms(alias, &term->list); | ||
441 | if (ret) | ||
442 | return ret; | ||
443 | list_del(&term->list); | ||
444 | free(term); | ||
445 | } | ||
446 | return 0; | ||
447 | } | ||
448 | |||
282 | int perf_pmu__new_format(struct list_head *list, char *name, | 449 | int perf_pmu__new_format(struct list_head *list, char *name, |
283 | int config, unsigned long *bits) | 450 | int config, unsigned long *bits) |
284 | { | 451 | { |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 68c0db965e1f..535f2c5258ab 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -19,17 +19,26 @@ struct perf_pmu__format { | |||
19 | struct list_head list; | 19 | struct list_head list; |
20 | }; | 20 | }; |
21 | 21 | ||
22 | struct perf_pmu__alias { | ||
23 | char *name; | ||
24 | struct list_head terms; | ||
25 | struct list_head list; | ||
26 | }; | ||
27 | |||
22 | struct perf_pmu { | 28 | struct perf_pmu { |
23 | char *name; | 29 | char *name; |
24 | __u32 type; | 30 | __u32 type; |
25 | struct list_head format; | 31 | struct list_head format; |
32 | struct list_head aliases; | ||
26 | struct list_head list; | 33 | struct list_head list; |
27 | }; | 34 | }; |
28 | 35 | ||
29 | struct perf_pmu *perf_pmu__find(char *name); | 36 | struct perf_pmu *perf_pmu__find(char *name); |
30 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | 37 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, |
31 | struct list_head *head_terms); | 38 | struct list_head *head_terms); |
32 | 39 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); | |
40 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, | ||
41 | struct list_head *head_terms); | ||
33 | int perf_pmu_wrap(void); | 42 | int perf_pmu_wrap(void); |
34 | void perf_pmu_error(struct list_head *list, char *name, char const *msg); | 43 | void perf_pmu_error(struct list_head *list, char *name, char const *msg); |
35 | 44 | ||
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 4c1b3d72a1d2..02dfa19a467f 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
@@ -209,6 +209,10 @@ static void define_event_symbols(struct event_format *event, | |||
209 | define_symbolic_values(args->symbol.symbols, ev_name, | 209 | define_symbolic_values(args->symbol.symbols, ev_name, |
210 | cur_field_name); | 210 | cur_field_name); |
211 | break; | 211 | break; |
212 | case PRINT_HEX: | ||
213 | define_event_symbols(event, ev_name, args->hex.field); | ||
214 | define_event_symbols(event, ev_name, args->hex.size); | ||
215 | break; | ||
212 | case PRINT_BSTRING: | 216 | case PRINT_BSTRING: |
213 | case PRINT_DYNAMIC_ARRAY: | 217 | case PRINT_DYNAMIC_ARRAY: |
214 | case PRINT_STRING: | 218 | case PRINT_STRING: |
@@ -233,7 +237,8 @@ static void define_event_symbols(struct event_format *event, | |||
233 | define_event_symbols(event, ev_name, args->next); | 237 | define_event_symbols(event, ev_name, args->next); |
234 | } | 238 | } |
235 | 239 | ||
236 | static inline struct event_format *find_cache_event(int type) | 240 | static inline |
241 | struct event_format *find_cache_event(struct pevent *pevent, int type) | ||
237 | { | 242 | { |
238 | static char ev_name[256]; | 243 | static char ev_name[256]; |
239 | struct event_format *event; | 244 | struct event_format *event; |
@@ -241,7 +246,7 @@ static inline struct event_format *find_cache_event(int type) | |||
241 | if (events[type]) | 246 | if (events[type]) |
242 | return events[type]; | 247 | return events[type]; |
243 | 248 | ||
244 | events[type] = event = trace_find_event(type); | 249 | events[type] = event = pevent_find_event(pevent, type); |
245 | if (!event) | 250 | if (!event) |
246 | return NULL; | 251 | return NULL; |
247 | 252 | ||
@@ -252,7 +257,8 @@ static inline struct event_format *find_cache_event(int type) | |||
252 | return event; | 257 | return event; |
253 | } | 258 | } |
254 | 259 | ||
255 | static void perl_process_tracepoint(union perf_event *pevent __unused, | 260 | static void perl_process_tracepoint(union perf_event *perf_event __unused, |
261 | struct pevent *pevent, | ||
256 | struct perf_sample *sample, | 262 | struct perf_sample *sample, |
257 | struct perf_evsel *evsel, | 263 | struct perf_evsel *evsel, |
258 | struct machine *machine __unused, | 264 | struct machine *machine __unused, |
@@ -275,13 +281,13 @@ static void perl_process_tracepoint(union perf_event *pevent __unused, | |||
275 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) | 281 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) |
276 | return; | 282 | return; |
277 | 283 | ||
278 | type = trace_parse_common_type(data); | 284 | type = trace_parse_common_type(pevent, data); |
279 | 285 | ||
280 | event = find_cache_event(type); | 286 | event = find_cache_event(pevent, type); |
281 | if (!event) | 287 | if (!event) |
282 | die("ug! no event found for type %d", type); | 288 | die("ug! no event found for type %d", type); |
283 | 289 | ||
284 | pid = trace_parse_common_pid(data); | 290 | pid = trace_parse_common_pid(pevent, data); |
285 | 291 | ||
286 | sprintf(handler, "%s::%s", event->system, event->name); | 292 | sprintf(handler, "%s::%s", event->system, event->name); |
287 | 293 | ||
@@ -314,7 +320,8 @@ static void perl_process_tracepoint(union perf_event *pevent __unused, | |||
314 | offset = field->offset; | 320 | offset = field->offset; |
315 | XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0))); | 321 | XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0))); |
316 | } else { /* FIELD_IS_NUMERIC */ | 322 | } else { /* FIELD_IS_NUMERIC */ |
317 | val = read_size(data + field->offset, field->size); | 323 | val = read_size(pevent, data + field->offset, |
324 | field->size); | ||
318 | if (field->flags & FIELD_IS_SIGNED) { | 325 | if (field->flags & FIELD_IS_SIGNED) { |
319 | XPUSHs(sv_2mortal(newSViv(val))); | 326 | XPUSHs(sv_2mortal(newSViv(val))); |
320 | } else { | 327 | } else { |
@@ -368,14 +375,15 @@ static void perl_process_event_generic(union perf_event *pevent __unused, | |||
368 | LEAVE; | 375 | LEAVE; |
369 | } | 376 | } |
370 | 377 | ||
371 | static void perl_process_event(union perf_event *pevent, | 378 | static void perl_process_event(union perf_event *event, |
379 | struct pevent *pevent, | ||
372 | struct perf_sample *sample, | 380 | struct perf_sample *sample, |
373 | struct perf_evsel *evsel, | 381 | struct perf_evsel *evsel, |
374 | struct machine *machine, | 382 | struct machine *machine, |
375 | struct thread *thread) | 383 | struct thread *thread) |
376 | { | 384 | { |
377 | perl_process_tracepoint(pevent, sample, evsel, machine, thread); | 385 | perl_process_tracepoint(event, pevent, sample, evsel, machine, thread); |
378 | perl_process_event_generic(pevent, sample, evsel, machine, thread); | 386 | perl_process_event_generic(event, sample, evsel, machine, thread); |
379 | } | 387 | } |
380 | 388 | ||
381 | static void run_start_sub(void) | 389 | static void run_start_sub(void) |
@@ -448,7 +456,7 @@ static int perl_stop_script(void) | |||
448 | return 0; | 456 | return 0; |
449 | } | 457 | } |
450 | 458 | ||
451 | static int perl_generate_script(const char *outfile) | 459 | static int perl_generate_script(struct pevent *pevent, const char *outfile) |
452 | { | 460 | { |
453 | struct event_format *event = NULL; | 461 | struct event_format *event = NULL; |
454 | struct format_field *f; | 462 | struct format_field *f; |
@@ -495,7 +503,7 @@ static int perl_generate_script(const char *outfile) | |||
495 | fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); | 503 | fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); |
496 | fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n"); | 504 | fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n"); |
497 | 505 | ||
498 | while ((event = trace_find_next_event(event))) { | 506 | while ((event = trace_find_next_event(pevent, event))) { |
499 | fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); | 507 | fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); |
500 | fprintf(ofp, "\tmy ("); | 508 | fprintf(ofp, "\tmy ("); |
501 | 509 | ||
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index acb9795286c4..ce4d1b0c3862 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -166,6 +166,10 @@ static void define_event_symbols(struct event_format *event, | |||
166 | define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name, | 166 | define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name, |
167 | cur_field_name); | 167 | cur_field_name); |
168 | break; | 168 | break; |
169 | case PRINT_HEX: | ||
170 | define_event_symbols(event, ev_name, args->hex.field); | ||
171 | define_event_symbols(event, ev_name, args->hex.size); | ||
172 | break; | ||
169 | case PRINT_STRING: | 173 | case PRINT_STRING: |
170 | break; | 174 | break; |
171 | case PRINT_TYPE: | 175 | case PRINT_TYPE: |
@@ -190,7 +194,8 @@ static void define_event_symbols(struct event_format *event, | |||
190 | define_event_symbols(event, ev_name, args->next); | 194 | define_event_symbols(event, ev_name, args->next); |
191 | } | 195 | } |
192 | 196 | ||
193 | static inline struct event_format *find_cache_event(int type) | 197 | static inline |
198 | struct event_format *find_cache_event(struct pevent *pevent, int type) | ||
194 | { | 199 | { |
195 | static char ev_name[256]; | 200 | static char ev_name[256]; |
196 | struct event_format *event; | 201 | struct event_format *event; |
@@ -198,7 +203,7 @@ static inline struct event_format *find_cache_event(int type) | |||
198 | if (events[type]) | 203 | if (events[type]) |
199 | return events[type]; | 204 | return events[type]; |
200 | 205 | ||
201 | events[type] = event = trace_find_event(type); | 206 | events[type] = event = pevent_find_event(pevent, type); |
202 | if (!event) | 207 | if (!event) |
203 | return NULL; | 208 | return NULL; |
204 | 209 | ||
@@ -209,7 +214,8 @@ static inline struct event_format *find_cache_event(int type) | |||
209 | return event; | 214 | return event; |
210 | } | 215 | } |
211 | 216 | ||
212 | static void python_process_event(union perf_event *pevent __unused, | 217 | static void python_process_event(union perf_event *perf_event __unused, |
218 | struct pevent *pevent, | ||
213 | struct perf_sample *sample, | 219 | struct perf_sample *sample, |
214 | struct perf_evsel *evsel __unused, | 220 | struct perf_evsel *evsel __unused, |
215 | struct machine *machine __unused, | 221 | struct machine *machine __unused, |
@@ -233,13 +239,13 @@ static void python_process_event(union perf_event *pevent __unused, | |||
233 | if (!t) | 239 | if (!t) |
234 | Py_FatalError("couldn't create Python tuple"); | 240 | Py_FatalError("couldn't create Python tuple"); |
235 | 241 | ||
236 | type = trace_parse_common_type(data); | 242 | type = trace_parse_common_type(pevent, data); |
237 | 243 | ||
238 | event = find_cache_event(type); | 244 | event = find_cache_event(pevent, type); |
239 | if (!event) | 245 | if (!event) |
240 | die("ug! no event found for type %d", type); | 246 | die("ug! no event found for type %d", type); |
241 | 247 | ||
242 | pid = trace_parse_common_pid(data); | 248 | pid = trace_parse_common_pid(pevent, data); |
243 | 249 | ||
244 | sprintf(handler_name, "%s__%s", event->system, event->name); | 250 | sprintf(handler_name, "%s__%s", event->system, event->name); |
245 | 251 | ||
@@ -284,7 +290,8 @@ static void python_process_event(union perf_event *pevent __unused, | |||
284 | offset = field->offset; | 290 | offset = field->offset; |
285 | obj = PyString_FromString((char *)data + offset); | 291 | obj = PyString_FromString((char *)data + offset); |
286 | } else { /* FIELD_IS_NUMERIC */ | 292 | } else { /* FIELD_IS_NUMERIC */ |
287 | val = read_size(data + field->offset, field->size); | 293 | val = read_size(pevent, data + field->offset, |
294 | field->size); | ||
288 | if (field->flags & FIELD_IS_SIGNED) { | 295 | if (field->flags & FIELD_IS_SIGNED) { |
289 | if ((long long)val >= LONG_MIN && | 296 | if ((long long)val >= LONG_MIN && |
290 | (long long)val <= LONG_MAX) | 297 | (long long)val <= LONG_MAX) |
@@ -438,7 +445,7 @@ out: | |||
438 | return err; | 445 | return err; |
439 | } | 446 | } |
440 | 447 | ||
441 | static int python_generate_script(const char *outfile) | 448 | static int python_generate_script(struct pevent *pevent, const char *outfile) |
442 | { | 449 | { |
443 | struct event_format *event = NULL; | 450 | struct event_format *event = NULL; |
444 | struct format_field *f; | 451 | struct format_field *f; |
@@ -487,7 +494,7 @@ static int python_generate_script(const char *outfile) | |||
487 | fprintf(ofp, "def trace_end():\n"); | 494 | fprintf(ofp, "def trace_end():\n"); |
488 | fprintf(ofp, "\tprint \"in trace_end\"\n\n"); | 495 | fprintf(ofp, "\tprint \"in trace_end\"\n\n"); |
489 | 496 | ||
490 | while ((event = trace_find_next_event(event))) { | 497 | while ((event = trace_find_next_event(pevent, event))) { |
491 | fprintf(ofp, "def %s__%s(", event->system, event->name); | 498 | fprintf(ofp, "def %s__%s(", event->system, event->name); |
492 | fprintf(ofp, "event_name, "); | 499 | fprintf(ofp, "event_name, "); |
493 | fprintf(ofp, "context, "); | 500 | fprintf(ofp, "context, "); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 56142d0fb8d7..8e485592ca20 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include "sort.h" | 14 | #include "sort.h" |
15 | #include "util.h" | 15 | #include "util.h" |
16 | #include "cpumap.h" | 16 | #include "cpumap.h" |
17 | #include "event-parse.h" | ||
17 | 18 | ||
18 | static int perf_session__open(struct perf_session *self, bool force) | 19 | static int perf_session__open(struct perf_session *self, bool force) |
19 | { | 20 | { |
@@ -289,7 +290,6 @@ struct branch_info *machine__resolve_bstack(struct machine *self, | |||
289 | } | 290 | } |
290 | 291 | ||
291 | int machine__resolve_callchain(struct machine *self, | 292 | int machine__resolve_callchain(struct machine *self, |
292 | struct perf_evsel *evsel __used, | ||
293 | struct thread *thread, | 293 | struct thread *thread, |
294 | struct ip_callchain *chain, | 294 | struct ip_callchain *chain, |
295 | struct symbol **parent) | 295 | struct symbol **parent) |
@@ -1449,7 +1449,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | |||
1449 | ret += hists__fprintf_nr_events(&session->hists, fp); | 1449 | ret += hists__fprintf_nr_events(&session->hists, fp); |
1450 | 1450 | ||
1451 | list_for_each_entry(pos, &session->evlist->entries, node) { | 1451 | list_for_each_entry(pos, &session->evlist->entries, node) { |
1452 | ret += fprintf(fp, "%s stats:\n", event_name(pos)); | 1452 | ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); |
1453 | ret += hists__fprintf_nr_events(&pos->hists, fp); | 1453 | ret += hists__fprintf_nr_events(&pos->hists, fp); |
1454 | } | 1454 | } |
1455 | 1455 | ||
@@ -1490,8 +1490,8 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
1490 | } | 1490 | } |
1491 | 1491 | ||
1492 | void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, | 1492 | void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, |
1493 | struct machine *machine, struct perf_evsel *evsel, | 1493 | struct machine *machine, int print_sym, |
1494 | int print_sym, int print_dso, int print_symoffset) | 1494 | int print_dso, int print_symoffset) |
1495 | { | 1495 | { |
1496 | struct addr_location al; | 1496 | struct addr_location al; |
1497 | struct callchain_cursor_node *node; | 1497 | struct callchain_cursor_node *node; |
@@ -1505,7 +1505,7 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, | |||
1505 | 1505 | ||
1506 | if (symbol_conf.use_callchain && sample->callchain) { | 1506 | if (symbol_conf.use_callchain && sample->callchain) { |
1507 | 1507 | ||
1508 | if (machine__resolve_callchain(machine, evsel, al.thread, | 1508 | if (machine__resolve_callchain(machine, al.thread, |
1509 | sample->callchain, NULL) != 0) { | 1509 | sample->callchain, NULL) != 0) { |
1510 | if (verbose) | 1510 | if (verbose) |
1511 | error("Failed to resolve callchain. Skipping\n"); | 1511 | error("Failed to resolve callchain. Skipping\n"); |
@@ -1611,3 +1611,58 @@ void perf_session__fprintf_info(struct perf_session *session, FILE *fp, | |||
1611 | perf_header__fprintf_info(session, fp, full); | 1611 | perf_header__fprintf_info(session, fp, full); |
1612 | fprintf(fp, "# ========\n#\n"); | 1612 | fprintf(fp, "# ========\n#\n"); |
1613 | } | 1613 | } |
1614 | |||
1615 | |||
1616 | int __perf_session__set_tracepoints_handlers(struct perf_session *session, | ||
1617 | const struct perf_evsel_str_handler *assocs, | ||
1618 | size_t nr_assocs) | ||
1619 | { | ||
1620 | struct perf_evlist *evlist = session->evlist; | ||
1621 | struct event_format *format; | ||
1622 | struct perf_evsel *evsel; | ||
1623 | char *tracepoint, *name; | ||
1624 | size_t i; | ||
1625 | int err; | ||
1626 | |||
1627 | for (i = 0; i < nr_assocs; i++) { | ||
1628 | err = -ENOMEM; | ||
1629 | tracepoint = strdup(assocs[i].name); | ||
1630 | if (tracepoint == NULL) | ||
1631 | goto out; | ||
1632 | |||
1633 | err = -ENOENT; | ||
1634 | name = strchr(tracepoint, ':'); | ||
1635 | if (name == NULL) | ||
1636 | goto out_free; | ||
1637 | |||
1638 | *name++ = '\0'; | ||
1639 | format = pevent_find_event_by_name(session->pevent, | ||
1640 | tracepoint, name); | ||
1641 | if (format == NULL) { | ||
1642 | /* | ||
1643 | * Adding a handler for an event not in the session, | ||
1644 | * just ignore it. | ||
1645 | */ | ||
1646 | goto next; | ||
1647 | } | ||
1648 | |||
1649 | evsel = perf_evlist__find_tracepoint_by_id(evlist, format->id); | ||
1650 | if (evsel == NULL) | ||
1651 | goto next; | ||
1652 | |||
1653 | err = -EEXIST; | ||
1654 | if (evsel->handler.func != NULL) | ||
1655 | goto out_free; | ||
1656 | evsel->handler.func = assocs[i].handler; | ||
1657 | next: | ||
1658 | free(tracepoint); | ||
1659 | } | ||
1660 | |||
1661 | err = 0; | ||
1662 | out: | ||
1663 | return err; | ||
1664 | |||
1665 | out_free: | ||
1666 | free(tracepoint); | ||
1667 | goto out; | ||
1668 | } | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 0c702e3f0a36..7c435bde6eb0 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -33,6 +33,7 @@ struct perf_session { | |||
33 | struct machine host_machine; | 33 | struct machine host_machine; |
34 | struct rb_root machines; | 34 | struct rb_root machines; |
35 | struct perf_evlist *evlist; | 35 | struct perf_evlist *evlist; |
36 | struct pevent *pevent; | ||
36 | /* | 37 | /* |
37 | * FIXME: Need to split this up further, we need global | 38 | * FIXME: Need to split this up further, we need global |
38 | * stats + per event stats. 'perf diff' also needs | 39 | * stats + per event stats. 'perf diff' also needs |
@@ -151,11 +152,20 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
151 | unsigned int type); | 152 | unsigned int type); |
152 | 153 | ||
153 | void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, | 154 | void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, |
154 | struct machine *machine, struct perf_evsel *evsel, | 155 | struct machine *machine, int print_sym, |
155 | int print_sym, int print_dso, int print_symoffset); | 156 | int print_dso, int print_symoffset); |
156 | 157 | ||
157 | int perf_session__cpu_bitmap(struct perf_session *session, | 158 | int perf_session__cpu_bitmap(struct perf_session *session, |
158 | const char *cpu_list, unsigned long *cpu_bitmap); | 159 | const char *cpu_list, unsigned long *cpu_bitmap); |
159 | 160 | ||
160 | void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full); | 161 | void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full); |
162 | |||
163 | struct perf_evsel_str_handler; | ||
164 | |||
165 | int __perf_session__set_tracepoints_handlers(struct perf_session *session, | ||
166 | const struct perf_evsel_str_handler *assocs, | ||
167 | size_t nr_assocs); | ||
168 | |||
169 | #define perf_session__set_tracepoints_handlers(session, array) \ | ||
170 | __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array)) | ||
161 | #endif /* __PERF_SESSION_H */ | 171 | #endif /* __PERF_SESSION_H */ |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index a27237430c5f..0f5a0a496bc4 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -241,6 +241,54 @@ struct sort_entry sort_sym = { | |||
241 | .se_width_idx = HISTC_SYMBOL, | 241 | .se_width_idx = HISTC_SYMBOL, |
242 | }; | 242 | }; |
243 | 243 | ||
244 | /* --sort srcline */ | ||
245 | |||
246 | static int64_t | ||
247 | sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) | ||
248 | { | ||
249 | return (int64_t)(right->ip - left->ip); | ||
250 | } | ||
251 | |||
252 | static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, | ||
253 | size_t size, unsigned int width __used) | ||
254 | { | ||
255 | FILE *fp; | ||
256 | char cmd[PATH_MAX + 2], *path = self->srcline, *nl; | ||
257 | size_t line_len; | ||
258 | |||
259 | if (path != NULL) | ||
260 | goto out_path; | ||
261 | |||
262 | snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64, | ||
263 | self->ms.map->dso->long_name, self->ip); | ||
264 | fp = popen(cmd, "r"); | ||
265 | if (!fp) | ||
266 | goto out_ip; | ||
267 | |||
268 | if (getline(&path, &line_len, fp) < 0 || !line_len) | ||
269 | goto out_ip; | ||
270 | fclose(fp); | ||
271 | self->srcline = strdup(path); | ||
272 | if (self->srcline == NULL) | ||
273 | goto out_ip; | ||
274 | |||
275 | nl = strchr(self->srcline, '\n'); | ||
276 | if (nl != NULL) | ||
277 | *nl = '\0'; | ||
278 | path = self->srcline; | ||
279 | out_path: | ||
280 | return repsep_snprintf(bf, size, "%s", path); | ||
281 | out_ip: | ||
282 | return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip); | ||
283 | } | ||
284 | |||
285 | struct sort_entry sort_srcline = { | ||
286 | .se_header = "Source:Line", | ||
287 | .se_cmp = sort__srcline_cmp, | ||
288 | .se_snprintf = hist_entry__srcline_snprintf, | ||
289 | .se_width_idx = HISTC_SRCLINE, | ||
290 | }; | ||
291 | |||
244 | /* --sort parent */ | 292 | /* --sort parent */ |
245 | 293 | ||
246 | static int64_t | 294 | static int64_t |
@@ -439,6 +487,7 @@ static struct sort_dimension sort_dimensions[] = { | |||
439 | DIM(SORT_PARENT, "parent", sort_parent), | 487 | DIM(SORT_PARENT, "parent", sort_parent), |
440 | DIM(SORT_CPU, "cpu", sort_cpu), | 488 | DIM(SORT_CPU, "cpu", sort_cpu), |
441 | DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), | 489 | DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), |
490 | DIM(SORT_SRCLINE, "srcline", sort_srcline), | ||
442 | }; | 491 | }; |
443 | 492 | ||
444 | int sort_dimension__add(const char *tok) | 493 | int sort_dimension__add(const char *tok) |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 472aa5a63a58..e724b26acd51 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -71,6 +71,7 @@ struct hist_entry { | |||
71 | char level; | 71 | char level; |
72 | bool used; | 72 | bool used; |
73 | u8 filtered; | 73 | u8 filtered; |
74 | char *srcline; | ||
74 | struct symbol *parent; | 75 | struct symbol *parent; |
75 | union { | 76 | union { |
76 | unsigned long position; | 77 | unsigned long position; |
@@ -93,6 +94,7 @@ enum sort_type { | |||
93 | SORT_SYM_FROM, | 94 | SORT_SYM_FROM, |
94 | SORT_SYM_TO, | 95 | SORT_SYM_TO, |
95 | SORT_MISPREDICT, | 96 | SORT_MISPREDICT, |
97 | SORT_SRCLINE, | ||
96 | }; | 98 | }; |
97 | 99 | ||
98 | /* | 100 | /* |
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index d5836382ff2c..199bc4d8905d 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c | |||
@@ -313,3 +313,25 @@ int strtailcmp(const char *s1, const char *s2) | |||
313 | return 0; | 313 | return 0; |
314 | } | 314 | } |
315 | 315 | ||
316 | /** | ||
317 | * rtrim - Removes trailing whitespace from @s. | ||
318 | * @s: The string to be stripped. | ||
319 | * | ||
320 | * Note that the first trailing whitespace is replaced with a %NUL-terminator | ||
321 | * in the given string @s. Returns @s. | ||
322 | */ | ||
323 | char *rtrim(char *s) | ||
324 | { | ||
325 | size_t size = strlen(s); | ||
326 | char *end; | ||
327 | |||
328 | if (!size) | ||
329 | return s; | ||
330 | |||
331 | end = s + size - 1; | ||
332 | while (end >= s && isspace(*end)) | ||
333 | end--; | ||
334 | *(end + 1) = '\0'; | ||
335 | |||
336 | return s; | ||
337 | } | ||
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 3e2e5ea0f03f..50958bbeb26a 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -1478,14 +1478,31 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) | |||
1478 | goto out; | 1478 | goto out; |
1479 | } | 1479 | } |
1480 | 1480 | ||
1481 | sec = elf_section_by_name(elf, &ehdr, &shdr, | 1481 | /* |
1482 | ".note.gnu.build-id", NULL); | 1482 | * Check following sections for notes: |
1483 | if (sec == NULL) { | 1483 | * '.note.gnu.build-id' |
1484 | * '.notes' | ||
1485 | * '.note' (VDSO specific) | ||
1486 | */ | ||
1487 | do { | ||
1488 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
1489 | ".note.gnu.build-id", NULL); | ||
1490 | if (sec) | ||
1491 | break; | ||
1492 | |||
1484 | sec = elf_section_by_name(elf, &ehdr, &shdr, | 1493 | sec = elf_section_by_name(elf, &ehdr, &shdr, |
1485 | ".notes", NULL); | 1494 | ".notes", NULL); |
1486 | if (sec == NULL) | 1495 | if (sec) |
1487 | goto out; | 1496 | break; |
1488 | } | 1497 | |
1498 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
1499 | ".note", NULL); | ||
1500 | if (sec) | ||
1501 | break; | ||
1502 | |||
1503 | return err; | ||
1504 | |||
1505 | } while (0); | ||
1489 | 1506 | ||
1490 | data = elf_getdata(sec, NULL); | 1507 | data = elf_getdata(sec, NULL); |
1491 | if (data == NULL) | 1508 | if (data == NULL) |
@@ -1590,11 +1607,62 @@ out: | |||
1590 | return err; | 1607 | return err; |
1591 | } | 1608 | } |
1592 | 1609 | ||
1610 | static int filename__read_debuglink(const char *filename, | ||
1611 | char *debuglink, size_t size) | ||
1612 | { | ||
1613 | int fd, err = -1; | ||
1614 | Elf *elf; | ||
1615 | GElf_Ehdr ehdr; | ||
1616 | GElf_Shdr shdr; | ||
1617 | Elf_Data *data; | ||
1618 | Elf_Scn *sec; | ||
1619 | Elf_Kind ek; | ||
1620 | |||
1621 | fd = open(filename, O_RDONLY); | ||
1622 | if (fd < 0) | ||
1623 | goto out; | ||
1624 | |||
1625 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
1626 | if (elf == NULL) { | ||
1627 | pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); | ||
1628 | goto out_close; | ||
1629 | } | ||
1630 | |||
1631 | ek = elf_kind(elf); | ||
1632 | if (ek != ELF_K_ELF) | ||
1633 | goto out_close; | ||
1634 | |||
1635 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
1636 | pr_err("%s: cannot get elf header.\n", __func__); | ||
1637 | goto out_close; | ||
1638 | } | ||
1639 | |||
1640 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
1641 | ".gnu_debuglink", NULL); | ||
1642 | if (sec == NULL) | ||
1643 | goto out_close; | ||
1644 | |||
1645 | data = elf_getdata(sec, NULL); | ||
1646 | if (data == NULL) | ||
1647 | goto out_close; | ||
1648 | |||
1649 | /* the start of this section is a zero-terminated string */ | ||
1650 | strncpy(debuglink, data->d_buf, size); | ||
1651 | |||
1652 | elf_end(elf); | ||
1653 | |||
1654 | out_close: | ||
1655 | close(fd); | ||
1656 | out: | ||
1657 | return err; | ||
1658 | } | ||
1659 | |||
1593 | char dso__symtab_origin(const struct dso *dso) | 1660 | char dso__symtab_origin(const struct dso *dso) |
1594 | { | 1661 | { |
1595 | static const char origin[] = { | 1662 | static const char origin[] = { |
1596 | [SYMTAB__KALLSYMS] = 'k', | 1663 | [SYMTAB__KALLSYMS] = 'k', |
1597 | [SYMTAB__JAVA_JIT] = 'j', | 1664 | [SYMTAB__JAVA_JIT] = 'j', |
1665 | [SYMTAB__DEBUGLINK] = 'l', | ||
1598 | [SYMTAB__BUILD_ID_CACHE] = 'B', | 1666 | [SYMTAB__BUILD_ID_CACHE] = 'B', |
1599 | [SYMTAB__FEDORA_DEBUGINFO] = 'f', | 1667 | [SYMTAB__FEDORA_DEBUGINFO] = 'f', |
1600 | [SYMTAB__UBUNTU_DEBUGINFO] = 'u', | 1668 | [SYMTAB__UBUNTU_DEBUGINFO] = 'u', |
@@ -1662,10 +1730,22 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1662 | */ | 1730 | */ |
1663 | want_symtab = 1; | 1731 | want_symtab = 1; |
1664 | restart: | 1732 | restart: |
1665 | for (dso->symtab_type = SYMTAB__BUILD_ID_CACHE; | 1733 | for (dso->symtab_type = SYMTAB__DEBUGLINK; |
1666 | dso->symtab_type != SYMTAB__NOT_FOUND; | 1734 | dso->symtab_type != SYMTAB__NOT_FOUND; |
1667 | dso->symtab_type++) { | 1735 | dso->symtab_type++) { |
1668 | switch (dso->symtab_type) { | 1736 | switch (dso->symtab_type) { |
1737 | case SYMTAB__DEBUGLINK: { | ||
1738 | char *debuglink; | ||
1739 | strncpy(name, dso->long_name, size); | ||
1740 | debuglink = name + dso->long_name_len; | ||
1741 | while (debuglink != name && *debuglink != '/') | ||
1742 | debuglink--; | ||
1743 | if (*debuglink == '/') | ||
1744 | debuglink++; | ||
1745 | filename__read_debuglink(dso->long_name, debuglink, | ||
1746 | size - (debuglink - name)); | ||
1747 | } | ||
1748 | break; | ||
1669 | case SYMTAB__BUILD_ID_CACHE: | 1749 | case SYMTAB__BUILD_ID_CACHE: |
1670 | /* skip the locally configured cache if a symfs is given */ | 1750 | /* skip the locally configured cache if a symfs is given */ |
1671 | if (symbol_conf.symfs[0] || | 1751 | if (symbol_conf.symfs[0] || |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index af0752b1aca1..a884b99017f0 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -257,6 +257,7 @@ enum symtab_type { | |||
257 | SYMTAB__KALLSYMS = 0, | 257 | SYMTAB__KALLSYMS = 0, |
258 | SYMTAB__GUEST_KALLSYMS, | 258 | SYMTAB__GUEST_KALLSYMS, |
259 | SYMTAB__JAVA_JIT, | 259 | SYMTAB__JAVA_JIT, |
260 | SYMTAB__DEBUGLINK, | ||
260 | SYMTAB__BUILD_ID_CACHE, | 261 | SYMTAB__BUILD_ID_CACHE, |
261 | SYMTAB__FEDORA_DEBUGINFO, | 262 | SYMTAB__FEDORA_DEBUGINFO, |
262 | SYMTAB__UBUNTU_DEBUGINFO, | 263 | SYMTAB__UBUNTU_DEBUGINFO, |
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index abe0e8e95068..7eeebcee291c 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c | |||
@@ -65,7 +65,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
65 | top->freq ? "Hz" : ""); | 65 | top->freq ? "Hz" : ""); |
66 | } | 66 | } |
67 | 67 | ||
68 | ret += SNPRINTF(bf + ret, size - ret, "%s", event_name(top->sym_evsel)); | 68 | ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel)); |
69 | 69 | ||
70 | ret += SNPRINTF(bf + ret, size - ret, "], "); | 70 | ret += SNPRINTF(bf + ret, size - ret, "], "); |
71 | 71 | ||
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 5dd3b5ec8411..0715c843c2e7 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -32,29 +32,25 @@ int header_page_size_size; | |||
32 | int header_page_ts_size; | 32 | int header_page_ts_size; |
33 | int header_page_data_offset; | 33 | int header_page_data_offset; |
34 | 34 | ||
35 | struct pevent *perf_pevent; | ||
36 | static struct pevent *pevent; | ||
37 | |||
38 | bool latency_format; | 35 | bool latency_format; |
39 | 36 | ||
40 | int read_trace_init(int file_bigendian, int host_bigendian) | 37 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian) |
41 | { | 38 | { |
42 | if (pevent) | 39 | struct pevent *pevent = pevent_alloc(); |
43 | return 0; | ||
44 | |||
45 | perf_pevent = pevent_alloc(); | ||
46 | pevent = perf_pevent; | ||
47 | 40 | ||
48 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); | 41 | if (pevent != NULL) { |
49 | pevent_set_file_bigendian(pevent, file_bigendian); | 42 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); |
50 | pevent_set_host_bigendian(pevent, host_bigendian); | 43 | pevent_set_file_bigendian(pevent, file_bigendian); |
44 | pevent_set_host_bigendian(pevent, host_bigendian); | ||
45 | } | ||
51 | 46 | ||
52 | return 0; | 47 | return pevent; |
53 | } | 48 | } |
54 | 49 | ||
55 | static int get_common_field(struct scripting_context *context, | 50 | static int get_common_field(struct scripting_context *context, |
56 | int *offset, int *size, const char *type) | 51 | int *offset, int *size, const char *type) |
57 | { | 52 | { |
53 | struct pevent *pevent = context->pevent; | ||
58 | struct event_format *event; | 54 | struct event_format *event; |
59 | struct format_field *field; | 55 | struct format_field *field; |
60 | 56 | ||
@@ -150,7 +146,7 @@ void *raw_field_ptr(struct event_format *event, const char *name, void *data) | |||
150 | return data + field->offset; | 146 | return data + field->offset; |
151 | } | 147 | } |
152 | 148 | ||
153 | int trace_parse_common_type(void *data) | 149 | int trace_parse_common_type(struct pevent *pevent, void *data) |
154 | { | 150 | { |
155 | struct pevent_record record; | 151 | struct pevent_record record; |
156 | 152 | ||
@@ -158,7 +154,7 @@ int trace_parse_common_type(void *data) | |||
158 | return pevent_data_type(pevent, &record); | 154 | return pevent_data_type(pevent, &record); |
159 | } | 155 | } |
160 | 156 | ||
161 | int trace_parse_common_pid(void *data) | 157 | int trace_parse_common_pid(struct pevent *pevent, void *data) |
162 | { | 158 | { |
163 | struct pevent_record record; | 159 | struct pevent_record record; |
164 | 160 | ||
@@ -166,27 +162,21 @@ int trace_parse_common_pid(void *data) | |||
166 | return pevent_data_pid(pevent, &record); | 162 | return pevent_data_pid(pevent, &record); |
167 | } | 163 | } |
168 | 164 | ||
169 | unsigned long long read_size(void *ptr, int size) | 165 | unsigned long long read_size(struct pevent *pevent, void *ptr, int size) |
170 | { | 166 | { |
171 | return pevent_read_number(pevent, ptr, size); | 167 | return pevent_read_number(pevent, ptr, size); |
172 | } | 168 | } |
173 | 169 | ||
174 | struct event_format *trace_find_event(int type) | 170 | void print_trace_event(struct pevent *pevent, int cpu, void *data, int size) |
175 | { | ||
176 | return pevent_find_event(pevent, type); | ||
177 | } | ||
178 | |||
179 | |||
180 | void print_trace_event(int cpu, void *data, int size) | ||
181 | { | 171 | { |
182 | struct event_format *event; | 172 | struct event_format *event; |
183 | struct pevent_record record; | 173 | struct pevent_record record; |
184 | struct trace_seq s; | 174 | struct trace_seq s; |
185 | int type; | 175 | int type; |
186 | 176 | ||
187 | type = trace_parse_common_type(data); | 177 | type = trace_parse_common_type(pevent, data); |
188 | 178 | ||
189 | event = trace_find_event(type); | 179 | event = pevent_find_event(pevent, type); |
190 | if (!event) { | 180 | if (!event) { |
191 | warning("ug! no event found for type %d", type); | 181 | warning("ug! no event found for type %d", type); |
192 | return; | 182 | return; |
@@ -202,8 +192,8 @@ void print_trace_event(int cpu, void *data, int size) | |||
202 | trace_seq_do_printf(&s); | 192 | trace_seq_do_printf(&s); |
203 | } | 193 | } |
204 | 194 | ||
205 | void print_event(int cpu, void *data, int size, unsigned long long nsecs, | 195 | void print_event(struct pevent *pevent, int cpu, void *data, int size, |
206 | char *comm) | 196 | unsigned long long nsecs, char *comm) |
207 | { | 197 | { |
208 | struct pevent_record record; | 198 | struct pevent_record record; |
209 | struct trace_seq s; | 199 | struct trace_seq s; |
@@ -226,7 +216,8 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs, | |||
226 | printf("\n"); | 216 | printf("\n"); |
227 | } | 217 | } |
228 | 218 | ||
229 | void parse_proc_kallsyms(char *file, unsigned int size __unused) | 219 | void parse_proc_kallsyms(struct pevent *pevent, |
220 | char *file, unsigned int size __unused) | ||
230 | { | 221 | { |
231 | unsigned long long addr; | 222 | unsigned long long addr; |
232 | char *func; | 223 | char *func; |
@@ -257,7 +248,8 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused) | |||
257 | } | 248 | } |
258 | } | 249 | } |
259 | 250 | ||
260 | void parse_ftrace_printk(char *file, unsigned int size __unused) | 251 | void parse_ftrace_printk(struct pevent *pevent, |
252 | char *file, unsigned int size __unused) | ||
261 | { | 253 | { |
262 | unsigned long long addr; | 254 | unsigned long long addr; |
263 | char *printk; | 255 | char *printk; |
@@ -281,17 +273,19 @@ void parse_ftrace_printk(char *file, unsigned int size __unused) | |||
281 | } | 273 | } |
282 | } | 274 | } |
283 | 275 | ||
284 | int parse_ftrace_file(char *buf, unsigned long size) | 276 | int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size) |
285 | { | 277 | { |
286 | return pevent_parse_event(pevent, buf, size, "ftrace"); | 278 | return pevent_parse_event(pevent, buf, size, "ftrace"); |
287 | } | 279 | } |
288 | 280 | ||
289 | int parse_event_file(char *buf, unsigned long size, char *sys) | 281 | int parse_event_file(struct pevent *pevent, |
282 | char *buf, unsigned long size, char *sys) | ||
290 | { | 283 | { |
291 | return pevent_parse_event(pevent, buf, size, sys); | 284 | return pevent_parse_event(pevent, buf, size, sys); |
292 | } | 285 | } |
293 | 286 | ||
294 | struct event_format *trace_find_next_event(struct event_format *event) | 287 | struct event_format *trace_find_next_event(struct pevent *pevent, |
288 | struct event_format *event) | ||
295 | { | 289 | { |
296 | static int idx; | 290 | static int idx; |
297 | 291 | ||
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index f097e0dd6c5c..719ed74a8565 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -114,20 +114,20 @@ static void skip(int size) | |||
114 | }; | 114 | }; |
115 | } | 115 | } |
116 | 116 | ||
117 | static unsigned int read4(void) | 117 | static unsigned int read4(struct pevent *pevent) |
118 | { | 118 | { |
119 | unsigned int data; | 119 | unsigned int data; |
120 | 120 | ||
121 | read_or_die(&data, 4); | 121 | read_or_die(&data, 4); |
122 | return __data2host4(perf_pevent, data); | 122 | return __data2host4(pevent, data); |
123 | } | 123 | } |
124 | 124 | ||
125 | static unsigned long long read8(void) | 125 | static unsigned long long read8(struct pevent *pevent) |
126 | { | 126 | { |
127 | unsigned long long data; | 127 | unsigned long long data; |
128 | 128 | ||
129 | read_or_die(&data, 8); | 129 | read_or_die(&data, 8); |
130 | return __data2host8(perf_pevent, data); | 130 | return __data2host8(pevent, data); |
131 | } | 131 | } |
132 | 132 | ||
133 | static char *read_string(void) | 133 | static char *read_string(void) |
@@ -168,12 +168,12 @@ static char *read_string(void) | |||
168 | return str; | 168 | return str; |
169 | } | 169 | } |
170 | 170 | ||
171 | static void read_proc_kallsyms(void) | 171 | static void read_proc_kallsyms(struct pevent *pevent) |
172 | { | 172 | { |
173 | unsigned int size; | 173 | unsigned int size; |
174 | char *buf; | 174 | char *buf; |
175 | 175 | ||
176 | size = read4(); | 176 | size = read4(pevent); |
177 | if (!size) | 177 | if (!size) |
178 | return; | 178 | return; |
179 | 179 | ||
@@ -181,29 +181,29 @@ static void read_proc_kallsyms(void) | |||
181 | read_or_die(buf, size); | 181 | read_or_die(buf, size); |
182 | buf[size] = '\0'; | 182 | buf[size] = '\0'; |
183 | 183 | ||
184 | parse_proc_kallsyms(buf, size); | 184 | parse_proc_kallsyms(pevent, buf, size); |
185 | 185 | ||
186 | free(buf); | 186 | free(buf); |
187 | } | 187 | } |
188 | 188 | ||
189 | static void read_ftrace_printk(void) | 189 | static void read_ftrace_printk(struct pevent *pevent) |
190 | { | 190 | { |
191 | unsigned int size; | 191 | unsigned int size; |
192 | char *buf; | 192 | char *buf; |
193 | 193 | ||
194 | size = read4(); | 194 | size = read4(pevent); |
195 | if (!size) | 195 | if (!size) |
196 | return; | 196 | return; |
197 | 197 | ||
198 | buf = malloc_or_die(size); | 198 | buf = malloc_or_die(size); |
199 | read_or_die(buf, size); | 199 | read_or_die(buf, size); |
200 | 200 | ||
201 | parse_ftrace_printk(buf, size); | 201 | parse_ftrace_printk(pevent, buf, size); |
202 | 202 | ||
203 | free(buf); | 203 | free(buf); |
204 | } | 204 | } |
205 | 205 | ||
206 | static void read_header_files(void) | 206 | static void read_header_files(struct pevent *pevent) |
207 | { | 207 | { |
208 | unsigned long long size; | 208 | unsigned long long size; |
209 | char *header_event; | 209 | char *header_event; |
@@ -214,7 +214,7 @@ static void read_header_files(void) | |||
214 | if (memcmp(buf, "header_page", 12) != 0) | 214 | if (memcmp(buf, "header_page", 12) != 0) |
215 | die("did not read header page"); | 215 | die("did not read header page"); |
216 | 216 | ||
217 | size = read8(); | 217 | size = read8(pevent); |
218 | skip(size); | 218 | skip(size); |
219 | 219 | ||
220 | /* | 220 | /* |
@@ -227,47 +227,48 @@ static void read_header_files(void) | |||
227 | if (memcmp(buf, "header_event", 13) != 0) | 227 | if (memcmp(buf, "header_event", 13) != 0) |
228 | die("did not read header event"); | 228 | die("did not read header event"); |
229 | 229 | ||
230 | size = read8(); | 230 | size = read8(pevent); |
231 | header_event = malloc_or_die(size); | 231 | header_event = malloc_or_die(size); |
232 | read_or_die(header_event, size); | 232 | read_or_die(header_event, size); |
233 | free(header_event); | 233 | free(header_event); |
234 | } | 234 | } |
235 | 235 | ||
236 | static void read_ftrace_file(unsigned long long size) | 236 | static void read_ftrace_file(struct pevent *pevent, unsigned long long size) |
237 | { | 237 | { |
238 | char *buf; | 238 | char *buf; |
239 | 239 | ||
240 | buf = malloc_or_die(size); | 240 | buf = malloc_or_die(size); |
241 | read_or_die(buf, size); | 241 | read_or_die(buf, size); |
242 | parse_ftrace_file(buf, size); | 242 | parse_ftrace_file(pevent, buf, size); |
243 | free(buf); | 243 | free(buf); |
244 | } | 244 | } |
245 | 245 | ||
246 | static void read_event_file(char *sys, unsigned long long size) | 246 | static void read_event_file(struct pevent *pevent, char *sys, |
247 | unsigned long long size) | ||
247 | { | 248 | { |
248 | char *buf; | 249 | char *buf; |
249 | 250 | ||
250 | buf = malloc_or_die(size); | 251 | buf = malloc_or_die(size); |
251 | read_or_die(buf, size); | 252 | read_or_die(buf, size); |
252 | parse_event_file(buf, size, sys); | 253 | parse_event_file(pevent, buf, size, sys); |
253 | free(buf); | 254 | free(buf); |
254 | } | 255 | } |
255 | 256 | ||
256 | static void read_ftrace_files(void) | 257 | static void read_ftrace_files(struct pevent *pevent) |
257 | { | 258 | { |
258 | unsigned long long size; | 259 | unsigned long long size; |
259 | int count; | 260 | int count; |
260 | int i; | 261 | int i; |
261 | 262 | ||
262 | count = read4(); | 263 | count = read4(pevent); |
263 | 264 | ||
264 | for (i = 0; i < count; i++) { | 265 | for (i = 0; i < count; i++) { |
265 | size = read8(); | 266 | size = read8(pevent); |
266 | read_ftrace_file(size); | 267 | read_ftrace_file(pevent, size); |
267 | } | 268 | } |
268 | } | 269 | } |
269 | 270 | ||
270 | static void read_event_files(void) | 271 | static void read_event_files(struct pevent *pevent) |
271 | { | 272 | { |
272 | unsigned long long size; | 273 | unsigned long long size; |
273 | char *sys; | 274 | char *sys; |
@@ -275,15 +276,15 @@ static void read_event_files(void) | |||
275 | int count; | 276 | int count; |
276 | int i,x; | 277 | int i,x; |
277 | 278 | ||
278 | systems = read4(); | 279 | systems = read4(pevent); |
279 | 280 | ||
280 | for (i = 0; i < systems; i++) { | 281 | for (i = 0; i < systems; i++) { |
281 | sys = read_string(); | 282 | sys = read_string(); |
282 | 283 | ||
283 | count = read4(); | 284 | count = read4(pevent); |
284 | for (x=0; x < count; x++) { | 285 | for (x=0; x < count; x++) { |
285 | size = read8(); | 286 | size = read8(pevent); |
286 | read_event_file(sys, size); | 287 | read_event_file(pevent, sys, size); |
287 | } | 288 | } |
288 | } | 289 | } |
289 | } | 290 | } |
@@ -377,7 +378,7 @@ static int calc_index(void *ptr, int cpu) | |||
377 | return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; | 378 | return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; |
378 | } | 379 | } |
379 | 380 | ||
380 | struct pevent_record *trace_peek_data(int cpu) | 381 | struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu) |
381 | { | 382 | { |
382 | struct pevent_record *data; | 383 | struct pevent_record *data; |
383 | void *page = cpu_data[cpu].page; | 384 | void *page = cpu_data[cpu].page; |
@@ -399,15 +400,15 @@ struct pevent_record *trace_peek_data(int cpu) | |||
399 | /* FIXME: handle header page */ | 400 | /* FIXME: handle header page */ |
400 | if (header_page_ts_size != 8) | 401 | if (header_page_ts_size != 8) |
401 | die("expected a long long type for timestamp"); | 402 | die("expected a long long type for timestamp"); |
402 | cpu_data[cpu].timestamp = data2host8(perf_pevent, ptr); | 403 | cpu_data[cpu].timestamp = data2host8(pevent, ptr); |
403 | ptr += 8; | 404 | ptr += 8; |
404 | switch (header_page_size_size) { | 405 | switch (header_page_size_size) { |
405 | case 4: | 406 | case 4: |
406 | cpu_data[cpu].page_size = data2host4(perf_pevent, ptr); | 407 | cpu_data[cpu].page_size = data2host4(pevent, ptr); |
407 | ptr += 4; | 408 | ptr += 4; |
408 | break; | 409 | break; |
409 | case 8: | 410 | case 8: |
410 | cpu_data[cpu].page_size = data2host8(perf_pevent, ptr); | 411 | cpu_data[cpu].page_size = data2host8(pevent, ptr); |
411 | ptr += 8; | 412 | ptr += 8; |
412 | break; | 413 | break; |
413 | default: | 414 | default: |
@@ -421,10 +422,10 @@ read_again: | |||
421 | 422 | ||
422 | if (idx >= cpu_data[cpu].page_size) { | 423 | if (idx >= cpu_data[cpu].page_size) { |
423 | get_next_page(cpu); | 424 | get_next_page(cpu); |
424 | return trace_peek_data(cpu); | 425 | return trace_peek_data(pevent, cpu); |
425 | } | 426 | } |
426 | 427 | ||
427 | type_len_ts = data2host4(perf_pevent, ptr); | 428 | type_len_ts = data2host4(pevent, ptr); |
428 | ptr += 4; | 429 | ptr += 4; |
429 | 430 | ||
430 | type_len = type_len4host(type_len_ts); | 431 | type_len = type_len4host(type_len_ts); |
@@ -434,14 +435,14 @@ read_again: | |||
434 | case RINGBUF_TYPE_PADDING: | 435 | case RINGBUF_TYPE_PADDING: |
435 | if (!delta) | 436 | if (!delta) |
436 | die("error, hit unexpected end of page"); | 437 | die("error, hit unexpected end of page"); |
437 | length = data2host4(perf_pevent, ptr); | 438 | length = data2host4(pevent, ptr); |
438 | ptr += 4; | 439 | ptr += 4; |
439 | length *= 4; | 440 | length *= 4; |
440 | ptr += length; | 441 | ptr += length; |
441 | goto read_again; | 442 | goto read_again; |
442 | 443 | ||
443 | case RINGBUF_TYPE_TIME_EXTEND: | 444 | case RINGBUF_TYPE_TIME_EXTEND: |
444 | extend = data2host4(perf_pevent, ptr); | 445 | extend = data2host4(pevent, ptr); |
445 | ptr += 4; | 446 | ptr += 4; |
446 | extend <<= TS_SHIFT; | 447 | extend <<= TS_SHIFT; |
447 | extend += delta; | 448 | extend += delta; |
@@ -452,7 +453,7 @@ read_again: | |||
452 | ptr += 12; | 453 | ptr += 12; |
453 | break; | 454 | break; |
454 | case 0: | 455 | case 0: |
455 | length = data2host4(perf_pevent, ptr); | 456 | length = data2host4(pevent, ptr); |
456 | ptr += 4; | 457 | ptr += 4; |
457 | die("here! length=%d", length); | 458 | die("here! length=%d", length); |
458 | break; | 459 | break; |
@@ -477,17 +478,17 @@ read_again: | |||
477 | return data; | 478 | return data; |
478 | } | 479 | } |
479 | 480 | ||
480 | struct pevent_record *trace_read_data(int cpu) | 481 | struct pevent_record *trace_read_data(struct pevent *pevent, int cpu) |
481 | { | 482 | { |
482 | struct pevent_record *data; | 483 | struct pevent_record *data; |
483 | 484 | ||
484 | data = trace_peek_data(cpu); | 485 | data = trace_peek_data(pevent, cpu); |
485 | cpu_data[cpu].next = NULL; | 486 | cpu_data[cpu].next = NULL; |
486 | 487 | ||
487 | return data; | 488 | return data; |
488 | } | 489 | } |
489 | 490 | ||
490 | ssize_t trace_report(int fd, bool __repipe) | 491 | ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) |
491 | { | 492 | { |
492 | char buf[BUFSIZ]; | 493 | char buf[BUFSIZ]; |
493 | char test[] = { 23, 8, 68 }; | 494 | char test[] = { 23, 8, 68 }; |
@@ -519,30 +520,32 @@ ssize_t trace_report(int fd, bool __repipe) | |||
519 | file_bigendian = buf[0]; | 520 | file_bigendian = buf[0]; |
520 | host_bigendian = bigendian(); | 521 | host_bigendian = bigendian(); |
521 | 522 | ||
522 | read_trace_init(file_bigendian, host_bigendian); | 523 | *ppevent = read_trace_init(file_bigendian, host_bigendian); |
524 | if (*ppevent == NULL) | ||
525 | die("read_trace_init failed"); | ||
523 | 526 | ||
524 | read_or_die(buf, 1); | 527 | read_or_die(buf, 1); |
525 | long_size = buf[0]; | 528 | long_size = buf[0]; |
526 | 529 | ||
527 | page_size = read4(); | 530 | page_size = read4(*ppevent); |
528 | 531 | ||
529 | read_header_files(); | 532 | read_header_files(*ppevent); |
530 | 533 | ||
531 | read_ftrace_files(); | 534 | read_ftrace_files(*ppevent); |
532 | read_event_files(); | 535 | read_event_files(*ppevent); |
533 | read_proc_kallsyms(); | 536 | read_proc_kallsyms(*ppevent); |
534 | read_ftrace_printk(); | 537 | read_ftrace_printk(*ppevent); |
535 | 538 | ||
536 | size = calc_data_size - 1; | 539 | size = calc_data_size - 1; |
537 | calc_data_size = 0; | 540 | calc_data_size = 0; |
538 | repipe = false; | 541 | repipe = false; |
539 | 542 | ||
540 | if (show_funcs) { | 543 | if (show_funcs) { |
541 | pevent_print_funcs(perf_pevent); | 544 | pevent_print_funcs(*ppevent); |
542 | return size; | 545 | return size; |
543 | } | 546 | } |
544 | if (show_printk) { | 547 | if (show_printk) { |
545 | pevent_print_printk(perf_pevent); | 548 | pevent_print_printk(*ppevent); |
546 | return size; | 549 | return size; |
547 | } | 550 | } |
548 | 551 | ||
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index 18ae6c1831d3..474aa7a7df43 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c | |||
@@ -36,6 +36,7 @@ static int stop_script_unsupported(void) | |||
36 | } | 36 | } |
37 | 37 | ||
38 | static void process_event_unsupported(union perf_event *event __unused, | 38 | static void process_event_unsupported(union perf_event *event __unused, |
39 | struct pevent *pevent __unused, | ||
39 | struct perf_sample *sample __unused, | 40 | struct perf_sample *sample __unused, |
40 | struct perf_evsel *evsel __unused, | 41 | struct perf_evsel *evsel __unused, |
41 | struct machine *machine __unused, | 42 | struct machine *machine __unused, |
@@ -61,7 +62,8 @@ static int python_start_script_unsupported(const char *script __unused, | |||
61 | return -1; | 62 | return -1; |
62 | } | 63 | } |
63 | 64 | ||
64 | static int python_generate_script_unsupported(const char *outfile __unused) | 65 | static int python_generate_script_unsupported(struct pevent *pevent __unused, |
66 | const char *outfile __unused) | ||
65 | { | 67 | { |
66 | print_python_unsupported_msg(); | 68 | print_python_unsupported_msg(); |
67 | 69 | ||
@@ -122,7 +124,8 @@ static int perl_start_script_unsupported(const char *script __unused, | |||
122 | return -1; | 124 | return -1; |
123 | } | 125 | } |
124 | 126 | ||
125 | static int perl_generate_script_unsupported(const char *outfile __unused) | 127 | static int perl_generate_script_unsupported(struct pevent *pevent __unused, |
128 | const char *outfile __unused) | ||
126 | { | 129 | { |
127 | print_perl_unsupported_msg(); | 130 | print_perl_unsupported_msg(); |
128 | 131 | ||
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 639852ac1117..8fef1d6687b7 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -8,6 +8,7 @@ | |||
8 | struct machine; | 8 | struct machine; |
9 | struct perf_sample; | 9 | struct perf_sample; |
10 | union perf_event; | 10 | union perf_event; |
11 | struct perf_tool; | ||
11 | struct thread; | 12 | struct thread; |
12 | 13 | ||
13 | extern int header_page_size_size; | 14 | extern int header_page_size_size; |
@@ -29,35 +30,36 @@ enum { | |||
29 | 30 | ||
30 | int bigendian(void); | 31 | int bigendian(void); |
31 | 32 | ||
32 | int read_trace_init(int file_bigendian, int host_bigendian); | 33 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian); |
33 | void print_trace_event(int cpu, void *data, int size); | 34 | void print_trace_event(struct pevent *pevent, int cpu, void *data, int size); |
34 | 35 | ||
35 | void print_event(int cpu, void *data, int size, unsigned long long nsecs, | 36 | void print_event(struct pevent *pevent, int cpu, void *data, int size, |
36 | char *comm); | 37 | unsigned long long nsecs, char *comm); |
37 | 38 | ||
38 | int parse_ftrace_file(char *buf, unsigned long size); | 39 | int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); |
39 | int parse_event_file(char *buf, unsigned long size, char *sys); | 40 | int parse_event_file(struct pevent *pevent, |
41 | char *buf, unsigned long size, char *sys); | ||
40 | 42 | ||
41 | struct pevent_record *trace_peek_data(int cpu); | 43 | struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu); |
42 | struct event_format *trace_find_event(int type); | ||
43 | 44 | ||
44 | unsigned long long | 45 | unsigned long long |
45 | raw_field_value(struct event_format *event, const char *name, void *data); | 46 | raw_field_value(struct event_format *event, const char *name, void *data); |
46 | void *raw_field_ptr(struct event_format *event, const char *name, void *data); | 47 | void *raw_field_ptr(struct event_format *event, const char *name, void *data); |
47 | 48 | ||
48 | void parse_proc_kallsyms(char *file, unsigned int size __unused); | 49 | void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); |
49 | void parse_ftrace_printk(char *file, unsigned int size __unused); | 50 | void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); |
50 | 51 | ||
51 | ssize_t trace_report(int fd, bool repipe); | 52 | ssize_t trace_report(int fd, struct pevent **pevent, bool repipe); |
52 | 53 | ||
53 | int trace_parse_common_type(void *data); | 54 | int trace_parse_common_type(struct pevent *pevent, void *data); |
54 | int trace_parse_common_pid(void *data); | 55 | int trace_parse_common_pid(struct pevent *pevent, void *data); |
55 | 56 | ||
56 | struct event_format *trace_find_next_event(struct event_format *event); | 57 | struct event_format *trace_find_next_event(struct pevent *pevent, |
57 | unsigned long long read_size(void *ptr, int size); | 58 | struct event_format *event); |
59 | unsigned long long read_size(struct pevent *pevent, void *ptr, int size); | ||
58 | unsigned long long eval_flag(const char *flag); | 60 | unsigned long long eval_flag(const char *flag); |
59 | 61 | ||
60 | struct pevent_record *trace_read_data(int cpu); | 62 | struct pevent_record *trace_read_data(struct pevent *pevent, int cpu); |
61 | int read_tracing_data(int fd, struct list_head *pattrs); | 63 | int read_tracing_data(int fd, struct list_head *pattrs); |
62 | 64 | ||
63 | struct tracing_data { | 65 | struct tracing_data { |
@@ -77,11 +79,12 @@ struct scripting_ops { | |||
77 | int (*start_script) (const char *script, int argc, const char **argv); | 79 | int (*start_script) (const char *script, int argc, const char **argv); |
78 | int (*stop_script) (void); | 80 | int (*stop_script) (void); |
79 | void (*process_event) (union perf_event *event, | 81 | void (*process_event) (union perf_event *event, |
82 | struct pevent *pevent, | ||
80 | struct perf_sample *sample, | 83 | struct perf_sample *sample, |
81 | struct perf_evsel *evsel, | 84 | struct perf_evsel *evsel, |
82 | struct machine *machine, | 85 | struct machine *machine, |
83 | struct thread *thread); | 86 | struct thread *thread); |
84 | int (*generate_script) (const char *outfile); | 87 | int (*generate_script) (struct pevent *pevent, const char *outfile); |
85 | }; | 88 | }; |
86 | 89 | ||
87 | int script_spec_register(const char *spec, struct scripting_ops *ops); | 90 | int script_spec_register(const char *spec, struct scripting_ops *ops); |
@@ -90,6 +93,7 @@ void setup_perl_scripting(void); | |||
90 | void setup_python_scripting(void); | 93 | void setup_python_scripting(void); |
91 | 94 | ||
92 | struct scripting_context { | 95 | struct scripting_context { |
96 | struct pevent *pevent; | ||
93 | void *event_data; | 97 | void *event_data; |
94 | }; | 98 | }; |
95 | 99 | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 2daaedb83d84..b13c7331eaf8 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -264,4 +264,6 @@ bool is_power_of_2(unsigned long n) | |||
264 | 264 | ||
265 | size_t hex_width(u64 v); | 265 | size_t hex_width(u64 v); |
266 | 266 | ||
267 | char *rtrim(char *s); | ||
268 | |||
267 | #endif | 269 | #endif |