diff options
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 |
