Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf, arch: Rework perf_event_index()

Put the logic to compute the event index into a per pmu method. This
is required because the x86 rules are weird and wonderful and don't
match the capabilities of the current scheme.

AFAIK only powerpc actually has a usable userspace read of the PMCs
but I'm not at all sure anybody actually used that.

ARM is restored to the default since it currently does not support
userspace access at all. And all software events are provided with a
method that reports their index as 0 (disabled).

Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Michael Cree <mcree@orcon.net.nz>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Deng-Cheng Zhu <dengcheng.zhu@gmail.com>
Cc: Anton Blanchard <anton@samba.org>
Cc: Eric B Munson <emunson@mgebm.net>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: David S. Miller <davem@davemloft.net>
Cc: Richard Kuo <rkuo@codeaurora.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Arun Sharma <asharma@fb.com>
Link: http://lkml.kernel.org/n/tip-dfydxodki16lylkt3gl2j7cw@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@elte.hu>

authored by

Peter Zijlstra and committed by
Ingo Molnar
35edc2a5 9a0f05cb

+41 -18
-4
arch/arm/include/asm/perf_event.h
··· 12 12 #ifndef __ARM_PERF_EVENT_H__ 13 13 #define __ARM_PERF_EVENT_H__ 14 14 15 - /* ARM performance counters start from 1 (in the cp15 accesses) so use the 16 - * same indexes here for consistency. */ 17 - #define PERF_EVENT_INDEX_OFFSET 1 18 - 19 15 /* ARM perf PMU IDs for use by internal perf clients. */ 20 16 enum arm_perf_pmu_ids { 21 17 ARM_PERF_PMU_ID_XSCALE1 = 0,
-2
arch/frv/include/asm/perf_event.h
··· 12 12 #ifndef _ASM_PERF_EVENT_H 13 13 #define _ASM_PERF_EVENT_H 14 14 15 - #define PERF_EVENT_INDEX_OFFSET 0 16 - 17 15 #endif /* _ASM_PERF_EVENT_H */
-2
arch/hexagon/include/asm/perf_event.h
··· 19 19 #ifndef _ASM_PERF_EVENT_H 20 20 #define _ASM_PERF_EVENT_H 21 21 22 - #define PERF_EVENT_INDEX_OFFSET 0 23 - 24 22 #endif /* _ASM_PERF_EVENT_H */
-2
arch/powerpc/include/asm/perf_event_server.h
··· 61 61 extern unsigned long perf_misc_flags(struct pt_regs *regs); 62 62 extern unsigned long perf_instruction_pointer(struct pt_regs *regs); 63 63 64 - #define PERF_EVENT_INDEX_OFFSET 1 65 - 66 64 /* 67 65 * Only override the default definitions in include/linux/perf_event.h 68 66 * if we have hardware PMU support.
+6
arch/powerpc/kernel/perf_event.c
··· 1187 1187 return err; 1188 1188 } 1189 1189 1190 + static int power_pmu_event_idx(struct perf_event *event) 1191 + { 1192 + return event->hw.idx; 1193 + } 1194 + 1190 1195 struct pmu power_pmu = { 1191 1196 .pmu_enable = power_pmu_enable, 1192 1197 .pmu_disable = power_pmu_disable, ··· 1204 1199 .start_txn = power_pmu_start_txn, 1205 1200 .cancel_txn = power_pmu_cancel_txn, 1206 1201 .commit_txn = power_pmu_commit_txn, 1202 + .event_idx = power_pmu_event_idx, 1207 1203 }; 1208 1204 1209 1205 /*
-1
arch/s390/include/asm/perf_event.h
··· 6 6 7 7 /* Empty, just to avoid compiling error */ 8 8 9 - #define PERF_EVENT_INDEX_OFFSET 0
-2
arch/x86/include/asm/perf_event.h
··· 188 188 #ifdef CONFIG_PERF_EVENTS 189 189 extern void perf_events_lapic_init(void); 190 190 191 - #define PERF_EVENT_INDEX_OFFSET 0 192 - 193 191 /* 194 192 * Abuse bit 3 of the cpu eflags register to indicate proper PEBS IP fixups. 195 193 * This flag is otherwise unused and ABI specified to be 0, so nobody should
+6
include/linux/perf_event.h
··· 680 680 * for each successful ->add() during the transaction. 681 681 */ 682 682 void (*cancel_txn) (struct pmu *pmu); /* optional */ 683 + 684 + /* 685 + * Will return the value for perf_event_mmap_page::index for this event, 686 + * if no implementation is provided it will default to: event->hw.idx + 1. 687 + */ 688 + int (*event_idx) (struct perf_event *event); /*optional */ 683 689 }; 684 690 685 691 /**
+22 -5
kernel/events/core.c
··· 3208 3208 return 0; 3209 3209 } 3210 3210 3211 - #ifndef PERF_EVENT_INDEX_OFFSET 3212 - # define PERF_EVENT_INDEX_OFFSET 0 3213 - #endif 3214 - 3215 3211 static int perf_event_index(struct perf_event *event) 3216 3212 { 3217 3213 if (event->hw.state & PERF_HES_STOPPED) ··· 3216 3220 if (event->state != PERF_EVENT_STATE_ACTIVE) 3217 3221 return 0; 3218 3222 3219 - return event->hw.idx + 1 - PERF_EVENT_INDEX_OFFSET; 3223 + return event->pmu->event_idx(event); 3220 3224 } 3221 3225 3222 3226 static void calc_timer_values(struct perf_event *event, ··· 4988 4992 return 0; 4989 4993 } 4990 4994 4995 + static int perf_swevent_event_idx(struct perf_event *event) 4996 + { 4997 + return 0; 4998 + } 4999 + 4991 5000 static struct pmu perf_swevent = { 4992 5001 .task_ctx_nr = perf_sw_context, 4993 5002 ··· 5002 5001 .start = perf_swevent_start, 5003 5002 .stop = perf_swevent_stop, 5004 5003 .read = perf_swevent_read, 5004 + 5005 + .event_idx = perf_swevent_event_idx, 5005 5006 }; 5006 5007 5007 5008 #ifdef CONFIG_EVENT_TRACING ··· 5090 5087 .start = perf_swevent_start, 5091 5088 .stop = perf_swevent_stop, 5092 5089 .read = perf_swevent_read, 5090 + 5091 + .event_idx = perf_swevent_event_idx, 5093 5092 }; 5094 5093 5095 5094 static inline void perf_tp_register(void) ··· 5311 5306 .start = cpu_clock_event_start, 5312 5307 .stop = cpu_clock_event_stop, 5313 5308 .read = cpu_clock_event_read, 5309 + 5310 + .event_idx = perf_swevent_event_idx, 5314 5311 }; 5315 5312 5316 5313 /* ··· 5385 5378 .start = task_clock_event_start, 5386 5379 .stop = task_clock_event_stop, 5387 5380 .read = task_clock_event_read, 5381 + 5382 + .event_idx = perf_swevent_event_idx, 5388 5383 }; 5389 5384 5390 5385 static void perf_pmu_nop_void(struct pmu *pmu) ··· 5412 5403 static void perf_pmu_cancel_txn(struct pmu *pmu) 5413 5404 { 5414 5405 perf_pmu_enable(pmu); 5406 + } 5407 + 5408 + static int perf_event_idx_default(struct perf_event *event) 5409 + { 5410 + return event->hw.idx + 1; 5415 5411 } 5416 5412 5417 5413 /* ··· 5607 5593 pmu->pmu_enable = perf_pmu_nop_void; 5608 5594 pmu->pmu_disable = perf_pmu_nop_void; 5609 5595 } 5596 + 5597 + if (!pmu->event_idx) 5598 + pmu->event_idx = perf_event_idx_default; 5610 5599 5611 5600 list_add_rcu(&pmu->entry, &pmus); 5612 5601 ret = 0;
+7
kernel/events/hw_breakpoint.c
··· 613 613 bp->hw.state = PERF_HES_STOPPED; 614 614 } 615 615 616 + static int hw_breakpoint_event_idx(struct perf_event *bp) 617 + { 618 + return 0; 619 + } 620 + 616 621 static struct pmu perf_breakpoint = { 617 622 .task_ctx_nr = perf_sw_context, /* could eventually get its own */ 618 623 ··· 627 622 .start = hw_breakpoint_start, 628 623 .stop = hw_breakpoint_stop, 629 624 .read = hw_breakpoint_pmu_read, 625 + 626 + .event_idx = hw_breakpoint_event_idx, 630 627 }; 631 628 632 629 int __init init_hw_breakpoint(void)