IRQ-bound performance events
Subsystems (3)
cover IRQ-bound performance events
Hello,
This patchset is against perf/core branch.
This is an an attempt to introduce IRQ-bound performance events - ones that only count in a context of a hardware interrupt handler. The aim is to measure events which can not be measured using existing task-bound or CPU-bound counters (i.e. L1 cache-misses of a particular hardware handler or its durability).
The implementation is pretty straightforward: an IRQ-bound event is registered with the IRQ descriptor and gets enabled/disabled using new PMU callbacks: pmu_enable_irq() and pmu_disable_irq().
The series has not been tested thoroughly and is a concept proof rather than a decent implementation: no group events could be be loaded, inappropriate (i.e. software) events are not rejected, only Intel and AMD PMUs were tried for 'perf stat', only Intel PMU works with precise events. Perf tool changes are just a hack.
Yet, I want first ensure if the taken approach is not screwed and I did not miss anything vital.
Below is a sample session on a machine with x2apic in cluster mode. IRQ number is passed using new argument -I <irq> (please nevermind '...process id '8'...' in the output):
# cat /proc/irq/8/smp_affinity_list 0,4,8,12,16,20,24,28,32,36,40,44 # ./tools/perf/perf stat -a -e L1-dcache-load-misses:k sleep 1
Performance counter stats for 'sleep 1':
124,078 L1-dcache-load-misses
1.001464219 seconds time elapsed# ./tools/perf/perf stat -I 8 -a -e L1-dcache-load-misses:k sleep 1
Performance counter stats for process id '8':
0 L1-dcache-load-misses
1.001466384 seconds time elapsed# ./tools/perf/perf stat -I 8 -a -e L1-dcache-load-misses:k hwclock --test Mon 17 Dec 2012 03:24:05 AM EST -0.500690 seconds
Performance counter stats for process id '8':
317 L1-dcache-load-misses
0.502153382 seconds time elapsed# ./tools/perf/perf stat -I 8 -C 0 -e L1-dcache-load-misses:k hwclock --test Mon 17 Dec 2012 03:30:36 AM EST -0.078717 seconds
Performance counter stats for process id '8':
72 L1-dcache-load-misses
0.079948468 seconds time elapsedAlexander Gordeev (6):
perf/core: IRQ-bound performance events perf/x86: IRQ-bound performance events perf/x86/AMD PMU: IRQ-bound performance events perf/x86/Core PMU: IRQ-bound performance events perf/x86/Intel PMU: IRQ-bound performance events perf/tool: Hack 'pid' as 'irq' for sys_perf_event_open()
arch/x86/kernel/cpu/perf_event.c | 71 ++++++++++++++++++--- arch/x86/kernel/cpu/perf_event.h | 19 ++++++ arch/x86/kernel/cpu/perf_event_amd.c | 2 + arch/x86/kernel/cpu/perf_event_intel.c | 93 +++++++++++++++++++++++++-- arch/x86/kernel/cpu/perf_event_intel_ds.c | 5 +- arch/x86/kernel/cpu/perf_event_knc.c | 2 + arch/x86/kernel/cpu/perf_event_p4.c | 2 + arch/x86/kernel/cpu/perf_event_p6.c | 2 + include/linux/irq.h | 8 ++ include/linux/irqdesc.h | 3 + include/linux/perf_event.h | 16 +++++ include/uapi/linux/perf_event.h | 1 + kernel/events/core.c | 69 +++++++++++++++---- kernel/irq/Makefile | 1 + kernel/irq/handle.c | 4 + kernel/irq/irqdesc.c | 14 ++++ kernel/irq/perf_event.c | 100 +++++++++++++++++++++++++++++ tools/perf/builtin-record.c | 9 +++ tools/perf/builtin-stat.c | 11 +++ tools/perf/util/evlist.c | 4 +- tools/perf/util/evsel.c | 3 + tools/perf/util/evsel.h | 1 + tools/perf/util/target.c | 4 + tools/perf/util/thread_map.c | 16 +++++ 24 files changed, 426 insertions(+), 34 deletions(-) create mode 100644 kernel/irq/perf_event.c
Signature · 7 lines
1.7.7.6 -- Regards, Alexander Gordeev [email protected]
RFC PATCH 1/6 perf/core: IRQ-bound performance events
Make possible counting performance events while a particular hardware context interrupt handler is running.
--- include/linux/irq.h | 8 +++ include/linux/irqdesc.h | 3 + include/linux/perf_event.h | 16 ++++++ include/uapi/linux/perf_event.h | 1 + kernel/events/core.c | 69 +++++++++++++++++++++------ kernel/irq/Makefile | 1 + kernel/irq/handle.c | 4 ++ kernel/irq/irqdesc.c | 14 +++++ kernel/irq/perf_event.c | 100 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 201 insertions(+), 15 deletions(-) create mode 100644 kernel/irq/perf_event.c
include/linux/irq.h +8 -0
@@ -604,6 +604,14 @@ static inline int irq_reserve_irq(unsigned int irq)# define irq_reg_readl (addr) readl(addr)#endif +#ifdef CONFIG_PERF_EVENTS +extern void perf_enable_irq_events (struct irq_desc *desc); +extern void perf_disable_irq_events (struct irq_desc *desc); +#else +static inline void perf_enable_irq_events (struct irq_desc *desc) { } +static inline void perf_disable_irq_events (struct irq_desc *desc) { } +#endif +/** * struct irq_chip_regs - register offsets for struct irq_gci * @enable: Enable register offset to reg_base
include/linux/irqdesc.h +3 -0
@@ -65,6 +65,9 @@ struct irq_desc {#ifdef CONFIG_PROC_FS struct proc_dir_entry *dir;#endif +#ifdef CONFIG_PERF_EVENTS +struct list_head *__percpu event_list; +#endif struct module *owner;const char *name; }____cacheline_internodealigned_in_smp ;
include/linux/perf_event.h +16 -0
@@ -197,6 +197,9 @@ struct pmu {void (*pmu_enable) (struct pmu *pmu);/* optional */ void (*pmu_disable) (struct pmu *pmu);/* optional */ +void (*pmu_enable_irq) (struct pmu *pmu,int irq);/* opt. */ +void (*pmu_disable_irq) (struct pmu *pmu,int irq);/* opt. */ +/* * Try and initialize the event for this PMU. * Should return -ENOENT when the @event doesn't match this PMU.
@@ -320,6 +323,7 @@ struct perf_event {struct list_head group_entry;struct list_head event_entry;struct list_head sibling_list; +struct list_head irq_desc_list;struct hlist_node hlist_entry;int nr_siblings;int group_flags;
@@ -392,6 +396,7 @@ struct perf_event {int oncpu;int cpu; +int irq;struct list_head owner_entry;struct task_struct *owner;
@@ -544,6 +549,8 @@ extern void perf_event_delayed_put(struct task_struct *task);extern void perf_event_print_debug (void );extern void perf_pmu_disable (struct pmu *pmu);extern void perf_pmu_enable (struct pmu *pmu); +extern void perf_pmu_disable_irq (struct pmu *pmu,int irq); +extern void perf_pmu_enable_irq (struct pmu *pmu,int irq);extern int perf_event_task_disable (void );extern int perf_event_task_enable (void );extern int perf_event_refresh (struct perf_event *event,int refresh);
@@ -624,6 +631,11 @@ static inline int is_software_event(struct perf_event *event)return event->pmu->task_ctx_nr == perf_sw_context; } +static inline bool is_interrupt_event (struct perf_event *event) +{ +return event->irq >=0 ; +} +extern struct static_key perf_swevent_enabled[PERF_COUNT_SW_MAX ];extern void __perf_sw_event (u32 ,u64 ,struct pt_regs *,u64 );
@@ -753,6 +765,8 @@ extern void perf_event_enable(struct perf_event *event);extern void perf_event_disable (struct perf_event *event);extern int __perf_event_disable (void *info);extern void perf_event_task_tick (void ); +extern int perf_event_irq_add (struct perf_event *event); +extern int perf_event_irq_del (struct perf_event *event);#else static inline void perf_event_task_sched_in(struct task_struct *prev,
@@ -792,6 +806,8 @@ static inline void perf_event_enable(struct perf_event *event) { }static inline void perf_event_disable (struct perf_event *event) { }static inline int __perf_event_disable (void *info) {return -1 ; }static inline void perf_event_task_tick (void ) { } +extern inline int perf_event_irq_add (struct perf_event *event) {return -EINVAL ; } +extern inline int perf_event_irq_del (struct perf_event *event) {return -EINVAL ; }#endif #define perf_output_put (handle, x) perf_output_copy((handle), &(x), sizeof(x))
include/uapi/linux/perf_event.h +1 -0
@@ -611,5 +611,6 @@ enum perf_callchain_context {#define PERF_FLAG_FD_NO_GROUP (1U << 0)#define PERF_FLAG_FD_OUTPUT (1U << 1)#define PERF_FLAG_PID_CGROUP (1U << 2)/* pid=cgroup id, per-cpu mode only */ +#define PERF_FLAG_PID_IRQ (1U << 3)/* pid=irq number */ #endif /* _UAPI_LINUX_PERF_EVENT_H */
kernel/events/core.c +54 -15
147 lines not on this page · raw message
kernel/irq/Makefile +1 -0
@@ -6,3 +6,4 @@ obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o obj-$(CONFIG_PM_SLEEP) += pm.o +obj-$(CONFIG_PERF_EVENTS) += perf_event.o
kernel/irq/handle.c +4 -0
@@ -139,7 +139,11 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)irqreturn_t res;trace_irq_handler_entry (irq, action); +perf_enable_irq_events (desc); + res = action->handler (irq, action->dev_id); + +perf_disable_irq_events (desc);trace_irq_handler_exit (irq, action, res); if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",
kernel/irq/irqdesc.c +14 -0
@@ -131,6 +131,14 @@ static void free_masks(struct irq_desc *desc)static inline void free_masks (struct irq_desc *desc) { }#endif +#ifdef CONFIG_PERF_EVENTS +extern int alloc_perf_events (struct irq_desc *desc); +extern void free_perf_events (struct irq_desc *desc); +#else +static inline int alloc_perf_events (struct irq_desc *desc) {return 0 ; } +static inline void free_perf_events (struct irq_desc *desc) { } +#endif +static struct irq_desc *alloc_desc (int irq,int node,struct module *owner) {struct irq_desc *desc;
@@ -147,6 +155,9 @@ static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)if (alloc_masks (desc, gfp, node)) goto err_kstat; +if (alloc_perf_events (desc)) + goto err_masks; +raw_spin_lock_init (&desc->lock);lockdep_set_class (&desc->lock, &irq_desc_lock_class);
@@ -154,6 +165,8 @@ static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)return desc; +err_masks: +free_masks (desc); err_kstat:free_percpu (desc->kstat_irqs); err_desc:
@@ -171,6 +184,7 @@ static void free_desc(unsigned int irq)delete_irq_desc (irq);mutex_unlock (&sparse_irq_lock); +free_perf_events (desc);free_masks (desc);free_percpu (desc->kstat_irqs);kfree (desc);
kernel/irq/perf_event.c new file +100 -0
100 lines not on this page · raw message
Signature · 7 lines
1.7.7.6 -- Regards, Alexander Gordeev [email protected]
RFC PATCH 2/6 perf/x86: IRQ-bound performance events
In reply to Alexander GordeevGeneric changes to x86 performance framework to further enable implementations of IRQ-bound performance events.
--- arch/x86/kernel/cpu/perf_event.c | 33 +++++++++++++++++++++++++++++-- arch/x86/kernel/cpu/perf_event.h | 5 ++++ arch/x86/kernel/cpu/perf_event_amd.c | 2 + arch/x86/kernel/cpu/perf_event_intel.c | 4 +++ arch/x86/kernel/cpu/perf_event_knc.c | 2 + arch/x86/kernel/cpu/perf_event_p4.c | 2 + arch/x86/kernel/cpu/perf_event_p6.c | 2 + 7 files changed, 47 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/perf_event.c +30 -3
@@ -525,6 +525,11 @@ static void x86_pmu_disable(struct pmu *pmu) x86_pmu.disable_all (); } +static void x86_pmu__disable_irq (struct pmu *pmu,int irq) +{ + x86_pmu.disable_irq (irq); +} +void x86_pmu_enable_all (int added) {struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events);
@@ -540,6 +545,10 @@ void x86_pmu_enable_all(int added) } } +void x86_pmu_enable_irq_nop_int (int irq) +{ +} +static struct pmu pmu;static inline int is_x86_event (struct perf_event *event)
@@ -920,6 +929,11 @@ static void x86_pmu_enable(struct pmu *pmu) x86_pmu.enable_all (added); } +static void x86_pmu__enable_irq (struct pmu *pmu,int irq) +{ + x86_pmu.enable_irq (irq); +} + static DEFINE_PER_CPU(u64 [X86_PMC_IDX_MAX], pmc_prev_left);/*
@@ -1065,7 +1079,12 @@ static void x86_pmu_start(struct perf_event *event, int flags) event->hw.state =0 ; cpuc->events[idx] = event; -__set_bit (idx, cpuc->active_mask); +if (is_interrupt_event (event)) { +__set_bit (idx, cpuc->actirq_mask); +perf_event_irq_add (event); + }else { +__set_bit (idx, cpuc->active_mask); + }__set_bit (idx, cpuc->running); x86_pmu.enable (event);perf_event_update_userpage (event);
@@ -1102,6 +1121,7 @@ void perf_event_print_debug(void)pr_info ("CPU#%d: pebs: %016llx\n" , cpu, pebs); }pr_info ("CPU#%d: active: %016llx\n" , cpu, *(u64 *)cpuc->active_mask); +pr_info ("CPU#%d: actirq: %016llx\n" , cpu, *(u64 *)cpuc->actirq_mask);for (idx =0 ; idx < x86_pmu.num_counters; idx++) {rdmsrl (x86_pmu_config_addr (idx), pmc_ctrl);
@@ -1130,8 +1150,11 @@ void x86_pmu_stop(struct perf_event *event, int flags)struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events);struct hw_perf_event *hwc = &event->hw; -if (__test_and_clear_bit (hwc->idx, cpuc->active_mask)) { +if (__test_and_clear_bit (hwc->idx, cpuc->active_mask) || +__test_and_clear_bit (hwc->idx, cpuc->actirq_mask)) { x86_pmu.disable (event); +if (unlikely (is_interrupt_event (event))) +perf_event_irq_del (event); cpuc->events[hwc->idx] =NULL ;WARN_ON_ONCE (hwc->state &PERF_HES_STOPPED ); hwc->state |=PERF_HES_STOPPED ;
@@ -1199,7 +1222,8 @@ int x86_pmu_handle_irq(struct pt_regs *regs)apic_write (APIC_LVTPC ,APIC_DM_NMI );for (idx =0 ; idx < x86_pmu.num_counters; idx++) { -if (!test_bit (idx, cpuc->active_mask)) { +if (!test_bit (idx, cpuc->active_mask) && + !test_bit (idx, cpuc->actirq_mask)) {/* * Though we deactivated the counter some cpus * might still deliver spurious interrupts still
@@ -1792,6 +1816,9 @@ static struct pmu pmu = { .pmu_enable = x86_pmu_enable, .pmu_disable = x86_pmu_disable, + .pmu_enable_irq = x86_pmu__enable_irq, + .pmu_disable_irq = x86_pmu__disable_irq, + .attr_groups = x86_pmu_attr_groups, .event_init = x86_pmu_event_init,
arch/x86/kernel/cpu/perf_event.h +5 -0
@@ -118,6 +118,7 @@ struct cpu_hw_events {*/ struct perf_event *events[X86_PMC_IDX_MAX ];/* in counter order */ unsigned long active_mask[BITS_TO_LONGS (X86_PMC_IDX_MAX )]; +unsigned long actirq_mask[BITS_TO_LONGS (X86_PMC_IDX_MAX )];unsigned long running[BITS_TO_LONGS (X86_PMC_IDX_MAX )];int enabled;
@@ -319,6 +320,8 @@ struct x86_pmu {int (*handle_irq)(struct pt_regs *);void (*disable_all)(void );void (*enable_all)(int added); +void (*disable_irq)(int irq); +void (*enable_irq)(int irq);void (*enable)(struct perf_event *);void (*disable)(struct perf_event *);int (*hw_config)(struct perf_event *event);
@@ -488,6 +491,8 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,void x86_pmu_enable_all (int added); +void x86_pmu_enable_irq_nop_int (int irq); +int perf_assign_events (struct event_constraint **constraints,int n,int wmin,int wmax,int *assign);int x86_schedule_events (struct cpu_hw_events *cpuc,int n,int *assign);
arch/x86/kernel/cpu/perf_event_amd.c +2 -0
@@ -581,6 +581,8 @@ static __initconst const struct x86_pmu amd_pmu = { .handle_irq = x86_pmu_handle_irq, .disable_all = x86_pmu_disable_all, .enable_all = x86_pmu_enable_all, + .disable_irq = x86_pmu_enable_irq_nop_int, + .enable_irq = x86_pmu_enable_irq_nop_int, .enable = x86_pmu_enable_event, .disable = x86_pmu_disable_event, .hw_config = amd_pmu_hw_config,
arch/x86/kernel/cpu/perf_event_intel.c +4 -0
@@ -1615,6 +1615,8 @@ static __initconst const struct x86_pmu core_pmu = { .handle_irq = x86_pmu_handle_irq, .disable_all = x86_pmu_disable_all, .enable_all = core_pmu_enable_all, + .disable_irq = x86_pmu_enable_irq_nop_int, + .enable_irq = x86_pmu_enable_irq_nop_int, .enable = core_pmu_enable_event, .disable = x86_pmu_disable_event, .hw_config = x86_pmu_hw_config,
@@ -1754,6 +1756,8 @@ static __initconst const struct x86_pmu intel_pmu = { .handle_irq = intel_pmu_handle_irq, .disable_all = intel_pmu_disable_all, .enable_all = intel_pmu_enable_all, + .disable_irq = x86_pmu_enable_irq_nop_int, + .enable_irq = x86_pmu_enable_irq_nop_int, .enable = intel_pmu_enable_event, .disable = intel_pmu_disable_event, .hw_config = intel_pmu_hw_config,
arch/x86/kernel/cpu/perf_event_knc.c +2 -0
@@ -289,6 +289,8 @@ static __initconst struct x86_pmu knc_pmu = { .handle_irq = knc_pmu_handle_irq, .disable_all = knc_pmu_disable_all, .enable_all = knc_pmu_enable_all, + .disable_irq = x86_pmu_enable_irq_nop_int, + .enable_irq = x86_pmu_enable_irq_nop_int, .enable = knc_pmu_enable_event, .disable = knc_pmu_disable_event, .hw_config = x86_pmu_hw_config,
arch/x86/kernel/cpu/perf_event_p4.c +2 -0
@@ -1287,6 +1287,8 @@ static __initconst const struct x86_pmu p4_pmu = { .handle_irq = p4_pmu_handle_irq, .disable_all = p4_pmu_disable_all, .enable_all = p4_pmu_enable_all, + .disable_irq = x86_pmu_enable_irq_nop_int, + .enable_irq = x86_pmu_enable_irq_nop_int, .enable = p4_pmu_enable_event, .disable = p4_pmu_disable_event, .eventsel = MSR_P4_BPU_CCCR0,
arch/x86/kernel/cpu/perf_event_p6.c +2 -0
@@ -202,6 +202,8 @@ static __initconst const struct x86_pmu p6_pmu = { .handle_irq = x86_pmu_handle_irq, .disable_all = p6_pmu_disable_all, .enable_all = p6_pmu_enable_all, + .disable_irq = x86_pmu_enable_irq_nop_int, + .enable_irq = x86_pmu_enable_irq_nop_int, .enable = p6_pmu_enable_event, .disable = p6_pmu_disable_event, .hw_config = x86_pmu_hw_config,
Signature · 7 lines
1.7.7.6 -- Regards, Alexander Gordeev [email protected]
RFC PATCH 3/6 perf/x86/AMD PMU: IRQ-bound performance events
In reply to Alexander Gordeev--- arch/x86/kernel/cpu/perf_event.c | 38 ++++++++++++++++++++++++++++----- arch/x86/kernel/cpu/perf_event.h | 14 ++++++++++++ arch/x86/kernel/cpu/perf_event_amd.c | 4 +- 3 files changed, 48 insertions(+), 8 deletions(-)
arch/x86/kernel/cpu/perf_event.c +32 -6
@@ -496,15 +496,23 @@ void x86_pmu_disable_all(void)int idx;for (idx =0 ; idx < x86_pmu.num_counters; idx++) { -u64 val; -if (!test_bit (idx, cpuc->active_mask))continue ; -rdmsrl (x86_pmu_config_addr (idx), val); -if (!(val &ARCH_PERFMON_EVENTSEL_ENABLE )) +__x86_pmu_disable_event (idx,ARCH_PERFMON_EVENTSEL_ENABLE ); + } +} + +void x86_pmu_disable_irq (int irq) +{ +struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events); +int idx; + +for (idx =0 ; idx < x86_pmu.num_counters; idx++) { +if (!test_bit (idx, cpuc->actirq_mask)) +continue ; +if (cpuc->events[idx]->irq != irq)continue ; - val &= ~ARCH_PERFMON_EVENTSEL_ENABLE ; -wrmsrl (x86_pmu_config_addr (idx), val); +__x86_pmu_disable_event (idx,ARCH_PERFMON_EVENTSEL_ENABLE ); } }
@@ -549,6 +557,24 @@ void x86_pmu_enable_irq_nop_int(int irq) { } +void x86_pmu_enable_irq (int irq) +{ +struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events); +int idx; + +for (idx =0 ; idx < x86_pmu.num_counters; idx++) { +struct perf_event *event = cpuc->events[idx]; + +if (!test_bit (idx, cpuc->actirq_mask)) +continue ; +if (event->irq != irq) +continue ; + +__x86_pmu_enable_event (&event->hw, +ARCH_PERFMON_EVENTSEL_ENABLE ); + } +} +static struct pmu pmu;static inline int is_x86_event (struct perf_event *event)
arch/x86/kernel/cpu/perf_event.h +14 -0
@@ -479,6 +479,19 @@ int x86_pmu_hw_config(struct perf_event *event);void x86_pmu_disable_all (void ); +void x86_pmu_disable_irq (int irq); + +static void inline __x86_pmu_disable_event (int idx,u64 enable_mask) +{ +u64 val; + +rdmsrl (x86_pmu_config_addr (idx), val); +if (val & enable_mask) { + val &= ~enable_mask; +wrmsrl (x86_pmu_config_addr (idx), val); + } +} +static inline void __x86_pmu_enable_event (struct hw_perf_event *hwc,u64 enable_mask) {
@@ -491,6 +504,7 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,void x86_pmu_enable_all (int added); +void x86_pmu_enable_irq (int irq);void x86_pmu_enable_irq_nop_int (int irq); int perf_assign_events(struct event_constraint **constraints, int n,
arch/x86/kernel/cpu/perf_event_amd.c +2 -2
@@ -581,8 +581,8 @@ static __initconst const struct x86_pmu amd_pmu = { .handle_irq = x86_pmu_handle_irq, .disable_all = x86_pmu_disable_all, .enable_all = x86_pmu_enable_all, - .disable_irq = x86_pmu_enable_irq_nop_int, - .enable_irq = x86_pmu_enable_irq_nop_int, + .disable_irq = x86_pmu_disable_irq, + .enable_irq = x86_pmu_enable_irq, .enable = x86_pmu_enable_event, .disable = x86_pmu_disable_event, .hw_config = amd_pmu_hw_config,
Signature · 7 lines
1.7.7.6 -- Regards, Alexander Gordeev [email protected]
RFC PATCH 4/6 perf/x86/Core PMU: IRQ-bound performance events
In reply to Alexander Gordeev--- arch/x86/kernel/cpu/perf_event_intel.c | 23 +++++++++++++++++++++-- 1 files changed, 21 insertions(+), 2 deletions(-)
arch/x86/kernel/cpu/perf_event_intel.c +21 -2
@@ -1585,6 +1585,25 @@ static void core_pmu_enable_all(int added) } } +void core_pmu_enable_irq (int irq) +{ +struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events); +int idx; + +for (idx =0 ; idx < x86_pmu.num_counters; idx++) { +struct perf_event *event = cpuc->events[idx]; + +if (!test_bit (idx, cpuc->actirq_mask) || + cpuc->events[idx]->attr.exclude_host) +continue ; +if (event->irq != irq) +continue ; + +__x86_pmu_enable_event (&event->hw, +ARCH_PERFMON_EVENTSEL_ENABLE ); + } +} +PMU_FORMAT_ATTR (event,"config:0-7" );PMU_FORMAT_ATTR (umask,"config:8-15" );PMU_FORMAT_ATTR (edge,"config:18" );
@@ -1615,8 +1634,8 @@ static __initconst const struct x86_pmu core_pmu = { .handle_irq = x86_pmu_handle_irq, .disable_all = x86_pmu_disable_all, .enable_all = core_pmu_enable_all, - .disable_irq = x86_pmu_enable_irq_nop_int, - .enable_irq = x86_pmu_enable_irq_nop_int, + .disable_irq = x86_pmu_disable_irq, + .enable_irq = core_pmu_enable_irq, .enable = core_pmu_enable_event, .disable = x86_pmu_disable_event, .hw_config = x86_pmu_hw_config,
Signature · 7 lines
1.7.7.6 -- Regards, Alexander Gordeev [email protected]
RFC PATCH 5/6 perf/x86/Intel PMU: IRQ-bound performance events
In reply to Alexander Gordeev--- arch/x86/kernel/cpu/perf_event_intel.c | 74 +++++++++++++++++++++++++---- arch/x86/kernel/cpu/perf_event_intel_ds.c | 5 +- 2 files changed, 68 insertions(+), 11 deletions(-)
arch/x86/kernel/cpu/perf_event_intel.c +65 -9
@@ -821,6 +821,24 @@ static inline bool intel_pmu_needs_lbr_smpl(struct perf_event *event)return false; } +u64 __get_intel_ctrl_irq_mask (struct cpu_hw_events *cpuc,int irq) +{ +int idx; +u64 ret =0 ; + +for (idx =0 ; idx < x86_pmu.num_counters; idx++) { +struct perf_event *event = cpuc->events[idx]; + +if (!test_bit (idx, cpuc->actirq_mask)) +continue ; + +if ((event->irq == irq) || (irq <0 )) + ret |= (1ull << event->hw.idx); + } + +return ret; +} +static void intel_pmu_disable_all (void ) {struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events);
@@ -834,14 +852,14 @@ static void intel_pmu_disable_all(void)intel_pmu_lbr_disable_all (); } -static void intel_pmu_enable_all (int added) +static void __intel_pmu_enable (u64 control) {struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events);intel_pmu_pebs_enable_all ();intel_pmu_lbr_enable_all (); -wrmsrl (MSR_CORE_PERF_GLOBAL_CTRL , - x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_guest_mask); + +wrmsrl (MSR_CORE_PERF_GLOBAL_CTRL , control);if (test_bit (INTEL_PMC_IDX_FIXED_BTS , cpuc->active_mask)) { struct perf_event *event =
@@ -854,6 +872,33 @@ static void intel_pmu_enable_all(int added) } } +static void intel_pmu_enable_all (int added) +{ +struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events); +u64 irq_mask =__get_intel_ctrl_irq_mask (cpuc,-1 ); + +__intel_pmu_enable (x86_pmu.intel_ctrl & + ~(cpuc->intel_ctrl_guest_mask | irq_mask)); +} + +static void intel_pmu_disable_irq (int irq) +{ +struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events); +u64 irq_mask =__get_intel_ctrl_irq_mask (cpuc, irq); + +wrmsrl (MSR_CORE_PERF_GLOBAL_CTRL , + x86_pmu.intel_ctrl & ~(cpuc->intel_ctrl_guest_mask | irq_mask)); +} + +static void intel_pmu_enable_irq (int irq) +{ +struct cpu_hw_events *cpuc = &__get_cpu_var (cpu_hw_events); +u64 irq_mask =__get_intel_ctrl_irq_mask (cpuc, irq); + +wrmsrl (MSR_CORE_PERF_GLOBAL_CTRL , + (x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_guest_mask) | irq_mask); +} +/* * Workaround for: * Intel Errata AAK100 (model 26)
@@ -935,6 +980,15 @@ static void intel_pmu_nhm_enable_all(int added)intel_pmu_enable_all (added); } +static inline u64 intel_pmu_get_control (void ) +{ +u64 control; + +rdmsrl (MSR_CORE_PERF_GLOBAL_CTRL , control); + +return control; +} +static inline u64 intel_pmu_get_status (void ) {u64 status;
@@ -1104,7 +1158,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)struct perf_sample_data data;struct cpu_hw_events *cpuc;int bit, loops; -u64 status; +u64 control, status;int handled; cpuc = &__get_cpu_var (cpu_hw_events);
@@ -1119,11 +1173,12 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)*/ apic_write (APIC_LVTPC ,APIC_DM_NMI ); + control =intel_pmu_get_control ();intel_pmu_disable_all (); handled =intel_pmu_drain_bts_buffer (); status =intel_pmu_get_status ();if (!status) { -intel_pmu_enable_all (0 ); +__intel_pmu_enable (control);return handled; }
@@ -1154,7 +1209,8 @@ again: handled++; -if (!test_bit (bit, cpuc->active_mask)) +if (!test_bit (bit, cpuc->active_mask) && + !test_bit (bit, cpuc->actirq_mask))continue ;if (!intel_pmu_save_and_restart (event))
@@ -1177,7 +1233,7 @@ again: goto again; done: -intel_pmu_enable_all (0 ); +__intel_pmu_enable (control);return handled; }
@@ -1775,8 +1831,8 @@ static __initconst const struct x86_pmu intel_pmu = { .handle_irq = intel_pmu_handle_irq, .disable_all = intel_pmu_disable_all, .enable_all = intel_pmu_enable_all, - .disable_irq = x86_pmu_enable_irq_nop_int, - .enable_irq = x86_pmu_enable_irq_nop_int, + .disable_irq = intel_pmu_disable_irq, + .enable_irq = intel_pmu_enable_irq, .enable = intel_pmu_enable_event, .disable = intel_pmu_disable_event, .hw_config = intel_pmu_hw_config,
arch/x86/kernel/cpu/perf_event_intel_ds.c +3 -2
@@ -619,7 +619,7 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)*/ ds->pebs_index = ds->pebs_buffer_base; -if (!test_bit (0 , cpuc->active_mask)) +if (!test_bit (0 , cpuc->active_mask) && !test_bit (0 , cpuc->actirq_mask))return ;WARN_ON_ONCE (!event);
@@ -671,7 +671,8 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)for ( ; at < top; at++) {for_each_set_bit (bit, (unsigned long *)&at->status, x86_pmu.max_pebs_events) { event = cpuc->events[bit]; -if (!test_bit (bit, cpuc->active_mask)) +if (!test_bit (bit, cpuc->active_mask) && + !test_bit (bit, cpuc->actirq_mask))continue ;WARN_ON_ONCE (!event);
Signature · 7 lines
1.7.7.6 -- Regards, Alexander Gordeev [email protected]
RFC PATCH 6/6 perf/tool: Hack 'pid' as 'irq' for sys_perf_event_open()
In reply to Alexander GordeevThis is not a decent change, just a quick fix to make possible testing of IRQ-bound performance events.
--- tools/perf/builtin-record.c | 9 +++++++++ tools/perf/builtin-stat.c | 11 +++++++++++ tools/perf/util/evlist.c | 4 +++- tools/perf/util/evsel.c | 3 +++ tools/perf/util/evsel.h | 1 + tools/perf/util/target.c | 4 ++++ tools/perf/util/thread_map.c | 16 ++++++++++++++++ 7 files changed, 47 insertions(+), 1 deletions(-)
tools/perf/builtin-record.c +9 -0
@@ -228,6 +228,7 @@ static int perf_record__open(struct perf_record *rec)struct perf_evlist *evlist = rec->evlist;struct perf_session *session = rec->session;struct perf_record_opts *opts = &rec->opts; +int irq = false;int rc =0 ;/*
@@ -239,6 +240,10 @@ static int perf_record__open(struct perf_record *rec)perf_evlist__config_attrs (evlist, opts); +if (perf_target__has_cpu (&opts->target) && +perf_target__has_task (&opts->target)) + irq = true; +list_for_each_entry (pos, &evlist->entries, node) {struct perf_event_attr *attr = &pos->attr;/*
@@ -255,6 +260,8 @@ static int perf_record__open(struct perf_record *rec)*/ bool time_needed = attr->sample_type &PERF_SAMPLE_TIME ; + pos->irq = irq; + fallback_missing_features:if (opts->exclude_guest_missing) attr->exclude_guest = attr->exclude_host =0 ;
@@ -1000,6 +1007,8 @@ const struct option record_options[] = { parse_events_option),OPT_CALLBACK (0 ,"filter" , &record.evlist,"filter" ,"event filter" , parse_filter), +OPT_STRING ('I' ,"irq" , &record.opts.target.pid,"irq" , +"record events on existing irq handler" ),OPT_STRING ('p' ,"pid" , &record.opts.target.pid,"pid" ,"record events on existing process id" ), OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
tools/perf/builtin-stat.c +11 -0
@@ -145,6 +145,15 @@ retry:if (exclude_guest_missing) evsel->attr.exclude_guest = evsel->attr.exclude_host =0 ; +if (perf_target__has_cpu (&target) &&perf_target__has_task (&target)) { + evsel->irq = true; + ret =perf_evsel__open (evsel,perf_evsel__cpus (evsel), + evsel_list->threads); +if (ret) + goto check_ret; +return 0 ; + } +if (perf_target__has_cpu (&target)) { ret =perf_evsel__open_per_cpu (evsel,perf_evsel__cpus (evsel));if (ret)
@@ -1108,6 +1117,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) "event filter", parse_filter),OPT_BOOLEAN ('i' ,"no-inherit" , &no_inherit,"child tasks do not inherit counters" ), +OPT_STRING ('I' ,"irq" , &target.pid,"irq" , +"stat events on existing irq handler" ),OPT_STRING ('p' ,"pid" , &target.pid,"pid" ,"stat events on existing process id" ), OPT_STRING('t', "tid", &target.tid, "tid",
tools/perf/util/evlist.c +3 -1
@@ -572,7 +572,9 @@ int perf_evlist__create_maps(struct perf_evlist *evlist,if (evlist->threads ==NULL )return -1 ; -if (perf_target__has_task (target)) +if (perf_target__has_task (target) &&perf_target__has_cpu (target)) + evlist->cpus =cpu_map__new (target->cpu_list); +else if (perf_target__has_task (target)) evlist->cpus =cpu_map__dummy_new ();else if (!perf_target__has_cpu (target) && !target->uses_mmap) evlist->cpus =cpu_map__dummy_new ();
tools/perf/util/evsel.c +3 -0
@@ -738,6 +738,9 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, pid = evsel->cgrp->fd; } +if (evsel->irq) + flags =PERF_FLAG_PID_IRQ ; +for (cpu =0 ; cpu < cpus->nr; cpu++) {for (thread =0 ; thread < threads->nr; thread++) {
tools/perf/util/evsel.h +1 -0
@@ -71,6 +71,7 @@ struct perf_evsel {unsigned int sample_size;bool supported;bool needs_swap; +bool irq;/* parse modifier helper */ int exclude_GH;struct perf_evsel *leader;
tools/perf/util/target.c +4 -0
@@ -20,12 +20,14 @@ enum perf_target_errno perf_target__validate(struct perf_target *target)if (target->pid) target->tid = target->pid; +#if (0 )/* CPU and PID are mutually exclusive */ if (target->tid && target->cpu_list) { target->cpu_list =NULL ;if (ret ==PERF_ERRNO_TARGET__SUCCESS ) ret =PERF_ERRNO_TARGET__PID_OVERRIDE_CPU ; } +#endif /* UID and PID are mutually exclusive */ if (target->tid && target->uid_str) {
@@ -41,12 +43,14 @@ enum perf_target_errno perf_target__validate(struct perf_target *target) ret =PERF_ERRNO_TARGET__UID_OVERRIDE_CPU ; } +#if (0 )/* PID and SYSTEM are mutually exclusive */ if (target->tid && target->system_wide) { target->system_wide = false;if (ret ==PERF_ERRNO_TARGET__SUCCESS ) ret =PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM ; } +#endif /* UID and SYSTEM are mutually exclusive */ if (target->uid_str && target->system_wide) {
tools/perf/util/thread_map.c +16 -0
@@ -159,8 +159,12 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)struct thread_map *threads =NULL , *nt;char name[256 ];int items, total_tasks =0 ; +#if (0 )struct dirent **namelist =NULL ;int i, j =0 ; +#else +int j =0 ; +#endif pid_t pid, prev_pid =INT_MAX ;char *end_ptr;struct str_node *pos;
@@ -180,7 +184,11 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)continue ;sprintf (name,"/proc/%d/task" , pid); +#if (0 ) items =scandir (name, &namelist, filter,NULL ); +#else + items =1 ; +#endif if (items <=0 ) goto out_free_threads;
@@ -192,12 +200,18 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) threads = nt; +#if (0 )for (i =0 ; i < items; i++) { threads->map[j++] =atoi (namelist[i]->d_name);free (namelist[i]); } +#else + threads->map[j++] = pid; +#endif threads->nr = total_tasks; +#if (0 )free (namelist); +#endif } out:
@@ -205,9 +219,11 @@ out:return threads; out_free_namelist: +#if (0 )for (i =0 ; i < items; i++)free (namelist[i]);free (namelist); +#endif out_free_threads:free (threads);
Signature · 7 lines
1.7.7.6 -- Regards, Alexander Gordeev [email protected]