Skip to content

Commit

Permalink
perf, arch: Rework perf_event_index()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Cc: Michael Cree <[email protected]>
Cc: Will Deacon <[email protected]>
Cc: Deng-Cheng Zhu <[email protected]>
Cc: Anton Blanchard <[email protected]>
Cc: Eric B Munson <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Paul Mundt <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Richard Kuo <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Arun Sharma <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
  • Loading branch information
Peter Zijlstra authored and Ingo Molnar committed Dec 21, 2011
1 parent 9a0f05c commit 35edc2a
Show file tree
Hide file tree
Showing 10 changed files with 41 additions and 18 deletions.
4 changes: 0 additions & 4 deletions arch/arm/include/asm/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@
#ifndef __ARM_PERF_EVENT_H__
#define __ARM_PERF_EVENT_H__

/* ARM performance counters start from 1 (in the cp15 accesses) so use the
* same indexes here for consistency. */
#define PERF_EVENT_INDEX_OFFSET 1

/* ARM perf PMU IDs for use by internal perf clients. */
enum arm_perf_pmu_ids {
ARM_PERF_PMU_ID_XSCALE1 = 0,
Expand Down
2 changes: 0 additions & 2 deletions arch/frv/include/asm/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,4 @@
#ifndef _ASM_PERF_EVENT_H
#define _ASM_PERF_EVENT_H

#define PERF_EVENT_INDEX_OFFSET 0

#endif /* _ASM_PERF_EVENT_H */
2 changes: 0 additions & 2 deletions arch/hexagon/include/asm/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,4 @@
#ifndef _ASM_PERF_EVENT_H
#define _ASM_PERF_EVENT_H

#define PERF_EVENT_INDEX_OFFSET 0

#endif /* _ASM_PERF_EVENT_H */
2 changes: 0 additions & 2 deletions arch/powerpc/include/asm/perf_event_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ struct pt_regs;
extern unsigned long perf_misc_flags(struct pt_regs *regs);
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);

#define PERF_EVENT_INDEX_OFFSET 1

/*
* Only override the default definitions in include/linux/perf_event.h
* if we have hardware PMU support.
Expand Down
6 changes: 6 additions & 0 deletions arch/powerpc/kernel/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -1187,6 +1187,11 @@ static int power_pmu_event_init(struct perf_event *event)
return err;
}

static int power_pmu_event_idx(struct perf_event *event)
{
return event->hw.idx;
}

struct pmu power_pmu = {
.pmu_enable = power_pmu_enable,
.pmu_disable = power_pmu_disable,
Expand All @@ -1199,6 +1204,7 @@ struct pmu power_pmu = {
.start_txn = power_pmu_start_txn,
.cancel_txn = power_pmu_cancel_txn,
.commit_txn = power_pmu_commit_txn,
.event_idx = power_pmu_event_idx,
};

/*
Expand Down
1 change: 0 additions & 1 deletion arch/s390/include/asm/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@

/* Empty, just to avoid compiling error */

#define PERF_EVENT_INDEX_OFFSET 0
2 changes: 0 additions & 2 deletions arch/x86/include/asm/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,6 @@ extern u32 get_ibs_caps(void);
#ifdef CONFIG_PERF_EVENTS
extern void perf_events_lapic_init(void);

#define PERF_EVENT_INDEX_OFFSET 0

/*
* Abuse bit 3 of the cpu eflags register to indicate proper PEBS IP fixups.
* This flag is otherwise unused and ABI specified to be 0, so nobody should
Expand Down
6 changes: 6 additions & 0 deletions include/linux/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,12 @@ struct pmu {
* for each successful ->add() during the transaction.
*/
void (*cancel_txn) (struct pmu *pmu); /* optional */

/*
* Will return the value for perf_event_mmap_page::index for this event,
* if no implementation is provided it will default to: event->hw.idx + 1.
*/
int (*event_idx) (struct perf_event *event); /*optional */
};

/**
Expand Down
27 changes: 22 additions & 5 deletions kernel/events/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -3208,10 +3208,6 @@ int perf_event_task_disable(void)
return 0;
}

#ifndef PERF_EVENT_INDEX_OFFSET
# define PERF_EVENT_INDEX_OFFSET 0
#endif

static int perf_event_index(struct perf_event *event)
{
if (event->hw.state & PERF_HES_STOPPED)
Expand All @@ -3220,7 +3216,7 @@ static int perf_event_index(struct perf_event *event)
if (event->state != PERF_EVENT_STATE_ACTIVE)
return 0;

return event->hw.idx + 1 - PERF_EVENT_INDEX_OFFSET;
return event->pmu->event_idx(event);
}

static void calc_timer_values(struct perf_event *event,
Expand Down Expand Up @@ -4992,6 +4988,11 @@ static int perf_swevent_init(struct perf_event *event)
return 0;
}

static int perf_swevent_event_idx(struct perf_event *event)
{
return 0;
}

static struct pmu perf_swevent = {
.task_ctx_nr = perf_sw_context,

Expand All @@ -5001,6 +5002,8 @@ static struct pmu perf_swevent = {
.start = perf_swevent_start,
.stop = perf_swevent_stop,
.read = perf_swevent_read,

.event_idx = perf_swevent_event_idx,
};

#ifdef CONFIG_EVENT_TRACING
Expand Down Expand Up @@ -5087,6 +5090,8 @@ static struct pmu perf_tracepoint = {
.start = perf_swevent_start,
.stop = perf_swevent_stop,
.read = perf_swevent_read,

.event_idx = perf_swevent_event_idx,
};

static inline void perf_tp_register(void)
Expand Down Expand Up @@ -5306,6 +5311,8 @@ static struct pmu perf_cpu_clock = {
.start = cpu_clock_event_start,
.stop = cpu_clock_event_stop,
.read = cpu_clock_event_read,

.event_idx = perf_swevent_event_idx,
};

/*
Expand Down Expand Up @@ -5378,6 +5385,8 @@ static struct pmu perf_task_clock = {
.start = task_clock_event_start,
.stop = task_clock_event_stop,
.read = task_clock_event_read,

.event_idx = perf_swevent_event_idx,
};

static void perf_pmu_nop_void(struct pmu *pmu)
Expand Down Expand Up @@ -5405,6 +5414,11 @@ static void perf_pmu_cancel_txn(struct pmu *pmu)
perf_pmu_enable(pmu);
}

static int perf_event_idx_default(struct perf_event *event)
{
return event->hw.idx + 1;
}

/*
* Ensures all contexts with the same task_ctx_nr have the same
* pmu_cpu_context too.
Expand Down Expand Up @@ -5594,6 +5608,9 @@ int perf_pmu_register(struct pmu *pmu, char *name, int type)
pmu->pmu_disable = perf_pmu_nop_void;
}

if (!pmu->event_idx)
pmu->event_idx = perf_event_idx_default;

list_add_rcu(&pmu->entry, &pmus);
ret = 0;
unlock:
Expand Down
7 changes: 7 additions & 0 deletions kernel/events/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,11 @@ static void hw_breakpoint_stop(struct perf_event *bp, int flags)
bp->hw.state = PERF_HES_STOPPED;
}

static int hw_breakpoint_event_idx(struct perf_event *bp)
{
return 0;
}

static struct pmu perf_breakpoint = {
.task_ctx_nr = perf_sw_context, /* could eventually get its own */

Expand All @@ -622,6 +627,8 @@ static struct pmu perf_breakpoint = {
.start = hw_breakpoint_start,
.stop = hw_breakpoint_stop,
.read = hw_breakpoint_pmu_read,

.event_idx = hw_breakpoint_event_idx,
};

int __init init_hw_breakpoint(void)
Expand Down

0 comments on commit 35edc2a

Please sign in to comment.