perf: Intel uncore pmu counting support
Subsystems (4)
v6 cover perf: Intel uncore pmu counting support
Hi, all
Here is the V6 patches to add uncore counting support for Nehalem, Sandy Bridge and Sandy Bridge-EP, applied on top of current tip. The code is based on Lin Ming's old patches.
For Nehalem and Sandy Bridge-EP, A few general events are exported under sysfs directory:
/sys/bus/event_source/devices/${uncore_dev}/events/
Each file in the events directory defines an event. The content is a string such as:
config=1,config1=2
You can use 'perf stat' to access to the uncore pmu. For example:
perf stat -a -C 0 -e 'uncore_imc_0/CAS_COUNT_RD/' sleep 1 perf stat -a -C 0 -e 'uncore_imc_0/event=CAS_COUNT_RD/' sleep 1
Any comment is appreciated.
Thank you
---
Changes since v1:
- Modify perf tool to parse events from sysfs
- A few minor code cleanup
Changes since v2:
- Place all events for a particular socket onto a single cpu
- Make the events parser in perf tool reentrantable
- A few code cleanup
Changes since v3:
- Use per cpu pointer to track uncore box
- Rework the cpu hotplug code because topology_physical_package_id() return wrong result when the cpu is offline
- Rework the event alias code, event terms are stored in the alias structure instead events string
Changes since v4:
- Include Jiri's uncore related changes patch set
- Add pmu/event=alias/ syntax support
Changes since v5:
- All lower case letters for uncore pmu name
- Make event alias case insensitive
PATCH v6 1/13 perf: Export perf_assign_events
From: "Yan, Zheng" <[email protected]>
Export perf_assign_events so the uncore code can use it to schedule events.
--- arch/x86/kernel/cpu/perf_event.c | 6 +++--- arch/x86/kernel/cpu/perf_event.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/perf_event.c +3 -3
@@ -626,7 +626,7 @@ static bool __perf_sched_find_counter(struct perf_sched *sched) c = sched->constraints[sched->state.event];/* Prefer fixed purpose counters */ -if (x86_pmu.num_counters_fixed) { +if (c->idxmsk64 & ((u64)-1 <<X86_PMC_IDX_FIXED )) { idx =X86_PMC_IDX_FIXED ;for_each_set_bit_from (idx, c->idxmsk,X86_PMC_IDX_MAX ) {if (!__test_and_set_bit (idx, sched->state.used))
@@ -693,8 +693,8 @@ static bool perf_sched_next_event(struct perf_sched *sched)/* * Assign a counter for each event. */ -static int perf_assign_events (struct event_constraint **constraints,int n, -int wmin,int wmax,int *assign) +int perf_assign_events (struct event_constraint **constraints,int n, +int wmin,int wmax,int *assign) {struct perf_sched sched;
arch/x86/kernel/cpu/perf_event.h +2 -0
@@ -481,6 +481,8 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,void x86_pmu_enable_all (int added); +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);void x86_pmu_stop (struct perf_event *event,int flags);
Signature · 1 line
1.7.6.5
[tip:perf/core] perf: Export perf_assign_events()
Commit-ID: 4b4969b14490a4f65b572b8f180164181104b5e1 Gitweb: http://git.kernel.org/tip/4b4969b14490a4f65b572b8f180164181104b5e1 Author: Yan, Zheng <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:30 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:20 +0200
perf: Export perf_assign_events()
Export perf_assign_events() so the uncore code can use it to schedule events.
--- arch/x86/kernel/cpu/perf_event.c | 6 +++--- arch/x86/kernel/cpu/perf_event.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/perf_event.c +3 -3
@@ -626,7 +626,7 @@ static bool __perf_sched_find_counter(struct perf_sched *sched) c = sched->constraints[sched->state.event];/* Prefer fixed purpose counters */ -if (x86_pmu.num_counters_fixed) { +if (c->idxmsk64 & (~0ULL <<X86_PMC_IDX_FIXED )) { idx =X86_PMC_IDX_FIXED ;for_each_set_bit_from (idx, c->idxmsk,X86_PMC_IDX_MAX ) {if (!__test_and_set_bit (idx, sched->state.used))
@@ -693,8 +693,8 @@ static bool perf_sched_next_event(struct perf_sched *sched)/* * Assign a counter for each event. */ -static int perf_assign_events (struct event_constraint **constraints,int n, -int wmin,int wmax,int *assign) +int perf_assign_events (struct event_constraint **constraints,int n, +int wmin,int wmax,int *assign) {struct perf_sched sched;
arch/x86/kernel/cpu/perf_event.h +2 -0
@@ -481,6 +481,8 @@ static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,void x86_pmu_enable_all (int added); +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);void x86_pmu_stop (struct perf_event *event,int flags);
PATCH v6 2/13 perf: Avoid race between cpu hotplug and installing event
In reply to Yan, ZhengFrom: "Yan, Zheng" <[email protected]>
perf_event_open requires the cpu on which to install event is online, but the cpu can go offline after perf_event_open checks that. Add get_online_cpus()/put_online_cpus() pair to avoid the race.
--- kernel/events/core.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
kernel/events/core.c +5 -0
@@ -6248,6 +6248,8 @@ SYSCALL_DEFINE5(perf_event_open, } } +get_online_cpus (); + event =perf_event_alloc (&attr, cpu, task, group_leader,NULL ,NULL ,NULL );if (IS_ERR (event)) {
@@ -6387,6 +6389,8 @@ SYSCALL_DEFINE5(perf_event_open,perf_unpin_context (ctx);mutex_unlock (&ctx->mutex); +put_online_cpus (); + event->owner = current;mutex_lock (¤t->perf_event_mutex);
@@ -6415,6 +6419,7 @@ err_context: err_alloc:free_event (event); err_task: +put_online_cpus ();if (task)put_task_struct (task); err_group_fd:
Signature · 1 line
1.7.6.5
[tip:perf/core] perf: Avoid race between cpu hotplug and installing event
Commit-ID: fbfc623f8231c8d8c78aab5841e9c6e5811ab638 Gitweb: http://git.kernel.org/tip/fbfc623f8231c8d8c78aab5841e9c6e5811ab638 Author: Yan, Zheng <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:31 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:20 +0200
perf: Avoid race between cpu hotplug and installing event
perf_event_open() requires the cpu on which to install event is online, but the cpu can go offline after perf_event_open checks that. Add a get_online_cpus()/put_online_cpus() pair to avoid the race.
--- kernel/events/core.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
kernel/events/core.c +5 -0
@@ -6252,6 +6252,8 @@ SYSCALL_DEFINE5(perf_event_open, } } +get_online_cpus (); + event =perf_event_alloc (&attr, cpu, task, group_leader,NULL ,NULL ,NULL );if (IS_ERR (event)) {
@@ -6391,6 +6393,8 @@ SYSCALL_DEFINE5(perf_event_open,perf_unpin_context (ctx);mutex_unlock (&ctx->mutex); +put_online_cpus (); + event->owner = current;mutex_lock (¤t->perf_event_mutex);
@@ -6419,6 +6423,7 @@ err_context: err_alloc:free_event (event); err_task: +put_online_cpus ();if (task)put_task_struct (task); err_group_fd:
PATCH v6 3/13 perf: Allow pmu to choose cpu on which to install event
In reply to Yan, ZhengFrom: "Yan, Zheng" <[email protected]>
Allow the pmu->event_init callback to change event->cpu, so pmu can choose cpu on which to install event.
--- kernel/events/core.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
kernel/events/core.c +4 -4
@@ -6302,7 +6302,7 @@ SYSCALL_DEFINE5(perf_event_open,/* * Get the target context (task or percpu): */ - ctx =find_get_context (pmu, task, cpu); + ctx =find_get_context (pmu, task, event->cpu);if (IS_ERR (ctx)) { err =PTR_ERR (ctx); goto err_alloc;
@@ -6375,16 +6375,16 @@ SYSCALL_DEFINE5(perf_event_open,mutex_lock (&ctx->mutex);if (move_group) { -perf_install_in_context (ctx, group_leader, cpu); +perf_install_in_context (ctx, group_leader, event->cpu);get_ctx (ctx);list_for_each_entry (sibling, &group_leader->sibling_list, group_entry) { -perf_install_in_context (ctx, sibling, cpu); +perf_install_in_context (ctx, sibling, event->cpu);get_ctx (ctx); } } -perf_install_in_context (ctx, event, cpu); +perf_install_in_context (ctx, event, event->cpu); ++ctx->generation;perf_unpin_context (ctx);mutex_unlock (&ctx->mutex);
Signature · 1 line
1.7.6.5
[tip:perf/core] perf: Allow the PMU driver to choose the CPU on which to install events
Commit-ID: e2d37cd213dcc0aeb3db4b37b9bd1710fe36fbf7 Gitweb: http://git.kernel.org/tip/e2d37cd213dcc0aeb3db4b37b9bd1710fe36fbf7 Author: Yan, Zheng <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:32 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:21 +0200
perf: Allow the PMU driver to choose the CPU on which to install events
Allow the pmu->event_init callback to change event->cpu, so the PMU driver can choose the CPU on which to install events.
--- kernel/events/core.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
kernel/events/core.c +4 -4
@@ -6306,7 +6306,7 @@ SYSCALL_DEFINE5(perf_event_open,/* * Get the target context (task or percpu): */ - ctx =find_get_context (pmu, task, cpu); + ctx =find_get_context (pmu, task, event->cpu);if (IS_ERR (ctx)) { err =PTR_ERR (ctx); goto err_alloc;
@@ -6379,16 +6379,16 @@ SYSCALL_DEFINE5(perf_event_open,mutex_lock (&ctx->mutex);if (move_group) { -perf_install_in_context (ctx, group_leader, cpu); +perf_install_in_context (ctx, group_leader, event->cpu);get_ctx (ctx);list_for_each_entry (sibling, &group_leader->sibling_list, group_entry) { -perf_install_in_context (ctx, sibling, cpu); +perf_install_in_context (ctx, sibling, event->cpu);get_ctx (ctx); } } -perf_install_in_context (ctx, event, cpu); +perf_install_in_context (ctx, event, event->cpu); ++ctx->generation;perf_unpin_context (ctx);mutex_unlock (&ctx->mutex);
PATCH v6 4/13 perf: Introduce perf_pmu_migrate_context
In reply to Yan, ZhengFrom: "Yan, Zheng" <[email protected]>
Originally from Peter Zijlstra. The helper migrates perf events from one cpu to another cpu.
--- include/linux/perf_event.h | 2 ++ kernel/events/core.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 0 deletions(-)
include/linux/perf_event.h +2 -0
@@ -1107,6 +1107,8 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr,struct task_struct *task, perf_overflow_handler_t callback, void *context); +extern void perf_pmu_migrate_context (struct pmu *pmu, +int src_cpu,int dst_cpu);extern u64 perf_event_read_value (struct perf_event *event,u64 *enabled,u64 *running);
kernel/events/core.c +36 -0
@@ -1641,6 +1641,8 @@ perf_install_in_context(struct perf_event_context *ctx,lockdep_assert_held (&ctx->mutex); event->ctx = ctx; +if (event->cpu !=-1 ) + event->cpu = cpu;if (!task) {/*
@@ -6375,6 +6377,7 @@ SYSCALL_DEFINE5(perf_event_open,mutex_lock (&ctx->mutex);if (move_group) { +synchronize_rcu ();perf_install_in_context (ctx, group_leader, event->cpu);get_ctx (ctx); list_for_each_entry(sibling, &group_leader->sibling_list,
@@ -6480,6 +6483,39 @@ err: }EXPORT_SYMBOL_GPL (perf_event_create_kernel_counter); +void perf_pmu_migrate_context (struct pmu *pmu,int src_cpu,int dst_cpu) +{ +struct perf_event_context *src_ctx; +struct perf_event_context *dst_ctx; +struct perf_event *event, *tmp; +LIST_HEAD (events); + + src_ctx = &per_cpu_ptr (pmu->pmu_cpu_context, src_cpu)->ctx; + dst_ctx = &per_cpu_ptr (pmu->pmu_cpu_context, dst_cpu)->ctx; + +mutex_lock (&src_ctx->mutex); +list_for_each_entry_safe (event, tmp, &src_ctx->event_list, + event_entry) { +perf_remove_from_context (event); +put_ctx (src_ctx); +list_add (&event->event_entry, &events); + } +mutex_unlock (&src_ctx->mutex); + +synchronize_rcu (); + +mutex_lock (&dst_ctx->mutex); +list_for_each_entry_safe (event, tmp, &events, event_entry) { +list_del (&event->event_entry); +if (event->state >=PERF_EVENT_STATE_OFF ) + event->state =PERF_EVENT_STATE_INACTIVE ; +perf_install_in_context (dst_ctx, event, dst_cpu); +get_ctx (dst_ctx); + } +mutex_unlock (&dst_ctx->mutex); +} +EXPORT_SYMBOL_GPL (perf_pmu_migrate_context); +static void sync_child_event (struct perf_event *child_event,struct task_struct *child) {
Signature · 1 line
1.7.6.5
[tip:perf/core] perf: Introduce perf_pmu_migrate_context()
Commit-ID: 0cda4c023132aa93f2dd94811061f812e88daf4c Gitweb: http://git.kernel.org/tip/0cda4c023132aa93f2dd94811061f812e88daf4c Author: Yan, Zheng <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:33 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:21 +0200
perf: Introduce perf_pmu_migrate_context()
Originally from Peter Zijlstra. The helper migrates perf events from one cpu to another cpu.
--- include/linux/perf_event.h | 2 ++ kernel/events/core.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 0 deletions(-)
include/linux/perf_event.h +2 -0
@@ -1107,6 +1107,8 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr,struct task_struct *task, perf_overflow_handler_t callback, void *context); +extern void perf_pmu_migrate_context (struct pmu *pmu, +int src_cpu,int dst_cpu);extern u64 perf_event_read_value (struct perf_event *event,u64 *enabled,u64 *running);
kernel/events/core.c +36 -0
@@ -1645,6 +1645,8 @@ perf_install_in_context(struct perf_event_context *ctx,lockdep_assert_held (&ctx->mutex); event->ctx = ctx; +if (event->cpu !=-1 ) + event->cpu = cpu;if (!task) {/*
@@ -6379,6 +6381,7 @@ SYSCALL_DEFINE5(perf_event_open,mutex_lock (&ctx->mutex);if (move_group) { +synchronize_rcu ();perf_install_in_context (ctx, group_leader, event->cpu);get_ctx (ctx); list_for_each_entry(sibling, &group_leader->sibling_list,
@@ -6484,6 +6487,39 @@ err: }EXPORT_SYMBOL_GPL (perf_event_create_kernel_counter); +void perf_pmu_migrate_context (struct pmu *pmu,int src_cpu,int dst_cpu) +{ +struct perf_event_context *src_ctx; +struct perf_event_context *dst_ctx; +struct perf_event *event, *tmp; +LIST_HEAD (events); + + src_ctx = &per_cpu_ptr (pmu->pmu_cpu_context, src_cpu)->ctx; + dst_ctx = &per_cpu_ptr (pmu->pmu_cpu_context, dst_cpu)->ctx; + +mutex_lock (&src_ctx->mutex); +list_for_each_entry_safe (event, tmp, &src_ctx->event_list, + event_entry) { +perf_remove_from_context (event); +put_ctx (src_ctx); +list_add (&event->event_entry, &events); + } +mutex_unlock (&src_ctx->mutex); + +synchronize_rcu (); + +mutex_lock (&dst_ctx->mutex); +list_for_each_entry_safe (event, tmp, &events, event_entry) { +list_del (&event->event_entry); +if (event->state >=PERF_EVENT_STATE_OFF ) + event->state =PERF_EVENT_STATE_INACTIVE ; +perf_install_in_context (dst_ctx, event, dst_cpu); +get_ctx (dst_ctx); + } +mutex_unlock (&dst_ctx->mutex); +} +EXPORT_SYMBOL_GPL (perf_pmu_migrate_context); +static void sync_child_event (struct perf_event *child_event,struct task_struct *child) {
PATCH v6 5/13 perf: Generic intel uncore support
In reply to Yan, ZhengFrom: "Yan, Zheng" <[email protected]>
This patch adds the generic intel uncore pmu support, including helper functions that add/delete uncore events, a hrtimer that periodically polls the counters to avoid overflow and code that places all events for a particular socket onto a single cpu. The code design is based on the structure of Sandy Bridge-EP's uncore subsystem, which consists of a variety of components, each component contain one or more boxes.
--- arch/x86/kernel/cpu/Makefile | 4 +- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 878 +++++++++++++++++++++++++ arch/x86/kernel/cpu/perf_event_intel_uncore.h | 204 ++++++ 3 files changed, 1085 insertions(+), 1 deletions(-) create mode 100644 arch/x86/kernel/cpu/perf_event_intel_uncore.c create mode 100644 arch/x86/kernel/cpu/perf_event_intel_uncore.h
arch/x86/kernel/cpu/Makefile +3 -1
@@ -32,7 +32,9 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o ifdef CONFIG_PERF_EVENTS obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o -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 +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_p4.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o endif obj-$(CONFIG_X86_MCE) += mcheck/
arch/x86/kernel/cpu/perf_event_intel_uncore.c new file +878 -0
878 lines not on this page · raw message
arch/x86/kernel/cpu/perf_event_intel_uncore.h new file +204 -0
204 lines not on this page · raw message
Signature · 1 line
1.7.6.5
[tip:perf/core] perf/x86: Add generic Intel uncore PMU support
Commit-ID: 087bfbb032691262f2f7d52b910652450c5554b8 Gitweb: http://git.kernel.org/tip/087bfbb032691262f2f7d52b910652450c5554b8 Author: Yan, Zheng <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:34 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:22 +0200
perf/x86: Add generic Intel uncore PMU support
This patch adds the generic Intel uncore PMU support, including helper functions that add/delete uncore events, a hrtimer that periodically polls the counters to avoid overflow and code that places all events for a particular socket onto a single cpu.
The code design is based on the structure of Sandy Bridge-EP's uncore subsystem, which consists of a variety of components, each component contains one or more "boxes".
(Tooling support follows in the next patches.)
--- arch/x86/kernel/cpu/Makefile | 4 +- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 878 +++++++++++++++++++++++++ arch/x86/kernel/cpu/perf_event_intel_uncore.h | 204 ++++++ 3 files changed, 1085 insertions(+), 1 deletions(-)
arch/x86/kernel/cpu/Makefile +3 -1
@@ -32,7 +32,9 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o ifdef CONFIG_PERF_EVENTS obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o -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 +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_p4.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o endif obj-$(CONFIG_X86_MCE) += mcheck/
arch/x86/kernel/cpu/perf_event_intel_uncore.c new file +878 -0
878 lines not on this page · raw message
arch/x86/kernel/cpu/perf_event_intel_uncore.h new file +204 -0
204 lines not on this page · raw message
Re: [tip:perf/core] perf/x86: Add generic Intel uncore PMU support
Quoted 26 lines · Zheng
This patch adds the generic Intel uncore PMU support, including helper functions that add/delete uncore events, a hrtimer that periodically polls the counters to avoid overflow and code that places all events for a particular socket onto a single cpu.
The code design is based on the structure of Sandy Bridge-EP's uncore subsystem, which consists of a variety of components, each component contains one or more "boxes".
(Tooling support follows in the next patches.)
...
arch/x86/kernel/cpu/perf_event_intel_uncore.c new file +13
-0+static enum hrtimer_restart uncore_pmu_hrtimer (struct hrtimer *hrtimer) +{ +struct intel_uncore_box *box; +unsigned long flags; +int bit; + + box = container_of(hrtimer, struct intel_uncore_box, hrtimer); +if (!box->n_active || box->cpu !=smp_processor_id ()) +return HRTIMER_NORESTART ; +/* +* disable local interrupt to prevent uncore_pmu_event_start/stop +* to interrupt the update process +*/
arch/x86/kernel/cpu/perf_event_intel_uncore.c line 82
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c new file +10
-0+local_irq_save (flags); + +for_each_set_bit (bit, box->active_mask,UNCORE_PMC_IDX_MAX ) +uncore_perf_event_update (box, box->events[bit]); + +local_irq_restore (flags); + +hrtimer_forward_now (hrtimer,ns_to_ktime (UNCORE_PMU_HRTIMER_INTERVAL )); +return HRTIMER_RESTART ; +}
i386 allmodconfig:
arch/x86/kernel/cpu/perf_event_intel_uncore.c: In function 'uncore_pmu_hrtimer':arch/x86/kernel/cpu/perf_event_intel_uncore.c:728: warning: integer overflow in expression arch/x86/kernel/cpu/perf_event_intel_uncore.c: In function 'uncore_pmu_start_hrtimer':arch/x86/kernel/cpu/perf_event_intel_uncore.c:735: warning: integer overflow in expression
Should we even be compiling this code in an i386 build?
Regardless of that, we have some head-scratching to do:
#define UNCORE_PMU_HRTIMER_INTERVAL (60 * NSEC_PER_SEC)
and
#define NSEC_PER_SEC 1000000000L
and 60 billion doesn't fit in 32 bits. So do we fix the perf_event_intel_uncore.c callsites? Or do we fix the UNCORE_PMU_HRTIMER_INTERVAL definition? Or do we fix the NSEC_PER_SEC definition?
I'm thinking perhaps the latter. What *is* the type of a nanosecond in Linux? include/linux/ktime.h is pretty insistent that it is u64. If so, NSEC_PER_SEC should logically have type ULL. But changing both its size and signedness is a pretty big change.
Re: [tip:perf/core] perf/x86: Add generic Intel uncore PMU support
Quoted 1 line · On Thu, 21 Jun 2012 15:43:34 -0700 Andrew Morton <[email protected]>…
i386 allmodconfig:
err, make that allnoconfig.
H. Peter Anvin
reviewerRe: [tip:perf/core] perf/x86: Add generic Intel uncore PMU support
In reply to Andrew MortonQuoted 15 lines · Andrew Morton
Regardless of that, we have some head-scratching to do:
#define
UNCORE_PMU_HRTIMER_INTERVAL(60 *NSEC_PER_SEC)and
#define
NSEC_PER_SEC1000000000Land 60 billion doesn't fit in 32 bits. So do we fix the
perf_event_intel_uncore.ccallsites? Or do we fix theUNCORE_PMU_HRTIMER_INTERVALdefinition? Or do we fix theNSEC_PER_SECdefinition?
Quoted 4 lines
I'm thinking perhaps the latter. What *is* the type of a nanosecond in Linux?
include/linux/ktime.his pretty insistent that it is u64. If so,NSEC_PER_SECshould logically have type ULL. But changing both its size and signedness is a pretty big change.
We could change the size only. The range from 9223372036.854775808 to 18446744073.709551615 seconds (292-584 years) isn't really that significant.
-hpa
Re: [tip:perf/core] perf/x86: Add generic Intel uncore PMU support
Quoted 16 lines · On Thu, 21 Jun 2012 15:47:49 -0700 "H. Peter Anvin" <[email protected]> wrote:
Quoted 15 lines · Andrew Morton
Regardless of that, we have some head-scratching to do:
#define
UNCORE_PMU_HRTIMER_INTERVAL(60 *NSEC_PER_SEC)and
#define
NSEC_PER_SEC1000000000Land 60 billion doesn't fit in 32 bits. So do we fix the
perf_event_intel_uncore.ccallsites? Or do we fix theUNCORE_PMU_HRTIMER_INTERVALdefinition? Or do we fix theNSEC_PER_SECdefinition?
Quoted 8 lines
Quoted 4 lines
I'm thinking perhaps the latter. What *is* the type of a nanosecond in Linux?
include/linux/ktime.his pretty insistent that it is u64. If so,NSEC_PER_SECshould logically have type ULL. But changing both its size and signedness is a pretty big change.We could change the size only. The range from 9223372036.854775808 to 18446744073.709551615 seconds (292-584 years) isn't really that significant.
What *is* significant is the effect of a signedness change upon arithmetic, conversions, warnings, etc. And whether such a change might actually introduce bugs.
Back away and ask the broader questions: why did ktime_t choose unsigned? Is time a signed concept? What is the right thing to do here, from a long-term design perspective?
H. Peter Anvin
reviewerRe: [tip:perf/core] perf/x86: Add generic Intel uncore PMU support
Quoted 9 lines · Andrew Morton
What *is* significant is the effect of a signedness change upon arithmetic, conversions, warnings, etc. And whether such a change might actually introduce bugs.
Back away and ask the broader questions: why did
ktime_tchoose unsigned? Is time a signed concept? What is the right thing to do here, from a long-term design perspective?
Time is definitely a signed concept -- it has no beginning or end (well, the Big Bang, but the ±110 Myr or so uncertainty of the exact timing of the Big Bang makes it a horridly awkward choice for epoch.)
Now, for some users of time you can inherently guarantee there will never be any references to time before a particular event, e.g. system boot, in which case an unsigned number might make sense, but as a whole I think using a signed type as time_t in nearly all Unix implementation was The Right Thing.
-hpa
Re: [tip:perf/core] perf/x86: Add generic Intel uncore PMU support
Quoted 15 lines · On Thu, 21 Jun 2012 16:10:23 -0700 "H. Peter Anvin" <[email protected]> wrote:
Quoted 9 lines · Andrew Morton
What *is* significant is the effect of a signedness change upon arithmetic, conversions, warnings, etc. And whether such a change might actually introduce bugs.
Back away and ask the broader questions: why did
ktime_tchoose unsigned? Is time a signed concept? What is the right thing to do here, from a long-term design perspective?Time is definitely a signed concept -- it has no beginning or end (well, the Big Bang, but the __110 Myr or so uncertainty of the exact timing of the Big Bang makes it a horridly awkward choice for epoch.)
Quoted 6 lines
Now, for some users of time you can inherently guarantee there will never be any references to time before a particular event, e.g. system boot, in which case an unsigned number might make sense, but as a whole I think using a signed type as
time_tin nearly all Unix implementation was The Right Thing.
So why is ktime_t unsigned?
Re: [tip:perf/core] perf/x86: Add generic Intel uncore PMU support
Quoted 18 lines · On Thu, 21 Jun 2012 16:15:58 -0700 Andrew Morton <[email protected]>…
Quoted 15 lines · On Thu, 21 Jun 2012 16:10:23 -0700 "H. Peter Anvin" <[email protected]> wrote:
Quoted 9 lines · Andrew Morton
What *is* significant is the effect of a signedness change upon arithmetic, conversions, warnings, etc. And whether such a change might actually introduce bugs.
Back away and ask the broader questions: why did
ktime_tchoose unsigned? Is time a signed concept? What is the right thing to do here, from a long-term design perspective?Time is definitely a signed concept -- it has no beginning or end (well, the Big Bang, but the __110 Myr or so uncertainty of the exact timing of the Big Bang makes it a horridly awkward choice for epoch.)
Quoted 8 lines
Quoted 6 lines
Now, for some users of time you can inherently guarantee there will never be any references to time before a particular event, e.g. system boot, in which case an unsigned number might make sense, but as a whole I think using a signed type as
time_tin nearly all Unix implementation was The Right Thing.So why is
ktime_tunsigned?
err, actually, it isn't. But lots of the APIs to manipulate ktime_t use u64. Reason?
I do agree that time quantities should be signed.
H. Peter Anvin
reviewerRe: [tip:perf/core] perf/x86: Add generic Intel uncore PMU support
Quoted 7 lines · Andrew Morton
Quoted 2 lines
So why is
ktime_tunsigned?err, actually, it isn't. But lots of the APIs to manipulate
ktime_tuse u64. Reason?I do agree that time quantities should be signed.
No idea... probably because when representing an actual wall time since the POSIX epoch that can happen during the poweron time on the system, the number will be positive since the POSIX epoch predates Linux.
-hpa
Re: [tip:perf/core] perf/x86: Add generic Intel uncore PMU support
Quoted 4 lines · On Thu, 21 Jun 2012 16:22:50 -0700 "H. Peter Anvin" <[email protected]> wrote:
Quoted 3 lines · Andrew Morton
Quoted 2 lines
So why is
ktime_tunsigned?
Quoted 9 lines
Quoted 4 lines
err, actually, it isn't. But lots of the APIs to manipulate
ktime_tuse u64. Reason?I do agree that time quantities should be signed.
No idea... probably because when representing an actual wall time since the POSIX epoch that can happen during the poweron time on the system, the number will be positive since the POSIX epoch predates Linux.
hm.
I'll stick this in my tree and see what happens:
From: Andrew Morton <[email protected]>
Subject: include/linux/time.h: make NSEC_PER_SEC 64-bit on 32-bit architectures
Nanoseconds are usually represented with 64-bit types (s64 and sometimes u64). The 32-bit definition of NSEC_PER_SEC can lead to compile-time and runtime arithmetic overflows on 32-bit systems.
So switch NSEC_PER_SEC to a 64-bit type using "LL".
---
include/linux/time.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/time.h renamed from include/linux/time.h~include-linux-timeh-make-nsec_per_sec-64-bit-on-32-bit-architectures +1 -1
@@ -37,7 +37,7 @@ extern struct timezone sys_tz;#define NSEC_PER_USEC 1000L#define NSEC_PER_MSEC 1000000L#define USEC_PER_SEC 1000000L -#define NSEC_PER_SEC 1000000000L +#define NSEC_PER_SEC 1000000000LL#define FSEC_PER_SEC 1000000000000000LL#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
_
Re: [tip:perf/core] perf/x86: Add generic Intel uncore PMU support
In reply to Andrew MortonQuoted 1 line · Andrew Morton
Should we even be compiling this code in an i386 build?
Some people still run i386 kernels on their brand spanking new Intel hardware.. So yeah probably.
But yeah, we could make it x86_64 only.. not really a strong case though.
Re: [PATCH V6 05/13] perf: Generic intel uncore support
In reply to Yan, ZhengQuoted 907 lines · Zheng
From: "Yan, Zheng" <[email protected]>
This patch adds the generic intel uncore pmu support, including helper functions that add/delete uncore events, a hrtimer that periodically polls the counters to avoid overflow and code that places all events for a particular socket onto a single cpu. The code design is based on the structure of Sandy Bridge-EP's uncore subsystem, which consists of a variety of components, each component contain one or more boxes.
Signed-off-by Zheng Yan <[email protected]>--- arch/x86/kernel/cpu/Makefile | 4 +- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 878 +++++++++++++++++++++++++ arch/x86/kernel/cpu/perf_event_intel_uncore.h | 204 ++++++ 3 files changed, 1085 insertions(+), 1 deletions(-) create mode 100644 arch/x86/kernel/cpu/perf_event_intel_uncore.c create mode 100644 arch/x86/kernel/cpu/perf_event_intel_uncore.harch/x86/kernel/cpu/Makefile +3
-1@@ -32,7 +32,9 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o ifdef CONFIG_PERF_EVENTS obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o -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 +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_p4.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o endif obj-$(CONFIG_X86_MCE) += mcheck/arch/x86/kernel/cpu/perf_event_intel_uncore.c new file +868
-0@@ -0,0 +1,878 @@ +#include "perf_event_intel_uncore.h" + +static struct intel_uncore_type *empty_uncore[] = {NULL , }; +static struct intel_uncore_type **msr_uncores = empty_uncore; + +/* mask of cpus that collect uncore events */ +static cpumask_t uncore_cpu_mask; + +/* constraint for the fixed counter */ +static struct event_constraint constraint_fixed = +EVENT_CONSTRAINT ((u64)-1 ,1 <<UNCORE_PMC_IDX_FIXED , (u64)-1 ); + +static void uncore_assign_hw_event (struct intel_uncore_box *box, +struct perf_event *event,int idx) +{ +struct hw_perf_event *hwc = &event->hw; + + hwc->idx = idx; + hwc->last_tag = ++box->tags[idx]; + +if (hwc->idx ==UNCORE_PMC_IDX_FIXED ) { + hwc->event_base =uncore_msr_fixed_ctr (box); + hwc->config_base =uncore_msr_fixed_ctl (box); +return ; + } + + hwc->config_base =uncore_msr_event_ctl (box, hwc->idx); + hwc->event_base =uncore_msr_perf_ctr (box, hwc->idx); +} + +static void uncore_perf_event_update (struct intel_uncore_box *box, +struct perf_event *event) +{ +u64 prev_count, new_count, delta; +int shift; + +if (event->hw.idx >=UNCORE_PMC_IDX_FIXED ) + shift =64 -uncore_fixed_ctr_bits (box); +else + shift =64 -uncore_perf_ctr_bits (box); + +/* the hrtimer might modify the previous event value */ +again: + prev_count =local64_read (&event->hw.prev_count); + new_count =uncore_read_counter (box, event); +if (local64_xchg (&event->hw.prev_count, new_count) != prev_count) + goto again; + + delta = (new_count << shift) - (prev_count << shift); + delta >>= shift; + +local64_add (delta, &event->count); +} + +/* +* The overflow interrupt is unavailable for SandyBridge-EP, is broken +* for SandyBridge. So we use hrtimer to periodically poll the counter +* to avoid overflow. +*/ +static enum hrtimer_restart uncore_pmu_hrtimer (struct hrtimer *hrtimer) +{ +struct intel_uncore_box *box; +unsigned long flags; +int bit; + + box = container_of(hrtimer, struct intel_uncore_box, hrtimer); +if (!box->n_active || box->cpu !=smp_processor_id ()) +return HRTIMER_NORESTART ; +/* +* disable local interrupt to prevent uncore_pmu_event_start/stop +* to interrupt the update process +*/ +local_irq_save (flags); + +for_each_set_bit (bit, box->active_mask,UNCORE_PMC_IDX_MAX ) +uncore_perf_event_update (box, box->events[bit]); + +local_irq_restore (flags); + +hrtimer_forward_now (hrtimer,ns_to_ktime (UNCORE_PMU_HRTIMER_INTERVAL )); +return HRTIMER_RESTART ; +} + +static void uncore_pmu_start_hrtimer (struct intel_uncore_box *box) +{ +__hrtimer_start_range_ns (&box->hrtimer, +ns_to_ktime (UNCORE_PMU_HRTIMER_INTERVAL ),0 , +HRTIMER_MODE_REL_PINNED ,0 ); +} + +static void uncore_pmu_cancel_hrtimer (struct intel_uncore_box *box) +{ +hrtimer_cancel (&box->hrtimer); +} + +static void uncore_pmu_init_hrtimer (struct intel_uncore_box *box) +{ +hrtimer_init (&box->hrtimer,CLOCK_MONOTONIC ,HRTIMER_MODE_REL ); + box->hrtimer.function = uncore_pmu_hrtimer; +} + +struct intel_uncore_box *uncore_alloc_box (int cpu) +{ +struct intel_uncore_box *box; + + box =kmalloc_node (sizeof (*box),GFP_KERNEL | __GFP_ZERO, +cpu_to_node (cpu)); +if (!box) +return NULL ; + +uncore_pmu_init_hrtimer (box); +atomic_set (&box->refcnt,1 ); + box->cpu =-1 ; + box->phys_id =-1 ; + +return box; +} + +static struct intel_uncore_box * +uncore_pmu_to_box (struct intel_uncore_pmu *pmu,int cpu) +{ +return *per_cpu_ptr (pmu->box, cpu); +} + +static struct intel_uncore_pmu *uncore_event_to_pmu (struct perf_event *event) +{ + return container_of(event->pmu, struct intel_uncore_pmu, pmu); +} + +static struct intel_uncore_box *uncore_event_to_box (struct perf_event *event) +{ +/* +* perf core schedules event on the basis of cpu, uncore events are +* collected by one of the cpus inside a physical package. +*/ +return uncore_pmu_to_box (uncore_event_to_pmu (event), +smp_processor_id ()); +} + +static int uncore_collect_events (struct intel_uncore_box *box, +struct perf_event *leader,bool dogrp) +{ +struct perf_event *event; +int n, max_count; + + max_count = box->pmu->type->num_counters; +if (box->pmu->type->fixed_ctl) + max_count++; + +if (box->n_events >= max_count) +return -EINVAL ; + + n = box->n_events; + box->event_list[n] = leader; + n++; +if (!dogrp) +return n; + +list_for_each_entry (event, &leader->sibling_list, group_entry) { +if (event->state <=PERF_EVENT_STATE_OFF ) +continue ; + +if (n >= max_count) +return -EINVAL ; + + box->event_list[n] = event; + n++; + } +return n; +} + +static struct event_constraint * +uncore_event_constraint (struct intel_uncore_type *type, +struct perf_event *event) +{ +struct event_constraint *c; + +if (event->hw.config == (u64)-1 ) +return &constraint_fixed; + +if (type->constraints) { +for_each_event_constraint (c, type->constraints) { +if ((event->hw.config & c->cmask) == c->code) +return c; + } + } + +return &type->unconstrainted; +} + +static int uncore_assign_events (struct intel_uncore_box *box, +int assign[],int n) +{ +unsigned long used_mask[BITS_TO_LONGS (UNCORE_PMC_IDX_MAX )]; +struct event_constraint *c, *constraints[UNCORE_PMC_IDX_MAX ]; +int i, ret, wmin, wmax; +struct hw_perf_event *hwc; + +bitmap_zero (used_mask,UNCORE_PMC_IDX_MAX ); + +for (i =0 , wmin =UNCORE_PMC_IDX_MAX , wmax =0 ; i < n; i++) { + c =uncore_event_constraint (box->pmu->type, + box->event_list[i]); + constraints[i] = c; + wmin =min (wmin, c->weight); + wmax =max (wmax, c->weight); + } + +/* fastpath, try to reuse previous register */ +for (i =0 ; i < n; i++) { + hwc = &box->event_list[i]->hw; + c = constraints[i]; + +/* never assigned */ +if (hwc->idx ==-1 ) +break ; + +/* constraint still honored */ +if (!test_bit (hwc->idx, c->idxmsk)) +break ; + +/* not already used */ +if (test_bit (hwc->idx, used_mask)) +break ; + +__set_bit (hwc->idx, used_mask); + assign[i] = hwc->idx; + } +if (i == n) +return 0 ; + +/* slow path */ + ret =perf_assign_events (constraints, n, wmin, wmax, assign); +return ret ? -EINVAL :0 ; +} + +static void uncore_pmu_event_start (struct perf_event *event,int flags) +{ +struct intel_uncore_box *box =uncore_event_to_box (event); +int idx = event->hw.idx; + +if (WARN_ON_ONCE (!(event->hw.state &PERF_HES_STOPPED ))) +return ; + +if (WARN_ON_ONCE (idx ==-1 || idx >=UNCORE_PMC_IDX_MAX )) +return ; + + event->hw.state =0 ; + box->events[idx] = event; + box->n_active++; +__set_bit (idx, box->active_mask); + +local64_set (&event->hw.prev_count,uncore_read_counter (box, event)); +uncore_enable_event (box, event); + +if (box->n_active ==1 ) { +uncore_enable_box (box); +uncore_pmu_start_hrtimer (box); + } +} + +static void uncore_pmu_event_stop (struct perf_event *event,int flags) +{ +struct intel_uncore_box *box =uncore_event_to_box (event); +struct hw_perf_event *hwc = &event->hw; + +if (__test_and_clear_bit (hwc->idx, box->active_mask)) { +uncore_disable_event (box, event); + box->n_active--; + box->events[hwc->idx] =NULL ; +WARN_ON_ONCE (hwc->state &PERF_HES_STOPPED ); + hwc->state |=PERF_HES_STOPPED ; + +if (box->n_active ==0 ) { +uncore_disable_box (box); +uncore_pmu_cancel_hrtimer (box); + } + } + +if ((flags &PERF_EF_UPDATE ) && !(hwc->state &PERF_HES_UPTODATE )) { +/* +* Drain the remaining delta count out of a event +* that we are disabling: +*/ +uncore_perf_event_update (box, event); + hwc->state |=PERF_HES_UPTODATE ; + } +} + +static int uncore_pmu_event_add (struct perf_event *event,int flags) +{ +struct intel_uncore_box *box =uncore_event_to_box (event); +struct hw_perf_event *hwc = &event->hw; +int assign[UNCORE_PMC_IDX_MAX ]; +int i, n, ret; + +if (!box) +return -ENODEV ; + + ret = n =uncore_collect_events (box, event, false); +if (ret <0 ) +return ret; + + hwc->state =PERF_HES_UPTODATE |PERF_HES_STOPPED ; +if (!(flags &PERF_EF_START )) + hwc->state |=PERF_HES_ARCH ; + + ret =uncore_assign_events (box, assign, n); +if (ret) +return ret; + +/* save events moving to new counters */ +for (i =0 ; i < box->n_events; i++) { + event = box->event_list[i]; + hwc = &event->hw; + +if (hwc->idx == assign[i] && + hwc->last_tag == box->tags[assign[i]]) +continue ; +/* +* Ensure we don't accidentally enable a stopped +* counter simply because we rescheduled. +*/ +if (hwc->state &PERF_HES_STOPPED ) + hwc->state |=PERF_HES_ARCH ; + +uncore_pmu_event_stop (event,PERF_EF_UPDATE ); + } + +/* reprogram moved events into new counters */ +for (i =0 ; i < n; i++) { + event = box->event_list[i]; + hwc = &event->hw; + +if (hwc->idx != assign[i] || + hwc->last_tag != box->tags[assign[i]]) +uncore_assign_hw_event (box, event, assign[i]); +else if (i < box->n_events) +continue ; + +if (hwc->state &PERF_HES_ARCH ) +continue ; + +uncore_pmu_event_start (event,0 ); + } + box->n_events = n; + +return 0 ; +} + +static void uncore_pmu_event_del (struct perf_event *event,int flags) +{ +struct intel_uncore_box *box =uncore_event_to_box (event); +int i; + +uncore_pmu_event_stop (event,PERF_EF_UPDATE ); + +for (i =0 ; i < box->n_events; i++) { +if (event == box->event_list[i]) { +while (++i < box->n_events) + box->event_list[i -1 ] = box->event_list[i]; + + --box->n_events; +break ; + } + } + + event->hw.idx =-1 ; + event->hw.last_tag = ~0ULL ; +} + +static void uncore_pmu_event_read (struct perf_event *event) +{ +struct intel_uncore_box *box =uncore_event_to_box (event); +uncore_perf_event_update (box, event); +} + +/* +* validation ensures the group can be loaded onto the +* PMU if it was the only group available. +*/ +static int uncore_validate_group (struct intel_uncore_pmu *pmu, +struct perf_event *event) +{ +struct perf_event *leader = event->group_leader; +struct intel_uncore_box *fake_box; +int assign[UNCORE_PMC_IDX_MAX ]; +int ret = -EINVAL , n; + + fake_box =uncore_alloc_box (smp_processor_id ()); +if (!fake_box) +return -ENOMEM ; + + fake_box->pmu = pmu; +/* +* the event is not yet connected with its +* siblings therefore we must first collect +* existing siblings, then add the new event +* before we can simulate the scheduling +*/ + n =uncore_collect_events (fake_box, leader, true); +if (n <0 ) + goto out; + + fake_box->n_events = n; + n =uncore_collect_events (fake_box, event, false); +if (n <0 ) + goto out; + + fake_box->n_events = n; + + ret =uncore_assign_events (fake_box, assign, n); +out: +kfree (fake_box); +return ret; +} + +int uncore_pmu_event_init (struct perf_event *event) +{ +struct intel_uncore_pmu *pmu; +struct intel_uncore_box *box; +struct hw_perf_event *hwc = &event->hw; +int ret; + +if (event->attr.type != event->pmu->type) +return -ENOENT ; + + pmu =uncore_event_to_pmu (event); +/* no device found for this pmu */ +if (pmu->func_id <0 ) +return -ENOENT ; + +/* +* Uncore PMU does measure at all privilege level all the time. +* So it doesn't make sense to specify any exclude bits. +*/ +if (event->attr.exclude_user || event->attr.exclude_kernel || + event->attr.exclude_hv || event->attr.exclude_idle) +return -EINVAL ; + +/* Sampling not supported yet */ +if (hwc->sample_period) +return -EINVAL ; + +/* +* Place all uncore events for a particular physical package +* onto a single cpu +*/ +if (event->cpu <0 ) +return -EINVAL ; + box =uncore_pmu_to_box (pmu, event->cpu); +if (!box || box->cpu <0 ) +return -EINVAL ; + event->cpu = box->cpu; + +if (event->attr.config ==UNCORE_FIXED_EVENT ) { +/* no fixed counter */ +if (!pmu->type->fixed_ctl) +return -EINVAL ; +/* +* if there is only one fixed counter, only the first pmu +* can access the fixed counter +*/ +if (pmu->type->single_fixed && pmu->pmu_idx >0 ) +return -EINVAL ; + hwc->config = (u64)-1 ; + }else { + hwc->config = event->attr.config & pmu->type->event_mask; + } + + event->hw.idx =-1 ; + event->hw.last_tag = ~0ULL ; + +if (event->group_leader != event) + ret =uncore_validate_group (pmu, event); +else + ret =0 ; + +return ret; +} + +static int __init uncore_pmu_register (struct intel_uncore_pmu *pmu) +{ +int ret; + + pmu->pmu = (struct pmu ) { + .attr_groups = pmu->type->attr_groups, + .task_ctx_nr = perf_invalid_context, + .event_init = uncore_pmu_event_init, + .add = uncore_pmu_event_add, + .del = uncore_pmu_event_del, + .start = uncore_pmu_event_start, + .stop = uncore_pmu_event_stop, + .read = uncore_pmu_event_read, + }; + +if (pmu->type->num_boxes ==1 ) { +if (strlen (pmu->type->name) >0 ) +sprintf (pmu->name,"uncore_%s" , pmu->type->name); +else +sprintf (pmu->name,"uncore" ); + }else { +sprintf (pmu->name,"uncore_%s_%d" , pmu->type->name, + pmu->pmu_idx); + } + + ret =perf_pmu_register (&pmu->pmu, pmu->name,-1 ); +return ret; +} + +static void __init uncore_type_exit (struct intel_uncore_type *type) +{ +int i; + +for (i =0 ; i < type->num_boxes; i++) +free_percpu (type->pmus[i].box); +kfree (type->pmus); + type->pmus =NULL ; +kfree (type->attr_groups[1 ]); + type->attr_groups[1 ] =NULL ; +} + +static int __init uncore_type_init (struct intel_uncore_type *type) +{ +struct intel_uncore_pmu *pmus; +struct attribute_group *events_group; +struct attribute **attrs; +int i, j; + + pmus =kzalloc (sizeof (*pmus) * type->num_boxes,GFP_KERNEL ); +if (!pmus) +return -ENOMEM ; + + type->unconstrainted = (struct event_constraint ) +__EVENT_CONSTRAINT (0 , (1ULL << type->num_counters) -1 , +0 , type->num_counters,0 ); + +for (i =0 ; i < type->num_boxes; i++) { + pmus[i].func_id =-1 ; + pmus[i].pmu_idx = i; + pmus[i].type = type; + pmus[i].box = alloc_percpu(struct intel_uncore_box *); +if (!pmus[i].box) + goto fail; + } + +if (type->event_descs) { + i =0 ; +while (type->event_descs[i].attr.attr.name) + i++; + + events_group =kzalloc (sizeof (struct attribute *) * (i +1 ) + +sizeof (*events_group),GFP_KERNEL ); +if (!events_group) + goto fail; + + attrs = (struct attribute **)(events_group +1 ); + events_group->name ="events" ; + events_group->attrs = attrs; + +for (j =0 ; j < i; j++) + attrs[j] = &type->event_descs[j].attr.attr; + + type->attr_groups[1 ] = events_group; + } + + type->pmus = pmus; +return 0 ; +fail: +uncore_type_exit (type); +return -ENOMEM ; +} + +static int __init uncore_types_init (struct intel_uncore_type **types) +{ +int i, ret; + +for (i =0 ; types[i]; i++) { + ret =uncore_type_init (types[i]); +if (ret) + goto fail; + } +return 0 ; +fail: +while (--i >=0 ) +uncore_type_exit (types[i]); +return ret; +} + +static void __cpuinit uncore_cpu_dying (int cpu) +{ +struct intel_uncore_type *type; +struct intel_uncore_pmu *pmu; +struct intel_uncore_box *box; +int i, j; + +for (i =0 ; msr_uncores[i]; i++) { + type = msr_uncores[i]; +for (j =0 ; j < type->num_boxes; j++) { + pmu = &type->pmus[j]; + box = *per_cpu_ptr (pmu->box, cpu); + *per_cpu_ptr (pmu->box, cpu) =NULL ; +if (box &&atomic_dec_and_test (&box->refcnt)) +kfree (box); + } + } +} + +static int __cpuinit uncore_cpu_starting (int cpu) +{ +struct intel_uncore_type *type; +struct intel_uncore_pmu *pmu; +struct intel_uncore_box *box, *exist; +int i, j, k, phys_id; + + phys_id =topology_physical_package_id (cpu); + +for (i =0 ; msr_uncores[i]; i++) { + type = msr_uncores[i]; +for (j =0 ; j < type->num_boxes; j++) { + pmu = &type->pmus[j]; + box = *per_cpu_ptr (pmu->box, cpu); +/* called by uncore_cpu_init? */ +if (box && box->phys_id >=0 ) { +uncore_box_init (box); +continue ; + } + +for_each_online_cpu (k) { + exist = *per_cpu_ptr (pmu->box, k); +if (exist && exist->phys_id == phys_id) { +atomic_inc (&exist->refcnt); + *per_cpu_ptr (pmu->box, cpu) = exist; +kfree (box); + box =NULL ; +break ; + } + } + +if (box) { + box->phys_id = phys_id; +uncore_box_init (box); + } + } + } +return 0 ; +} + +static int __cpuinit uncore_cpu_prepare (int cpu,int phys_id) +{ +struct intel_uncore_type *type; +struct intel_uncore_pmu *pmu; +struct intel_uncore_box *box; +int i, j; + +for (i =0 ; msr_uncores[i]; i++) { + type = msr_uncores[i]; +for (j =0 ; j < type->num_boxes; j++) { + pmu = &type->pmus[j]; +if (pmu->func_id <0 ) + pmu->func_id = j; + + box =uncore_alloc_box (cpu); +if (!box) +return -ENOMEM ; + + box->pmu = pmu; + box->phys_id = phys_id; + *per_cpu_ptr (pmu->box, cpu) = box; + } + } +return 0 ; +} + +static void __cpuinit uncore_change_context (struct intel_uncore_type **uncores, +int old_cpu,int new_cpu) +{ +struct intel_uncore_type *type; +struct intel_uncore_pmu *pmu; +struct intel_uncore_box *box; +int i, j; + +for (i =0 ; uncores[i]; i++) { + type = uncores[i]; +for (j =0 ; j < type->num_boxes; j++) { + pmu = &type->pmus[j]; +if (old_cpu <0 ) + box =uncore_pmu_to_box (pmu, new_cpu); +else + box =uncore_pmu_to_box (pmu, old_cpu); +if (!box) +continue ; + +if (old_cpu <0 ) { +WARN_ON_ONCE (box->cpu !=-1 ); + box->cpu = new_cpu; +continue ; + } + +WARN_ON_ONCE (box->cpu != old_cpu); +if (new_cpu >=0 ) { +uncore_pmu_cancel_hrtimer (box); +perf_pmu_migrate_context (&pmu->pmu, + old_cpu, new_cpu); + box->cpu = new_cpu; + }else { + box->cpu =-1 ; + } + } + } +} + +static void __cpuinit uncore_event_exit_cpu (int cpu) +{ +int i, phys_id, target; + +/* if exiting cpu is used for collecting uncore events */ +if (!cpumask_test_and_clear_cpu (cpu, &uncore_cpu_mask)) +return ; + +/* find a new cpu to collect uncore events */ + phys_id =topology_physical_package_id (cpu); + target =-1 ; +for_each_online_cpu (i) { +if (i == cpu) +continue ; +if (phys_id ==topology_physical_package_id (i)) { + target = i; +break ; + } + } + +/* migrate uncore events to the new cpu */ +if (target >=0 ) +cpumask_set_cpu (target, &uncore_cpu_mask); + +uncore_change_context (msr_uncores, cpu, target); +} + +static void __cpuinit uncore_event_init_cpu (int cpu) +{ +int i, phys_id; + + phys_id =topology_physical_package_id (cpu); +for_each_cpu (i, &uncore_cpu_mask) { +if (phys_id ==topology_physical_package_id (i)) +return ; + } + +cpumask_set_cpu (cpu, &uncore_cpu_mask); + +uncore_change_context (msr_uncores,-1 , cpu); +} + +static int __cpuinit uncore_cpu_notifier (struct notifier_block *self, +unsigned long action,void *hcpu) +{ +unsigned int cpu = (long )hcpu; + +/* allocate/free data structure for uncore box */ +switch (action & ~CPU_TASKS_FROZEN ) { +case CPU_UP_PREPARE : +uncore_cpu_prepare (cpu,-1 ); +break ; +case CPU_STARTING : +uncore_cpu_starting (cpu); +break ; +case CPU_UP_CANCELED : +case CPU_DYING : +uncore_cpu_dying (cpu); +break ; +default : +break ; + } + +/* select the cpu that collects uncore events */ +switch (action & ~CPU_TASKS_FROZEN ) { +case CPU_DOWN_FAILED : +case CPU_STARTING : +uncore_event_init_cpu (cpu); +break ; +case CPU_DOWN_PREPARE : +uncore_event_exit_cpu (cpu); +break ; +default : +break ; + } + +return NOTIFY_OK ; +} + +static struct notifier_block uncore_cpu_nb__cpuinitdata = { + .notifier_call = uncore_cpu_notifier, +/* +* to migrate uncore events, our notifier should be executed +* before perf core's notifier. +*/ + .priority =CPU_PRI_PERF +1 , +}; + +static void __init uncore_cpu_setup (void *dummy) +{ +uncore_cpu_starting (smp_processor_id ()); +} + +static int __init uncore_cpu_init (void ) +{ +int ret, cpu; + +switch (boot_cpu_data.x86_model) { +default : +return 0 ; + } + + ret =uncore_types_init (msr_uncores); +if (ret) +return ret; + +get_online_cpus (); + +for_each_online_cpu (cpu) { +int i, phys_id =topology_physical_package_id (cpu); + +for_each_cpu (i, &uncore_cpu_mask) { +if (phys_id ==topology_physical_package_id (i)) { + phys_id =-1 ; +break ; + } + } +if (phys_id <0 ) +continue ; + +uncore_cpu_prepare (cpu, phys_id); +uncore_event_init_cpu (cpu); + } +on_each_cpu (uncore_cpu_setup,NULL ,1 ); + +register_cpu_notifier (&uncore_cpu_nb); + +put_online_cpus (); + +return 0 ; +} + +static int __init uncore_pmus_register (void ) +{ +struct intel_uncore_pmu *pmu; +struct intel_uncore_type *type; +int i, j; + +for (i =0 ; msr_uncores[i]; i++) { + type = msr_uncores[i]; +for (j =0 ; j < type->num_boxes; j++) { + pmu = &type->pmus[j]; +uncore_pmu_register (pmu); + } + } + +return 0 ; +} + +static int __init intel_uncore_init (void ) +{ +int ret; + +if (boot_cpu_data.x86_vendor !=X86_VENDOR_INTEL ) +return -ENODEV ; +
arch/x86/kernel/cpu/perf_event_intel_uncore.c line 878
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c new file +10
-0+ ret =uncore_cpu_init (); +if (ret) + goto fail; + +uncore_pmus_register (); +return 0 ; +fail: +return ret; +} +device_initcall (intel_uncore_init);
You cannot use device_initcall() here. Otherwise you're subject to linker ordering issues between intel_uncore_init() and the perf_event_sysfs_init() initcall. You need the perf_event sysfs support to be enabled BEFORE you init the uncore otherwise you won't see the uncore sysfs entries. Given how perf now relies on sysfs to parse the event, this is a showstopper.
The thing I have tried and which seems to work around the problem is to force intel_uncore_init() to be called in the next round of initcalls after device_initcall() via device_initcall_sync().
Note that this problem is not just specific to intel_uncore_init(). It also applies to ANY PMU module which wants to exports data via sysfs, e.g. IBS.
Re: [PATCH V6 05/13] perf: Generic intel uncore support
[...snip...]
Quoted 20 lines
Quoted 8 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c new file +8
-0+ +static int __init intel_uncore_init (void ) +{ +int ret; + +if (boot_cpu_data.x86_vendor !=X86_VENDOR_INTEL ) +return -ENODEV ; +arch/x86/kernel/cpu/perf_event_intel_uncore.c line 878
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c new file +10
-0+ ret =uncore_cpu_init (); +if (ret) + goto fail; + +uncore_pmus_register (); +return 0 ; +fail: +return ret; +} +device_initcall (intel_uncore_init);
Quoted 6 lines
You cannot use
device_initcall()here. Otherwise you're subject to linker ordering issues betweenintel_uncore_init()and theperf_event_sysfs_init()initcall. You need theperf_eventsysfs support to be enabled BEFORE you init the uncore otherwise you won't see the uncore sysfs entries. Given how perf now relies on sysfs to parse the event, this is a showstopper.
I think the ordering makes no matter. perf_event_sysfs_init() checks PMUs that were registered previously and allocates sysfs entries for them.
Regards
Yan, Zheng
Re: [PATCH V6 05/13] perf: Generic intel uncore support
Quoted 28 lines · Zheng
[...snip...]
Quoted 20 lines
Quoted 8 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c new file +8
-0+ +static int __init intel_uncore_init (void ) +{ +int ret; + +if (boot_cpu_data.x86_vendor !=X86_VENDOR_INTEL ) +return -ENODEV ; +arch/x86/kernel/cpu/perf_event_intel_uncore.c line 878
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c new file +10
-0+ ret =uncore_cpu_init (); +if (ret) + goto fail; + +uncore_pmus_register (); +return 0 ; +fail: +return ret; +} +device_initcall (intel_uncore_init);Quoted 6 lines
You cannot use
device_initcall()here. Otherwise you're subject to linker ordering issues betweenintel_uncore_init()and theperf_event_sysfs_init()initcall. You need theperf_eventsysfs support to be enabled BEFORE you init the uncore otherwise you won't see the uncore sysfs entries. Given how perf now relies on sysfs to parse the event, this is a showstopper.
Quoted 4 lines
I think the ordering makes no matter.
perf_event_sysfs_init()checks PMUs that were registered previously and allocates sysfs entries for them.
You're right, seems like I had a bad kernel that caused the problem to happen.
Thanks for checking.
PATCH v6 6/13 perf: Add Nehalem and Sandy Bridge uncore support
In reply to Yan, ZhengFrom: "Yan, Zheng" <[email protected]>
Add Intel Nehalem and Sandy Bridge uncore pmu support.
--- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 194 +++++++++++++++++++++++++ arch/x86/kernel/cpu/perf_event_intel_uncore.h | 50 +++++++ 2 files changed, 244 insertions(+), 0 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_uncore.c +194 -0
@@ -10,6 +10,192 @@ static cpumask_t uncore_cpu_mask;static struct event_constraint constraint_fixed =EVENT_CONSTRAINT ((u64)-1 ,1 <<UNCORE_PMC_IDX_FIXED , (u64)-1 ); +DEFINE_UNCORE_FORMAT_ATTR (event, event,"config:0-7" ); +DEFINE_UNCORE_FORMAT_ATTR (umask, umask,"config:8-15" ); +DEFINE_UNCORE_FORMAT_ATTR (edge, edge,"config:18" ); +DEFINE_UNCORE_FORMAT_ATTR (inv, inv,"config:23" ); +DEFINE_UNCORE_FORMAT_ATTR (cmask5, cmask,"config:24-28" ); +DEFINE_UNCORE_FORMAT_ATTR (cmask8, cmask,"config:24-31" ); + +/* Sandy Bridge uncore support */ +static void snb_uncore_msr_enable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +if (hwc->idx <UNCORE_PMC_IDX_FIXED ) +wrmsrl (hwc->config_base, hwc->config |SNB_UNC_CTL_EN ); +else +wrmsrl (hwc->config_base,SNB_UNC_CTL_EN ); +} + +static void snb_uncore_msr_disable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +wrmsrl (event->hw.config_base,0 ); +} + +static u64 snb_uncore_msr_read_counter (struct intel_uncore_box *box, +struct perf_event *event) +{ +u64 count; +rdmsrl (event->hw.event_base, count); +return count; +} + +static void snb_uncore_msr_init_box (struct intel_uncore_box *box) +{ +if (box->pmu->pmu_idx ==0 ) { +wrmsrl (SNB_UNC_PERF_GLOBAL_CTL , +SNB_UNC_GLOBAL_CTL_EN |SNB_UNC_GLOBAL_CTL_CORE_ALL ); + } +} + +static struct attribute *snb_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_cmask5.attr, +NULL , +}; + +static struct attribute_group snb_uncore_format_group = { + .name ="format" , + .attrs = snb_uncore_formats_attr, +}; + +static struct intel_uncore_ops snb_uncore_msr_ops = { + .init_box = snb_uncore_msr_init_box, + .disable_event = snb_uncore_msr_disable_event, + .enable_event = snb_uncore_msr_enable_event, + .read_counter = snb_uncore_msr_read_counter, +}; + +static struct event_constraint snb_uncore_cbo_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x80 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x83 ,0x1 ), +EVENT_CONSTRAINT_END +}; + +static struct intel_uncore_type snb_uncore_cbo = { + .name ="cbox" , + .num_counters =2 , + .num_boxes =4 , + .perf_ctr_bits =44 , + .fixed_ctr_bits =48 , + .perf_ctr =SNB_UNC_CBO_0_PER_CTR0 , + .event_ctl =SNB_UNC_CBO_0_PERFEVTSEL0 , + .fixed_ctr =SNB_UNC_FIXED_CTR , + .fixed_ctl =SNB_UNC_FIXED_CTR_CTRL , + .single_fixed =1 , + .event_mask =SNB_UNC_RAW_EVENT_MASK , + .msr_offset =SNB_UNC_CBO_MSR_OFFSET , + .constraints = snb_uncore_cbo_constraints, + .ops = &snb_uncore_msr_ops, + .format_group = &snb_uncore_format_group, +}; + +static struct intel_uncore_type *snb_msr_uncores[] = { + &snb_uncore_cbo, +NULL , +}; +/* end of Sandy Bridge uncore support */ + +/* Nehalem uncore support */ +static void nhm_uncore_msr_disable_box (struct intel_uncore_box *box) +{ +wrmsrl (NHM_UNC_PERF_GLOBAL_CTL ,0 ); +} + +static void nhm_uncore_msr_enable_box (struct intel_uncore_box *box) +{ +wrmsrl (NHM_UNC_PERF_GLOBAL_CTL , +NHM_UNC_GLOBAL_CTL_EN_PC_ALL |NHM_UNC_GLOBAL_CTL_EN_FC ); +} + +static void nhm_uncore_msr_enable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +if (hwc->idx <UNCORE_PMC_IDX_FIXED ) +wrmsrl (hwc->config_base, hwc->config |SNB_UNC_CTL_EN ); +else +wrmsrl (hwc->config_base,NHM_UNC_FIXED_CTR_CTL_EN ); +} + +static struct attribute *nhm_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_cmask8.attr, +NULL , +}; + +static struct attribute_group nhm_uncore_format_group = { + .name ="format" , + .attrs = nhm_uncore_formats_attr, +}; + +static struct uncore_event_desc nhm_uncore_events[] = { +INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"config=0xffff" ), +/* full cache line writes to DRAM */ +INTEL_UNCORE_EVENT_DESC (QMC_WRITES_FULL_ANY ,"event=0x2f,umask=0xf" ), +/* Quickpath Memory Controller normal priority read requests */ +INTEL_UNCORE_EVENT_DESC (QMC_NORMAL_READS_ANY ,"event=0x2c,umask=0xf" ), +/* Quickpath Home Logic read requests from the IOH */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_IOH_READS , +"event=0x20,umask=0x1" ), +/* Quickpath Home Logic write requests from the IOH */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_IOH_WRITES , +"event=0x20,umask=0x2" ), +/* Quickpath Home Logic read requests from a remote socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_REMOTE_READS , +"event=0x20,umask=0x4" ), +/* Quickpath Home Logic write requests from a remote socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_REMOTE_WRITES , +"event=0x20,umask=0x8" ), +/* Quickpath Home Logic read requests from the local socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_LOCAL_READS , +"event=0x20,umask=0x10" ), +/* Quickpath Home Logic write requests from the local socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_LOCAL_WRITES , +"event=0x20,umask=0x20" ), + {/* end: all zeroes */ }, +}; + +static struct intel_uncore_ops nhm_uncore_msr_ops = { + .disable_box = nhm_uncore_msr_disable_box, + .enable_box = nhm_uncore_msr_enable_box, + .disable_event = snb_uncore_msr_disable_event, + .enable_event = nhm_uncore_msr_enable_event, + .read_counter = snb_uncore_msr_read_counter, +}; + +static struct intel_uncore_type nhm_uncore = { + .name ="" , + .num_counters =8 , + .num_boxes =1 , + .perf_ctr_bits =48 , + .fixed_ctr_bits =48 , + .event_ctl =NHM_UNC_PERFEVTSEL0 , + .perf_ctr =NHM_UNC_UNCORE_PMC0 , + .fixed_ctr =NHM_UNC_FIXED_CTR , + .fixed_ctl =NHM_UNC_FIXED_CTR_CTRL , + .event_mask =NHM_UNC_RAW_EVENT_MASK , + .event_descs = nhm_uncore_events, + .ops = &nhm_uncore_msr_ops, + .format_group = &nhm_uncore_format_group, +}; + +static struct intel_uncore_type *nhm_msr_uncores[] = { + &nhm_uncore, +NULL , +}; +/* end of Nehalem uncore support */ +static void uncore_assign_hw_event (struct intel_uncore_box *box,struct perf_event *event,int idx) {
@@ -808,6 +994,14 @@ static int __init uncore_cpu_init(void)int ret, cpu;switch (boot_cpu_data.x86_model) { +case 26 :/* Nehalem */ +case 30 : +case 37 :/* Westmere */ + msr_uncores = nhm_msr_uncores; +break ; +case 42 :/* Sandy Bridge */ + msr_uncores = snb_msr_uncores; +break ;default :return 0 ; }
arch/x86/kernel/cpu/perf_event_intel_uncore.h +50 -0
56 lines not on this page · raw message
Signature · 1 line
1.7.6.5
Re: [PATCH V6 06/13] perf: Add Nehalem and Sandy Bridge uncore support
arch/x86/kernel/cpu/perf_event_intel_uncore.c static int __init uncore_cpu_init(void) · line 1004
Quoted 12 lines · Zheng
arch/x86/kernel/cpu/perf_event_intel_uncore.c +8
-0@@ -808,6 +994,14 @@ static int __init uncore_cpu_init(void)int ret, cpu;switch (boot_cpu_data.x86_model) { +case 26 :/* Nehalem */ +case 30 : +case 37 :/* Westmere */ + msr_uncores = nhm_msr_uncores; +break ; +case 42 :/* Sandy Bridge */ + msr_uncores = snb_msr_uncores; +break ;
What about WSP-EP (44)? Does it have an uncore similar to the regular WSM (37) or WSM-EX / Xeon-E7 (47) ?
NHM-EX and WSM-EX are similar again, and not (yet) supported by these patches, right?
Peter Zijlstra
maintainerRe: [PATCH V6 06/13] perf: Add Nehalem and Sandy Bridge uncore support
Quoted 4 lines · Peter Zijlstra
Quoted 3 lines · Zheng
arch/x86/kernel/cpu/perf_event_intel_uncore.c +0
-0@@ -808,6 +994,14 @@ static int __init uncore_cpu_init(void)int ret, cpu;
Quoted 12 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c static int __init uncore_cpu_init(void) · line 1004
Quoted 9 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c +8
-0switch (boot_cpu_data.x86_model) { +case 26 :/* Nehalem */ +case 30 : +case 37 :/* Westmere */ + msr_uncores = nhm_msr_uncores; +break ; +case 42 :/* Sandy Bridge */ + msr_uncores = snb_msr_uncores; +break ;What about WSP-EP (44)? Does it have an uncore similar to the regular WSM (37) or WSM-EX / Xeon-E7 (47) ?
I added the 44 and this seems to work.. that is, it didn't die due to incorrect MSR access quite yet.
Re: [PATCH V6 06/13] perf: Add Nehalem and Sandy Bridge uncore support
In reply to Peter ZijlstraQuoted 17 lines · Peter Zijlstra
arch/x86/kernel/cpu/perf_event_intel_uncore.c static int __init uncore_cpu_init(void) · line 1004
Quoted 12 lines · Zheng
arch/x86/kernel/cpu/perf_event_intel_uncore.c +8
-0@@ -808,6 +994,14 @@ static int __init uncore_cpu_init(void)int ret, cpu;switch (boot_cpu_data.x86_model) { +case 26 :/* Nehalem */ +case 30 : +case 37 :/* Westmere */ + msr_uncores = nhm_msr_uncores; +break ; +case 42 :/* Sandy Bridge */ + msr_uncores = snb_msr_uncores; +break ;What about WSP-EP (44)? Does it have an uncore similar to the regular WSM (37) or WSM-EX / Xeon-E7 (47) ?
Quoted 2 lines
NHM-EX and WSM-EX are similar again, and not (yet) supported by these patches, right?
(NHM,WSM)-EX uncores are completely different from EP and need a new driver.
-Andi
Quoted 1 line
Signature · 1 line
[email protected] -- Speaking for myself only.
Re: [PATCH V6 06/13] perf: Add Nehalem and Sandy Bridge uncore support
In reply to Yan, ZhengQuoted 16 lines · Zheng
arch/x86/kernel/cpu/perf_event_intel_uncore.c +16
-0+static struct uncore_event_desc nhm_uncore_events[] = { +INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"config=0xffff" ), +/* full cache line writes to DRAM */ +INTEL_UNCORE_EVENT_DESC (QMC_WRITES_FULL_ANY ,"event=0x2f,umask=0xf" ), +/* Quickpath Memory Controller normal priority read requests */ +INTEL_UNCORE_EVENT_DESC (QMC_NORMAL_READS_ANY ,"event=0x2c,umask=0xf" ), +/* Quickpath Home Logic read requests from the IOH */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_IOH_READS , +"event=0x20,umask=0x1" ), +/* Quickpath Home Logic write requests from the IOH */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_IOH_WRITES , +"event=0x20,umask=0x2" ), +/* Quickpath Home Logic read requests from a remote socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_REMOTE_READS , +"event=0x20,umask=0x4" ), +/* Quickpath Home Logic write requests from a remote socket */
arch/x86/kernel/cpu/perf_event_intel_uncore.c static cpumask_t uncore_cpu_mask; · line 167
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c +10
-0+INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_REMOTE_WRITES , +"event=0x20,umask=0x8" ), +/* Quickpath Home Logic read requests from the local socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_LOCAL_READS , +"event=0x20,umask=0x10" ), +/* Quickpath Home Logic write requests from the local socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_LOCAL_WRITES , + "event=0x20,umask=0x20"), + { /* end: all zeroes */ }, +};
Should we lowercase all event names as well?
/sys/bus/event_source/devices/uncore/events /sys/bus/event_source/devices/uncore/events/QHL_REQUEST_REMOTE_READS /sys/bus/event_source/devices/uncore/events/QHL_REQUEST_LOCAL_READS /sys/bus/event_source/devices/uncore/events/QHL_REQUEST_IOH_READS /sys/bus/event_source/devices/uncore/events/QHL_REQUEST_REMOTE_WRITES /sys/bus/event_source/devices/uncore/events/QMC_WRITES_FULL_ANY /sys/bus/event_source/devices/uncore/events/QMC_NORMAL_READS_ANY /sys/bus/event_source/devices/uncore/events/QHL_REQUEST_LOCAL_WRITES /sys/bus/event_source/devices/uncore/events/QHL_REQUEST_IOH_WRITES /sys/bus/event_source/devices/uncore/events/CLOCKTICKS
BTW we could encode those things like:
INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads, 0x1020);
And have the print function decode that into something pretty, it would save some 18 bytes per event or so. Not sure that's worth it, but who knows.
Re: [PATCH V6 06/13] perf: Add Nehalem and Sandy Bridge uncore support
Quoted 21 lines · Peter Zijlstra
Quoted 20 lines · Zheng
+static struct
uncore_event_descnhm_uncore_events[] = {
+INTEL_UNCORE_EVENT_DESC(CLOCKTICKS, "config=0xffff"),
+ /* full cache line writes to DRAM */
+INTEL_UNCORE_EVENT_DESC(QMC_WRITES_FULL_ANY, "event=0x2f,umask=0xf"),
+ /* Quickpath Memory Controller normal priority read requests */
+INTEL_UNCORE_EVENT_DESC(QMC_NORMAL_READS_ANY, "event=0x2c,umask=0xf"),
+ /* Quickpath Home Logic read requests from the IOH */
+ INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_IOH_READS,
+ "event=0x20,umask=0x1"),
+ /* Quickpath Home Logic write requests from the IOH */
+ INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_IOH_WRITES,
+ "event=0x20,umask=0x2"),
+ /* Quickpath Home Logic read requests from a remote socket */
+ INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_REMOTE_READS,
+ "event=0x20,umask=0x4"),
+ /* Quickpath Home Logic write requests from a remote socket */
+ INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_REMOTE_WRITES,
+ "event=0x20,umask=0x8"),
+ /* Quickpath Home Logic read requests from the local socket */
+ INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_LOCAL_READS,
Quoted 9 lines
Quoted 6 lines
+ "event=0x20,umask=0x10"),
+ /* Quickpath Home Logic write requests from the local socket */
+ INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_LOCAL_WRITES,
+ "event=0x20,umask=0x20"),
+ { /* end: all zeroes */ },
+};Should we lowercase all event names as well?
Yes, and let the parser be case insensitive.
Quoted 20 lines
/sys/bus/event_source/devices/uncore/events/sys/bus/event_source/devices/uncore/events/QHL_REQUEST_REMOTE_READS/sys/bus/event_source/devices/uncore/events/QHL_REQUEST_LOCAL_READS/sys/bus/event_source/devices/uncore/events/QHL_REQUEST_IOH_READS/sys/bus/event_source/devices/uncore/events/QHL_REQUEST_REMOTE_WRITES/sys/bus/event_source/devices/uncore/events/QMC_WRITES_FULL_ANY/sys/bus/event_source/devices/uncore/events/QMC_NORMAL_READS_ANY/sys/bus/event_source/devices/uncore/events/QHL_REQUEST_LOCAL_WRITES/sys/bus/event_source/devices/uncore/events/QHL_REQUEST_IOH_WRITES/sys/bus/event_source/devices/uncore/events/CLOCKTICKSBTW we could encode those things like:
INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads, 0x1020);And have the print function decode that into something pretty, it would save some 18 bytes per event or so. Not sure that's worth it, but who knows.
Re: [PATCH V6 06/13] perf: Add Nehalem and Sandy Bridge uncore support
Quoted 1 line · Stephane Eranian
Yes, and let the parser be case insensitive.
Right, I did the below on top..
---
arch/x86/kernel/cpu/perf_event_intel_uncore.c +16 -35
@@ -179,22 +179,17 @@ static struct attribute *snbep_uncore_pc };static struct uncore_event_desc snbep_uncore_imc_events[] = { -INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"config=0xffff" ), -/* read */ -INTEL_UNCORE_EVENT_DESC (CAS_COUNT_RD ,"event=0x4,umask=0x3" ), -/* write */ -INTEL_UNCORE_EVENT_DESC (CAS_COUNT_WR ,"event=0x4,umask=0xc" ), + INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0xff"); +INTEL_UNCORE_EVENT_DESC (cas_count_read,"event=0x04,umask=0x03" ), + INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"), { /* end: all zeroes */ }, };static struct uncore_event_desc snbep_uncore_qpi_events[] = { -INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"event=0x14" ), -/* outgoing data+nondata flits */ -INTEL_UNCORE_EVENT_DESC (TxL_FLITS_ACTIVE,"event=0x0,umask=0x6" ), -/* DRS data received */ -INTEL_UNCORE_EVENT_DESC (DRS_DATA ,"event=0x2,umask=0x8" ), -/* NCB data received */ -INTEL_UNCORE_EVENT_DESC (NCB_DATA ,"event=0x3,umask=0x4" ), +INTEL_UNCORE_EVENT_DESC (clockticks,"event=0x14" ), +INTEL_UNCORE_EVENT_DESC (txl_flits_active,"event=0x0,umask=0x6" ), +INTEL_UNCORE_EVENT_DESC (drs_data,"event=0x2,umask=0x8" ), +INTEL_UNCORE_EVENT_DESC (ncb_data,"event=0x3,umask=0x4" ), {/* end: all zeroes */ }, };
@@ -621,29 +616,15 @@ static struct attribute_group nhm_uncore };static struct uncore_event_desc nhm_uncore_events[] = { -INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"config=0xffff" ), -/* full cache line writes to DRAM */ -INTEL_UNCORE_EVENT_DESC (QMC_WRITES_FULL_ANY ,"event=0x2f,umask=0xf" ), -/* Quickpath Memory Controller normal priority read requests */ -INTEL_UNCORE_EVENT_DESC (QMC_NORMAL_READS_ANY ,"event=0x2c,umask=0xf" ), -/* Quickpath Home Logic read requests from the IOH */ -INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_IOH_READS , -"event=0x20,umask=0x1" ), -/* Quickpath Home Logic write requests from the IOH */ -INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_IOH_WRITES , -"event=0x20,umask=0x2" ), -/* Quickpath Home Logic read requests from a remote socket */ -INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_REMOTE_READS , -"event=0x20,umask=0x4" ), -/* Quickpath Home Logic write requests from a remote socket */ -INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_REMOTE_WRITES , -"event=0x20,umask=0x8" ), -/* Quickpath Home Logic read requests from the local socket */ -INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_LOCAL_READS , -"event=0x20,umask=0x10" ), -/* Quickpath Home Logic write requests from the local socket */ -INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_LOCAL_WRITES , -"event=0x20,umask=0x20" ), +INTEL_UNCORE_EVENT_DESC (clockticks,"event=0xff,umask=0xff" ), +INTEL_UNCORE_EVENT_DESC (qmc_writes_full_any,"event=0x2f,umask=0x0f" ), +INTEL_UNCORE_EVENT_DESC (qmc_normal_reads_any,"event=0x2c,umask=0x0f" ), +INTEL_UNCORE_EVENT_DESC (qhl_request_ioh_reads,"event=0x20,umask=0x01" ), +INTEL_UNCORE_EVENT_DESC (qhl_request_ioh_writes,"event=0x20,umask=0x02" ), +INTEL_UNCORE_EVENT_DESC (qhl_request_remote_reads,"event=0x20,umask=0x04" ), +INTEL_UNCORE_EVENT_DESC (qhl_request_remote_writes,"event=0x20,umask=0x08" ), +INTEL_UNCORE_EVENT_DESC (qhl_request_local_reads,"event=0x20,umask=0x10" ), +INTEL_UNCORE_EVENT_DESC (qhl_request_local_writes,"event=0x20,umask=0x20" ), {/* end: all zeroes */ }, };
Peter Zijlstra
maintainerRe: [PATCH V6 06/13] perf: Add Nehalem and Sandy Bridge uncore support
Quoted 1 line · Peter Zijlstra
Right, I did the below on top..
I also did a s/cbo[^x]/cbox/ and s/(u64)-1/~0ULL/ on the entire patch-set.
Re: [PATCH V6 06/13] perf: Add Nehalem and Sandy Bridge uncore support
In reply to Peter ZijlstraQuoted 10 lines · Peter Zijlstra
Quoted 1 line · Stephane Eranian
Yes, and let the parser be case insensitive.
Right, I did the below on top..
---
arch/x86/kernel/cpu/perf_event_intel_uncore.c static struct attribute *snbep_uncore_pc · line 182
Quoted 9 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c +1
-5@@ -179,22 +179,17 @@ static struct attribute *snbep_uncore_pc }; static struct uncore_event_desc snbep_uncore_imc_events[] = { - INTEL_UNCORE_EVENT_DESC(CLOCKTICKS, "config=0xffff"), - /* read */ - INTEL_UNCORE_EVENT_DESC(CAS_COUNT_RD, "event=0x4,umask=0x3"), - /* write */ - INTEL_UNCORE_EVENT_DESC(CAS_COUNT_WR, "event=0x4,umask=0xc"), + INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0xff");
Just like for core, I would pick 0xff as the pseudo event code for fixed uncore events
and use the umask value to determine which of the fixed events we want to map to. There
is only one fixed counter so far. But more could be added later on, so why not start with
umask=0x00 or umask=0x1 instead of umask=0xff?
Quoted 71 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c +8
-30+ INTEL_UNCORE_EVENT_DESC(cas_count_read, "event=0x04,umask=0x03"), + INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"), { /* end: all zeroes */ }, }; static struct uncore_event_desc snbep_uncore_qpi_events[] = { - INTEL_UNCORE_EVENT_DESC(CLOCKTICKS, "event=0x14"), - /* outgoing data+nondata flits */ - INTEL_UNCORE_EVENT_DESC(TxL_FLITS_ACTIVE, "event=0x0,umask=0x6"), - /* DRS data received */ - INTEL_UNCORE_EVENT_DESC(DRS_DATA, "event=0x2,umask=0x8"), - /* NCB data received */ - INTEL_UNCORE_EVENT_DESC(NCB_DATA, "event=0x3,umask=0x4"), + INTEL_UNCORE_EVENT_DESC(clockticks, "event=0x14"), + INTEL_UNCORE_EVENT_DESC(txl_flits_active, "event=0x0,umask=0x6"), + INTEL_UNCORE_EVENT_DESC(drs_data, "event=0x2,umask=0x8"), + INTEL_UNCORE_EVENT_DESC(ncb_data, "event=0x3,umask=0x4"), { /* end: all zeroes */ }, };@@ -621,29 +616,15 @@ static struct attribute_group nhm_uncore }; static struct uncore_event_desc nhm_uncore_events[] = { - INTEL_UNCORE_EVENT_DESC(CLOCKTICKS, "config=0xffff"), - /* full cache line writes to DRAM */ - INTEL_UNCORE_EVENT_DESC(QMC_WRITES_FULL_ANY, "event=0x2f,umask=0xf"), - /* Quickpath Memory Controller normal priority read requests */ - INTEL_UNCORE_EVENT_DESC(QMC_NORMAL_READS_ANY, "event=0x2c,umask=0xf"), - /* Quickpath Home Logic read requests from the IOH */ - INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_IOH_READS, - "event=0x20,umask=0x1"), - /* Quickpath Home Logic write requests from the IOH */ - INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_IOH_WRITES, - "event=0x20,umask=0x2"), - /* Quickpath Home Logic read requests from a remote socket */ - INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_REMOTE_READS, - "event=0x20,umask=0x4"), - /* Quickpath Home Logic write requests from a remote socket */ - INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_REMOTE_WRITES, - "event=0x20,umask=0x8"), - /* Quickpath Home Logic read requests from the local socket */ - INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_LOCAL_READS, - "event=0x20,umask=0x10"), - /* Quickpath Home Logic write requests from the local socket */ - INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_LOCAL_WRITES, - "event=0x20,umask=0x20"), + INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0xff"), + INTEL_UNCORE_EVENT_DESC(qmc_writes_full_any,"event=0x2f,umask=0x0f"),
+INTEL_UNCORE_EVENT_DESC(qmc_normal_reads_any, "event=0x2c,umask=0x0f"),
+INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_reads, "event=0x20,umask=0x01"),
+INTEL_UNCORE_EVENT_DESC(qhl_request_ioh_writes, "event=0x20,umask=0x02"),
+INTEL_UNCORE_EVENT_DESC(qhl_request_remote_reads, "event=0x20,umask=0x04"),
+INTEL_UNCORE_EVENT_DESC(qhl_request_remote_writes, "event=0x20,umask=0x08"),
+INTEL_UNCORE_EVENT_DESC(qhl_request_local_reads, "event=0x20,umask=0x10"),
+INTEL_UNCORE_EVENT_DESC(qhl_request_local_writes, "event=0x20,umask=0x20"),
{ /* end: all zeroes */ },
};
Re: [PATCH V6 06/13] perf: Add Nehalem and Sandy Bridge uncore support
Quoted 13 lines · Stephane Eranian
Quoted 12 lines · Peter Zijlstra
Quoted 12 lines · Stephane Eranian
Quoted 1 line
Quoted 1 line
Yes, and let the parser be case insensitive.
Right, I did the below on top..
---
arch/x86/kernel/cpu/perf_event_intel_uncore.c +0
-0@@ -179,22 +179,17 @@ static struct attribute *snbep_uncore_pc };
Quoted 15 lines
Quoted 7 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c static struct attribute *snbep_uncore_pc · line 182
Quoted 7 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c +1
-5static struct uncore_event_desc snbep_uncore_imc_events[] = { -INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"config=0xffff" ), -/* read */ -INTEL_UNCORE_EVENT_DESC (CAS_COUNT_RD ,"event=0x4,umask=0x3" ), -/* write */ -INTEL_UNCORE_EVENT_DESC (CAS_COUNT_WR ,"event=0x4,umask=0xc" ), + INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0xff");Just like for core, I would pick
0xffas the pseudo event code for fixed uncore events
and use the umask value to determine which of the fixed events we want to map to. There
is only one fixed counter so far. But more could be added later on, so why not start with
umask=0x00 or umask=0x1 instead of umask=0xff?
Good idea. I think changing the definition of UNCORE_FIXED_EVENT to 0xff and changing configure for the clockticks events to config=0xff are enough for now.
Regards
Yan, Zheng
Re: [PATCH V6 06/13] perf: Add Nehalem and Sandy Bridge uncore support
In reply to Yan, Zhengarch/x86/kernel/cpu/perf_event_intel_uncore.c static cpumask_t uncore_cpu_mask; · line 143
Quoted 2 lines · Zheng
arch/x86/kernel/cpu/perf_event_intel_uncore.c +2
-0+static struct uncore_event_desc nhm_uncore_events[] = { +INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"config=0xffff" ),
Why does that use config=0xffff, also I couldn't find event 0xff listed, is it special-cased somewhere?
Quoted 14 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c +14
-0+/* full cache line writes to DRAM */ +INTEL_UNCORE_EVENT_DESC (QMC_WRITES_FULL_ANY ,"event=0x2f,umask=0xf" ), +/* Quickpath Memory Controller normal priority read requests */ +INTEL_UNCORE_EVENT_DESC (QMC_NORMAL_READS_ANY ,"event=0x2c,umask=0xf" ), +/* Quickpath Home Logic read requests from the IOH */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_IOH_READS , +"event=0x20,umask=0x1" ), +/* Quickpath Home Logic write requests from the IOH */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_IOH_WRITES , +"event=0x20,umask=0x2" ), +/* Quickpath Home Logic read requests from a remote socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_REMOTE_READS , + "event=0x20,umask=0x4"), +/* Quickpath Home Logic write requests from a remote socket */
arch/x86/kernel/cpu/perf_event_intel_uncore.c static cpumask_t uncore_cpu_mask; · line 167
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c +10
-0+INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_REMOTE_WRITES , +"event=0x20,umask=0x8" ), +/* Quickpath Home Logic read requests from the local socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_LOCAL_READS , +"event=0x20,umask=0x10" ), +/* Quickpath Home Logic write requests from the local socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_LOCAL_WRITES , + "event=0x20,umask=0x20"), + { /* end: all zeroes */ }, +};
The rest of the events seem to be valid on both NHM and WSM, I didn't look very closely, but it looks like WSM has a few extra events, but includes all NHM events.
Re: [PATCH V6 06/13] perf: Add Nehalem and Sandy Bridge uncore support
Quoted 6 lines · Peter Zijlstra
Quoted 2 lines · Zheng
+static struct
uncore_event_descnhm_uncore_events[] = {
+INTEL_UNCORE_EVENT_DESC(CLOCKTICKS, "config=0xffff"),Why does that use config=0xffff, also I couldn't find event
0xfflisted, is it special-cased somewhere?
That's becase some uncore have 1 fixed counter to count uncore cycles. That means no specific encoding, so we need to make one up just like for core PMU and the ref-cycle event.
Quoted 31 lines
Quoted 17 lines
+ /* full cache line writes to DRAM */
+INTEL_UNCORE_EVENT_DESC(QMC_WRITES_FULL_ANY, "event=0x2f,umask=0xf"),
+ /* Quickpath Memory Controller normal priority read requests */
+INTEL_UNCORE_EVENT_DESC(QMC_NORMAL_READS_ANY, "event=0x2c,umask=0xf"),
+ /* Quickpath Home Logic read requests from the IOH */
+ INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_IOH_READS,
+ "event=0x20,umask=0x1"),
+ /* Quickpath Home Logic write requests from the IOH */
+ INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_IOH_WRITES,
+ "event=0x20,umask=0x2"),
+ /* Quickpath Home Logic read requests from a remote socket */
+ INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_REMOTE_READS,
+ "event=0x20,umask=0x4"),
+ /* Quickpath Home Logic write requests from a remote socket */
+ INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_REMOTE_WRITES,
+ "event=0x20,umask=0x8"),Quoted 8 lines
+ /* Quickpath Home Logic read requests from the local socket */
+ INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_LOCAL_READS,
+ "event=0x20,umask=0x10"),
+ /* Quickpath Home Logic write requests from the local socket */
+ INTEL_UNCORE_EVENT_DESC(QHL_REQUEST_LOCAL_WRITES,
+ "event=0x20,umask=0x20"),
+ { /* end: all zeroes */ },
+};The rest of the events seem to be valid on both NHM and WSM, I didn't look very closely, but it looks like WSM has a few extra events, but includes all NHM events.
Re: [PATCH V6 06/13] perf: Add Nehalem and Sandy Bridge uncore support
Quoted 3 lines · Stephane Eranian
That's becase some uncore have 1 fixed counter to count uncore cycles. That means no specific encoding, so we need to make one up just like for core PMU and the ref-cycle event.
Would've been nice to have that mentioned somewhere...
[tip:perf/core] perf/x86: Add Intel Nehalem and Sandy Bridge uncore PMU support
In reply to Yan, ZhengCommit-ID: fcde10e916326545e8fec1807357c68ef08dc443 Gitweb: http://git.kernel.org/tip/fcde10e916326545e8fec1807357c68ef08dc443 Author: Yan, Zheng <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:35 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:22 +0200
perf/x86: Add Intel Nehalem and Sandy Bridge uncore PMU support
--- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 195 +++++++++++++++++++++++++ arch/x86/kernel/cpu/perf_event_intel_uncore.h | 50 +++++++ 2 files changed, 245 insertions(+), 0 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_uncore.c +195 -0
@@ -10,6 +10,192 @@ static cpumask_t uncore_cpu_mask;static struct event_constraint constraint_fixed =EVENT_CONSTRAINT (~0ULL ,1 <<UNCORE_PMC_IDX_FIXED , ~0ULL ); +DEFINE_UNCORE_FORMAT_ATTR (event, event,"config:0-7" ); +DEFINE_UNCORE_FORMAT_ATTR (umask, umask,"config:8-15" ); +DEFINE_UNCORE_FORMAT_ATTR (edge, edge,"config:18" ); +DEFINE_UNCORE_FORMAT_ATTR (inv, inv,"config:23" ); +DEFINE_UNCORE_FORMAT_ATTR (cmask5, cmask,"config:24-28" ); +DEFINE_UNCORE_FORMAT_ATTR (cmask8, cmask,"config:24-31" ); + +/* Sandy Bridge uncore support */ +static void snb_uncore_msr_enable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +if (hwc->idx <UNCORE_PMC_IDX_FIXED ) +wrmsrl (hwc->config_base, hwc->config |SNB_UNC_CTL_EN ); +else +wrmsrl (hwc->config_base,SNB_UNC_CTL_EN ); +} + +static void snb_uncore_msr_disable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +wrmsrl (event->hw.config_base,0 ); +} + +static u64 snb_uncore_msr_read_counter (struct intel_uncore_box *box, +struct perf_event *event) +{ +u64 count; +rdmsrl (event->hw.event_base, count); +return count; +} + +static void snb_uncore_msr_init_box (struct intel_uncore_box *box) +{ +if (box->pmu->pmu_idx ==0 ) { +wrmsrl (SNB_UNC_PERF_GLOBAL_CTL , +SNB_UNC_GLOBAL_CTL_EN |SNB_UNC_GLOBAL_CTL_CORE_ALL ); + } +} + +static struct attribute *snb_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_cmask5.attr, +NULL , +}; + +static struct attribute_group snb_uncore_format_group = { + .name ="format" , + .attrs = snb_uncore_formats_attr, +}; + +static struct intel_uncore_ops snb_uncore_msr_ops = { + .init_box = snb_uncore_msr_init_box, + .disable_event = snb_uncore_msr_disable_event, + .enable_event = snb_uncore_msr_enable_event, + .read_counter = snb_uncore_msr_read_counter, +}; + +static struct event_constraint snb_uncore_cbox_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x80 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x83 ,0x1 ), +EVENT_CONSTRAINT_END +}; + +static struct intel_uncore_type snb_uncore_cbox = { + .name ="cbox" , + .num_counters =2 , + .num_boxes =4 , + .perf_ctr_bits =44 , + .fixed_ctr_bits =48 , + .perf_ctr =SNB_UNC_CBO_0_PER_CTR0 , + .event_ctl =SNB_UNC_CBO_0_PERFEVTSEL0 , + .fixed_ctr =SNB_UNC_FIXED_CTR , + .fixed_ctl =SNB_UNC_FIXED_CTR_CTRL , + .single_fixed =1 , + .event_mask =SNB_UNC_RAW_EVENT_MASK , + .msr_offset =SNB_UNC_CBO_MSR_OFFSET , + .constraints = snb_uncore_cbox_constraints, + .ops = &snb_uncore_msr_ops, + .format_group = &snb_uncore_format_group, +}; + +static struct intel_uncore_type *snb_msr_uncores[] = { + &snb_uncore_cbox, +NULL , +}; +/* end of Sandy Bridge uncore support */ + +/* Nehalem uncore support */ +static void nhm_uncore_msr_disable_box (struct intel_uncore_box *box) +{ +wrmsrl (NHM_UNC_PERF_GLOBAL_CTL ,0 ); +} + +static void nhm_uncore_msr_enable_box (struct intel_uncore_box *box) +{ +wrmsrl (NHM_UNC_PERF_GLOBAL_CTL , +NHM_UNC_GLOBAL_CTL_EN_PC_ALL |NHM_UNC_GLOBAL_CTL_EN_FC ); +} + +static void nhm_uncore_msr_enable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +if (hwc->idx <UNCORE_PMC_IDX_FIXED ) +wrmsrl (hwc->config_base, hwc->config |SNB_UNC_CTL_EN ); +else +wrmsrl (hwc->config_base,NHM_UNC_FIXED_CTR_CTL_EN ); +} + +static struct attribute *nhm_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_cmask8.attr, +NULL , +}; + +static struct attribute_group nhm_uncore_format_group = { + .name ="format" , + .attrs = nhm_uncore_formats_attr, +}; + +static struct uncore_event_desc nhm_uncore_events[] = { +INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"config=0xffff" ), +/* full cache line writes to DRAM */ +INTEL_UNCORE_EVENT_DESC (QMC_WRITES_FULL_ANY ,"event=0x2f,umask=0xf" ), +/* Quickpath Memory Controller normal priority read requests */ +INTEL_UNCORE_EVENT_DESC (QMC_NORMAL_READS_ANY ,"event=0x2c,umask=0xf" ), +/* Quickpath Home Logic read requests from the IOH */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_IOH_READS , +"event=0x20,umask=0x1" ), +/* Quickpath Home Logic write requests from the IOH */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_IOH_WRITES , +"event=0x20,umask=0x2" ), +/* Quickpath Home Logic read requests from a remote socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_REMOTE_READS , +"event=0x20,umask=0x4" ), +/* Quickpath Home Logic write requests from a remote socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_REMOTE_WRITES , +"event=0x20,umask=0x8" ), +/* Quickpath Home Logic read requests from the local socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_LOCAL_READS , +"event=0x20,umask=0x10" ), +/* Quickpath Home Logic write requests from the local socket */ +INTEL_UNCORE_EVENT_DESC (QHL_REQUEST_LOCAL_WRITES , +"event=0x20,umask=0x20" ), + {/* end: all zeroes */ }, +}; + +static struct intel_uncore_ops nhm_uncore_msr_ops = { + .disable_box = nhm_uncore_msr_disable_box, + .enable_box = nhm_uncore_msr_enable_box, + .disable_event = snb_uncore_msr_disable_event, + .enable_event = nhm_uncore_msr_enable_event, + .read_counter = snb_uncore_msr_read_counter, +}; + +static struct intel_uncore_type nhm_uncore = { + .name ="" , + .num_counters =8 , + .num_boxes =1 , + .perf_ctr_bits =48 , + .fixed_ctr_bits =48 , + .event_ctl =NHM_UNC_PERFEVTSEL0 , + .perf_ctr =NHM_UNC_UNCORE_PMC0 , + .fixed_ctr =NHM_UNC_FIXED_CTR , + .fixed_ctl =NHM_UNC_FIXED_CTR_CTRL , + .event_mask =NHM_UNC_RAW_EVENT_MASK , + .event_descs = nhm_uncore_events, + .ops = &nhm_uncore_msr_ops, + .format_group = &nhm_uncore_format_group, +}; + +static struct intel_uncore_type *nhm_msr_uncores[] = { + &nhm_uncore, +NULL , +}; +/* end of Nehalem uncore support */ +static void uncore_assign_hw_event (struct intel_uncore_box *box,struct perf_event *event,int idx) {
@@ -808,6 +994,15 @@ static int __init uncore_cpu_init(void)int ret, cpu;switch (boot_cpu_data.x86_model) { +case 26 :/* Nehalem */ +case 30 : +case 37 :/* Westmere */ +case 44 : + msr_uncores = nhm_msr_uncores; +break ; +case 42 :/* Sandy Bridge */ + msr_uncores = snb_msr_uncores; +break ;default :return 0 ; }
arch/x86/kernel/cpu/perf_event_intel_uncore.h +50 -0
56 lines not on this page · raw message
PATCH v6 7/13 perf: Generic pci uncore device support
In reply to Yan, ZhengFrom: "Yan, Zheng" <[email protected]>
This patch adds generic support for uncore pmu presented as pci device.
--- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 175 ++++++++++++++++++++++++- arch/x86/kernel/cpu/perf_event_intel_uncore.h | 66 +++++++++ 2 files changed, 236 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_uncore.c +170 -5
@@ -2,6 +2,11 @@static struct intel_uncore_type *empty_uncore[] = {NULL , };static struct intel_uncore_type **msr_uncores = empty_uncore; +static struct intel_uncore_type **pci_uncores = empty_uncore; +/* pci bus to socket mapping */ +static int pcibus_to_physid[256 ] = { [0 ...255 ] =-1 , }; + +static DEFINE_RAW_SPINLOCK (uncore_box_lock);/* mask of cpus that collect uncore events */ static cpumask_t uncore_cpu_mask;
@@ -205,13 +210,13 @@ static void uncore_assign_hw_event(struct intel_uncore_box *box, hwc->last_tag = ++box->tags[idx];if (hwc->idx ==UNCORE_PMC_IDX_FIXED ) { - hwc->event_base =uncore_msr_fixed_ctr (box); - hwc->config_base =uncore_msr_fixed_ctl (box); + hwc->event_base =uncore_fixed_ctr (box); + hwc->config_base =uncore_fixed_ctl (box);return ; } - hwc->config_base =uncore_msr_event_ctl (box, hwc->idx); - hwc->event_base =uncore_msr_perf_ctr (box, hwc->idx); + hwc->config_base =uncore_event_ctl (box, hwc->idx); + hwc->event_base =uncore_perf_ctr (box, hwc->idx); } static void uncore_perf_event_update(struct intel_uncore_box *box,
@@ -305,6 +310,22 @@ struct intel_uncore_box *uncore_alloc_box(int cpu)static struct intel_uncore_box *uncore_pmu_to_box (struct intel_uncore_pmu *pmu,int cpu) { +static struct intel_uncore_box *box; + + box = *per_cpu_ptr (pmu->box, cpu); +if (box) +return box; + +raw_spin_lock (&uncore_box_lock); +list_for_each_entry (box, &pmu->box_list, list) { +if (box->phys_id ==topology_physical_package_id (cpu)) { +atomic_inc (&box->refcnt); + *per_cpu_ptr (pmu->box, cpu) = box; +break ; + } + } +raw_spin_unlock (&uncore_box_lock); +return *per_cpu_ptr (pmu->box, cpu); }
@@ -706,6 +727,13 @@ static void __init uncore_type_exit(struct intel_uncore_type *type) type->attr_groups[1 ] =NULL ; } +static void uncore_types_exit (struct intel_uncore_type **types) +{ +int i; +for (i =0 ; types[i]; i++) +uncore_type_exit (types[i]); +} +static int __init uncore_type_init (struct intel_uncore_type *type) {struct intel_uncore_pmu *pmus;
@@ -725,6 +753,7 @@ static int __init uncore_type_init(struct intel_uncore_type *type) pmus[i].func_id =-1 ; pmus[i].pmu_idx = i; pmus[i].type = type; +INIT_LIST_HEAD (&pmus[i].box_list); pmus[i].box = alloc_percpu(struct intel_uncore_box *);if (!pmus[i].box) goto fail;
@@ -773,6 +802,127 @@ fail:return ret; } +static struct pci_driver *uncore_pci_driver; +static bool pcidrv_registered; + +/* +* add a pci uncore device +*/ +static int __devinit uncore_pci_add (struct intel_uncore_type *type, +struct pci_dev *pdev) +{ +struct intel_uncore_pmu *pmu; +struct intel_uncore_box *box; +int i, phys_id; + + phys_id = pcibus_to_physid[pdev->bus->number]; +if (phys_id <0 ) +return -ENODEV ; + + box =uncore_alloc_box (0 ); +if (!box) +return -ENOMEM ; + +/* +* for performance monitoring unit with multiple boxes, +* each box has a different function id. +*/ +for (i =0 ; i < type->num_boxes; i++) { + pmu = &type->pmus[i]; +if (pmu->func_id == pdev->devfn) +break ; +if (pmu->func_id <0 ) { + pmu->func_id = pdev->devfn; +break ; + } + pmu =NULL ; + } + +if (!pmu) { +kfree (box); +return -EINVAL ; + } + + box->phys_id = phys_id; + box->pci_dev = pdev; + box->pmu = pmu; +uncore_box_init (box); +pci_set_drvdata (pdev, box); + +raw_spin_lock (&uncore_box_lock); +list_add_tail (&box->list, &pmu->box_list); +raw_spin_unlock (&uncore_box_lock); + +return 0 ; +} + +static void __devexit uncore_pci_remove(struct pci_dev *pdev) +{ +struct intel_uncore_box *box =pci_get_drvdata (pdev); +struct intel_uncore_pmu *pmu = box->pmu; +int cpu, phys_id = pcibus_to_physid[pdev->bus->number]; + +if (WARN_ON_ONCE (phys_id != box->phys_id)) +return ; + +raw_spin_lock (&uncore_box_lock); +list_del (&box->list); +raw_spin_unlock (&uncore_box_lock); + +for_each_possible_cpu (cpu) { +if (*per_cpu_ptr (pmu->box, cpu) == box) { + *per_cpu_ptr (pmu->box, cpu) =NULL ; +atomic_dec (&box->refcnt); + } + } + +WARN_ON_ONCE (atomic_read (&box->refcnt) !=1 ); +kfree (box); +} + +static int __devinit uncore_pci_probe (struct pci_dev *pdev, +const struct pci_device_id *id) +{ +struct intel_uncore_type *type; + + type = (struct intel_uncore_type *)id->driver_data; +return uncore_pci_add (type, pdev); +} + +static int __init uncore_pci_init (void ) +{ +int ret; + +switch (boot_cpu_data.x86_model) { +default : +return 0 ; + } + + ret =uncore_types_init (pci_uncores); +if (ret) +return ret; + + uncore_pci_driver->probe = uncore_pci_probe; + uncore_pci_driver->remove = uncore_pci_remove; + + ret =pci_register_driver (uncore_pci_driver); +if (ret ==0 ) + pcidrv_registered = true; +else +uncore_types_exit (pci_uncores); + +return ret; +} + +static void __init uncore_pci_exit (void ) +{ +if (pcidrv_registered) { + pcidrv_registered = false; +pci_unregister_driver (uncore_pci_driver); +uncore_types_exit (pci_uncores); + } +} +static void __cpuinit uncore_cpu_dying (int cpu) {struct intel_uncore_type *type;
@@ -921,6 +1071,7 @@ static void __cpuinit uncore_event_exit_cpu(int cpu)cpumask_set_cpu (target, &uncore_cpu_mask);uncore_change_context (msr_uncores, cpu, target); +uncore_change_context (pci_uncores, cpu, target); }static void __cpuinit uncore_event_init_cpu (int cpu)
@@ -936,6 +1087,7 @@ static void __cpuinit uncore_event_init_cpu(int cpu)cpumask_set_cpu (cpu, &uncore_cpu_mask);uncore_change_context (msr_uncores,-1 , cpu); +uncore_change_context (pci_uncores,-1 , cpu); } static int __cpuinit uncore_cpu_notifier(struct notifier_block *self,
@@ -1050,6 +1202,14 @@ static int __init uncore_pmus_register(void) } } +for (i =0 ; pci_uncores[i]; i++) { + type = pci_uncores[i]; +for (j =0 ; j < type->num_boxes; j++) { + pmu = &type->pmus[j]; +uncore_pmu_register (pmu); + } + } +return 0 ; }
@@ -1060,9 +1220,14 @@ static int __init intel_uncore_init(void)if (boot_cpu_data.x86_vendor !=X86_VENDOR_INTEL )return -ENODEV ; - ret =uncore_cpu_init (); + ret =uncore_pci_init ();if (ret) goto fail; + ret =uncore_cpu_init (); +if (ret) { +uncore_pci_exit (); + goto fail; + }uncore_pmus_register ();return 0 ;
arch/x86/kernel/cpu/perf_event_intel_uncore.h +66 -0
95 lines not on this page · raw message
Signature · 1 line
1.7.6.5
Re: [PATCH V6 07/13] perf: Generic pci uncore device support
Quoted 12 lines · Zheng
arch/x86/kernel/cpu/perf_event_intel_uncore.c +8
-0@@ -305,6 +310,22 @@ struct intel_uncore_box *uncore_alloc_box(int cpu)static struct intel_uncore_box *uncore_pmu_to_box (struct intel_uncore_pmu *pmu,int cpu) { +static struct intel_uncore_box *box; + + box = *per_cpu_ptr (pmu->box, cpu); +if (box) +return box; + +raw_spin_lock (&uncore_box_lock); +list_for_each_entry (box, &pmu->box_list, list) {
arch/x86/kernel/cpu/perf_event_intel_uncore.c struct intel_uncore_box *uncore_alloc_box(int cpu) · line 330
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c +8
-0+if (box->phys_id ==topology_physical_package_id (cpu)) { +atomic_inc (&box->refcnt); + *per_cpu_ptr (pmu->box, cpu) = box; +break ; + } + } +raw_spin_unlock (&uncore_box_lock); +return *per_cpu_ptr (pmu->box, cpu); }
So why can't we do that lookup from a hotplug notifier?
Re: [PATCH V6 07/13] perf: Generic pci uncore device support
Quoted 17 lines · Peter Zijlstra
Quoted 16 lines · Zheng
arch/x86/kernel/cpu/perf_event_intel_uncore.c +12
-0@@ -305,6 +310,22 @@ struct intel_uncore_box *uncore_alloc_box(int cpu)static struct intel_uncore_box *uncore_pmu_to_box (struct intel_uncore_pmu *pmu,int cpu) { +static struct intel_uncore_box *box; + + box = *per_cpu_ptr (pmu->box, cpu); +if (box) +return box; + +raw_spin_lock (&uncore_box_lock); +list_for_each_entry (box, &pmu->box_list, list) { +if (box->phys_id ==topology_physical_package_id (cpu)) { +atomic_inc (&box->refcnt); + *per_cpu_ptr (pmu->box, cpu) = box; +break ;
Quoted 9 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c struct intel_uncore_box *uncore_alloc_box(int cpu) · line 330
Quoted 6 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c +4
-0+ } + } +raw_spin_unlock (&uncore_box_lock); +return *per_cpu_ptr (pmu->box, cpu); }So why can't we do that lookup from a hotplug notifier?
We can. But I personally prefer not to mix pci uncore initialization code with cpu hotplug notifier. Because pci hotplug and cpu hotplug are separate process, I'm not completely sure which one happens first.
Regards
Yan, Zheng
Re: [PATCH V6 07/13] perf: Generic pci uncore device support
Quoted 27 lines · Zheng
Quoted 17 lines · Peter Zijlstra
Quoted 16 lines · Zheng
arch/x86/kernel/cpu/perf_event_intel_uncore.c +12
-0@@ -305,6 +310,22 @@ struct intel_uncore_box *uncore_alloc_box(int cpu)static struct intel_uncore_box *uncore_pmu_to_box (struct intel_uncore_pmu *pmu,int cpu) { +static struct intel_uncore_box *box; + + box = *per_cpu_ptr (pmu->box, cpu); +if (box) +return box; + +raw_spin_lock (&uncore_box_lock); +list_for_each_entry (box, &pmu->box_list, list) { +if (box->phys_id ==topology_physical_package_id (cpu)) { +atomic_inc (&box->refcnt); + *per_cpu_ptr (pmu->box, cpu) = box; +break ;Quoted 9 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c struct intel_uncore_box *uncore_alloc_box(int cpu) · line 330
Quoted 6 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c +4
-0+ } + } +raw_spin_unlock (&uncore_box_lock); +return *per_cpu_ptr (pmu->box, cpu); }So why can't we do that lookup from a hotplug notifier?
Quoted 3 lines
We can. But I personally prefer not to mix pci uncore initialization code with cpu hotplug notifier. Because pci hotplug and cpu hotplug are separate process, I'm not completely sure which one happens first.
I suspect nobody does.. OK we'll leave it as it is. Thanks
[tip:perf/core] perf: Add generic PCI uncore PMU device support
In reply to Yan, ZhengCommit-ID: 14371cce03c2fc393997e17f979e76674b7f392a Gitweb: http://git.kernel.org/tip/14371cce03c2fc393997e17f979e76674b7f392a Author: Yan, Zheng <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:36 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:23 +0200
perf: Add generic PCI uncore PMU device support
This patch adds generic support for uncore PMUs presented as PCI devices. (These come in addition to the CPU/MSR based uncores.)
--- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 175 ++++++++++++++++++++++++- arch/x86/kernel/cpu/perf_event_intel_uncore.h | 66 +++++++++ 2 files changed, 236 insertions(+), 5 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_uncore.c +170 -5
@@ -2,6 +2,11 @@static struct intel_uncore_type *empty_uncore[] = {NULL , };static struct intel_uncore_type **msr_uncores = empty_uncore; +static struct intel_uncore_type **pci_uncores = empty_uncore; +/* pci bus to socket mapping */ +static int pcibus_to_physid[256 ] = { [0 ...255 ] =-1 , }; + +static DEFINE_RAW_SPINLOCK (uncore_box_lock);/* mask of cpus that collect uncore events */ static cpumask_t uncore_cpu_mask;
@@ -205,13 +210,13 @@ static void uncore_assign_hw_event(struct intel_uncore_box *box, hwc->last_tag = ++box->tags[idx];if (hwc->idx ==UNCORE_PMC_IDX_FIXED ) { - hwc->event_base =uncore_msr_fixed_ctr (box); - hwc->config_base =uncore_msr_fixed_ctl (box); + hwc->event_base =uncore_fixed_ctr (box); + hwc->config_base =uncore_fixed_ctl (box);return ; } - hwc->config_base =uncore_msr_event_ctl (box, hwc->idx); - hwc->event_base =uncore_msr_perf_ctr (box, hwc->idx); + hwc->config_base =uncore_event_ctl (box, hwc->idx); + hwc->event_base =uncore_perf_ctr (box, hwc->idx); } static void uncore_perf_event_update(struct intel_uncore_box *box,
@@ -305,6 +310,22 @@ struct intel_uncore_box *uncore_alloc_box(int cpu)static struct intel_uncore_box *uncore_pmu_to_box (struct intel_uncore_pmu *pmu,int cpu) { +static struct intel_uncore_box *box; + + box = *per_cpu_ptr (pmu->box, cpu); +if (box) +return box; + +raw_spin_lock (&uncore_box_lock); +list_for_each_entry (box, &pmu->box_list, list) { +if (box->phys_id ==topology_physical_package_id (cpu)) { +atomic_inc (&box->refcnt); + *per_cpu_ptr (pmu->box, cpu) = box; +break ; + } + } +raw_spin_unlock (&uncore_box_lock); +return *per_cpu_ptr (pmu->box, cpu); }
@@ -706,6 +727,13 @@ static void __init uncore_type_exit(struct intel_uncore_type *type) type->attr_groups[1 ] =NULL ; } +static void uncore_types_exit (struct intel_uncore_type **types) +{ +int i; +for (i =0 ; types[i]; i++) +uncore_type_exit (types[i]); +} +static int __init uncore_type_init (struct intel_uncore_type *type) {struct intel_uncore_pmu *pmus;
@@ -725,6 +753,7 @@ static int __init uncore_type_init(struct intel_uncore_type *type) pmus[i].func_id =-1 ; pmus[i].pmu_idx = i; pmus[i].type = type; +INIT_LIST_HEAD (&pmus[i].box_list); pmus[i].box = alloc_percpu(struct intel_uncore_box *);if (!pmus[i].box) goto fail;
@@ -773,6 +802,127 @@ fail:return ret; } +static struct pci_driver *uncore_pci_driver; +static bool pcidrv_registered; + +/* +* add a pci uncore device +*/ +static int __devinit uncore_pci_add (struct intel_uncore_type *type, +struct pci_dev *pdev) +{ +struct intel_uncore_pmu *pmu; +struct intel_uncore_box *box; +int i, phys_id; + + phys_id = pcibus_to_physid[pdev->bus->number]; +if (phys_id <0 ) +return -ENODEV ; + + box =uncore_alloc_box (0 ); +if (!box) +return -ENOMEM ; + +/* +* for performance monitoring unit with multiple boxes, +* each box has a different function id. +*/ +for (i =0 ; i < type->num_boxes; i++) { + pmu = &type->pmus[i]; +if (pmu->func_id == pdev->devfn) +break ; +if (pmu->func_id <0 ) { + pmu->func_id = pdev->devfn; +break ; + } + pmu =NULL ; + } + +if (!pmu) { +kfree (box); +return -EINVAL ; + } + + box->phys_id = phys_id; + box->pci_dev = pdev; + box->pmu = pmu; +uncore_box_init (box); +pci_set_drvdata (pdev, box); + +raw_spin_lock (&uncore_box_lock); +list_add_tail (&box->list, &pmu->box_list); +raw_spin_unlock (&uncore_box_lock); + +return 0 ; +} + +static void __devexit uncore_pci_remove(struct pci_dev *pdev) +{ +struct intel_uncore_box *box =pci_get_drvdata (pdev); +struct intel_uncore_pmu *pmu = box->pmu; +int cpu, phys_id = pcibus_to_physid[pdev->bus->number]; + +if (WARN_ON_ONCE (phys_id != box->phys_id)) +return ; + +raw_spin_lock (&uncore_box_lock); +list_del (&box->list); +raw_spin_unlock (&uncore_box_lock); + +for_each_possible_cpu (cpu) { +if (*per_cpu_ptr (pmu->box, cpu) == box) { + *per_cpu_ptr (pmu->box, cpu) =NULL ; +atomic_dec (&box->refcnt); + } + } + +WARN_ON_ONCE (atomic_read (&box->refcnt) !=1 ); +kfree (box); +} + +static int __devinit uncore_pci_probe (struct pci_dev *pdev, +const struct pci_device_id *id) +{ +struct intel_uncore_type *type; + + type = (struct intel_uncore_type *)id->driver_data; +return uncore_pci_add (type, pdev); +} + +static int __init uncore_pci_init (void ) +{ +int ret; + +switch (boot_cpu_data.x86_model) { +default : +return 0 ; + } + + ret =uncore_types_init (pci_uncores); +if (ret) +return ret; + + uncore_pci_driver->probe = uncore_pci_probe; + uncore_pci_driver->remove = uncore_pci_remove; + + ret =pci_register_driver (uncore_pci_driver); +if (ret ==0 ) + pcidrv_registered = true; +else +uncore_types_exit (pci_uncores); + +return ret; +} + +static void __init uncore_pci_exit (void ) +{ +if (pcidrv_registered) { + pcidrv_registered = false; +pci_unregister_driver (uncore_pci_driver); +uncore_types_exit (pci_uncores); + } +} +static void __cpuinit uncore_cpu_dying (int cpu) {struct intel_uncore_type *type;
@@ -921,6 +1071,7 @@ static void __cpuinit uncore_event_exit_cpu(int cpu)cpumask_set_cpu (target, &uncore_cpu_mask);uncore_change_context (msr_uncores, cpu, target); +uncore_change_context (pci_uncores, cpu, target); }static void __cpuinit uncore_event_init_cpu (int cpu)
@@ -936,6 +1087,7 @@ static void __cpuinit uncore_event_init_cpu(int cpu)cpumask_set_cpu (cpu, &uncore_cpu_mask);uncore_change_context (msr_uncores,-1 , cpu); +uncore_change_context (pci_uncores,-1 , cpu); } static int __cpuinit uncore_cpu_notifier(struct notifier_block *self,
@@ -1051,6 +1203,14 @@ static int __init uncore_pmus_register(void) } } +for (i =0 ; pci_uncores[i]; i++) { + type = pci_uncores[i]; +for (j =0 ; j < type->num_boxes; j++) { + pmu = &type->pmus[j]; +uncore_pmu_register (pmu); + } + } +return 0 ; }
@@ -1061,9 +1221,14 @@ static int __init intel_uncore_init(void)if (boot_cpu_data.x86_vendor !=X86_VENDOR_INTEL )return -ENODEV ; - ret =uncore_cpu_init (); + ret =uncore_pci_init ();if (ret) goto fail; + ret =uncore_cpu_init (); +if (ret) { +uncore_pci_exit (); + goto fail; + }uncore_pmus_register ();return 0 ;
arch/x86/kernel/cpu/perf_event_intel_uncore.h +66 -0
95 lines not on this page · raw message
PATCH 1/1 perf, x86: Fix section mismatch in uncore_pci_init()
Quoted 13 lines · Zheng
Commit-ID: 14371cce03c2fc393997e17f979e76674b7f392a Gitweb: http://git.kernel.org/tip/14371cce03c2fc393997e17f979e76674b7f392a Author: Yan, Zheng <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:36 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:23 +0200perf: Add generic PCI uncore PMU device support
This patch adds generic support for uncore PMUs presented as PCI devices. (These come in addition to the CPU/MSR based uncores.)
Quoted 8 lines
Signed-off-by Zheng Yan <[email protected]>Signed-off-by Peter Zijlstra <[email protected]>Signed-off-by Ingo Molnar <[email protected]>--- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 175 ++++++++++++++++++++++++- arch/x86/kernel/cpu/perf_event_intel_uncore.h | 66 +++++++++ 2 files changed, 236 insertions(+), 5 deletions(-)
This patch causes a section mismatch, fix below.
-Robert
Quoted 1 line
From
912df3647e53c7bb1c61fd8fe4366cba1f788755Mon Sep 17 00:00:00 2001
From: Robert Richter <[email protected]>
Date: Wed, 20 Jun 2012 18:31:17 +0200
Subject: [PATCH] perf, x86: Fix section mismatch in uncore_pci_init()
Fixing section mismatch in uncore_pci_init():
WARNING: vmlinux.o(.init.text+0x9246): Section mismatch in reference from the function uncore_pci_init() to the function .devexit.text:uncore_pci_remove() The function __init uncore_pci_init() references
a function __devexit uncore_pci_remove().
This is often seen when error handling in the init function
uses functionality in the exit path.
The fix is often to remove the __devexit annotation of
uncore_pci_remove() so it may be used outside an exit section.
--- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_uncore.c +1 -1
@@ -1313,7 +1313,7 @@ static int __devinit uncore_pci_add(struct intel_uncore_type *type,return 0 ; } -static void __devexit uncore_pci_remove(struct pci_dev *pdev) +static void uncore_pci_remove (struct pci_dev *pdev) {struct intel_uncore_box *box =pci_get_drvdata (pdev);struct intel_uncore_pmu *pmu = box->pmu;
Signature · 7 lines
1.7.8.4 -- Advanced Micro Devices, Inc. Operating System Research Center
[tip:perf/core] perf/x86: Fix section mismatch in uncore_pci_init( )
Commit-ID: 357398e96d8c883b010379a7669df43ed0e2e32b Gitweb: http://git.kernel.org/tip/357398e96d8c883b010379a7669df43ed0e2e32b Author: Robert Richter <[email protected]> AuthorDate: Wed, 20 Jun 2012 18:39:27 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 25 Jun 2012 10:32:21 +0200
perf/x86: Fix section mismatch in uncore_pci_init()
Fix section mismatch in uncore_pci_init():
WARNING: vmlinux.o(.init.text+0x9246): Section mismatch in reference from the function uncore_pci_init() to the function .devexit.text:uncore_pci_remove() The function __init uncore_pci_init() references
a function __devexit uncore_pci_remove().
[...]
--- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_uncore.c +1 -1
@@ -1313,7 +1313,7 @@ static int __devinit uncore_pci_add(struct intel_uncore_type *type,return 0 ; } -static void __devexit uncore_pci_remove(struct pci_dev *pdev) +static void uncore_pci_remove (struct pci_dev *pdev) {struct intel_uncore_box *box =pci_get_drvdata (pdev);struct intel_uncore_pmu *pmu = box->pmu;
[tip:perf/urgent] perf, x86: Fix uncore_types_exit section mismatch
In reply to Yan, ZhengCommit-ID: cffa59baa5f1cf3e3e9e172697db48912471531c Gitweb: http://git.kernel.org/tip/cffa59baa5f1cf3e3e9e172697db48912471531c Author: Borislav Petkov <[email protected]> AuthorDate: Thu, 2 Aug 2012 12:55:27 +0200 Committer: Thomas Gleixner <[email protected]> CommitDate: Mon, 13 Aug 2012 19:01:03 +0200
perf, x86: Fix uncore_types_exit section mismatch
Fix the following section mismatch:
WARNING: arch/x86/kernel/cpu/built-in.o(.text+0x7ad9): Section mismatch in reference from the function uncore_types_exit() to the function .init.text:uncore_type_exit()
The function uncore_types_exit() references the function __init uncore_type_exit(). This is often because uncore_types_exit lacks a __init annotation or the annotation of uncore_type_exit is wrong.
caused by 14371cce03c2 ("perf: Add generic PCI uncore PMU device support").
--- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_uncore.c +1 -1
@@ -2373,7 +2373,7 @@ static void __init uncore_type_exit(struct intel_uncore_type *type) type->attr_groups[1 ] =NULL ; } -static void uncore_types_exit (struct intel_uncore_type **types) +static void __init uncore_types_exit (struct intel_uncore_type **types) {int i;for (i =0 ; types[i]; i++)
PATCH v6 8/13 perf: Add Sandy Bridge-EP uncore support
In reply to Yan, ZhengFrom: "Yan, Zheng" <[email protected]>
Add Intel Nehalem and Sandy Bridge uncore pmu support. The uncore subsystem in Sandy Bridge-EP consists of 8 components (Ubox, Cacheing Agent, Home Agent, Memory controller, Power Control, QPI Link Layer, R2PCIe, R3QPI).
--- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 484 +++++++++++++++++++++++++ arch/x86/kernel/cpu/perf_event_intel_uncore.h | 86 +++++ include/linux/pci_ids.h | 11 + 3 files changed, 581 insertions(+), 0 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_uncore.c +484 -0
@@ -21,6 +21,482 @@ DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");DEFINE_UNCORE_FORMAT_ATTR (inv, inv,"config:23" );DEFINE_UNCORE_FORMAT_ATTR (cmask5, cmask,"config:24-28" );DEFINE_UNCORE_FORMAT_ATTR (cmask8, cmask,"config:24-31" ); +DEFINE_UNCORE_FORMAT_ATTR (thresh8, thresh,"config:24-31" ); +DEFINE_UNCORE_FORMAT_ATTR (thresh5, thresh,"config:24-28" ); +DEFINE_UNCORE_FORMAT_ATTR (occ_sel, occ_sel,"config:14-15" ); +DEFINE_UNCORE_FORMAT_ATTR (occ_invert, occ_invert,"config:30" ); +DEFINE_UNCORE_FORMAT_ATTR (occ_edge, occ_edge,"config:14-51" ); + +/* Sandy Bridge-EP uncore support */ +static void snbep_uncore_pci_disable_box (struct intel_uncore_box *box) +{ +struct pci_dev *pdev = box->pci_dev; +int box_ctl =uncore_pci_box_ctl (box); +u32 config; + +pci_read_config_dword (pdev, box_ctl, &config); + config |=SNBEP_PMON_BOX_CTL_FRZ ; +pci_write_config_dword (pdev, box_ctl, config); +} + +static void snbep_uncore_pci_enable_box (struct intel_uncore_box *box) +{ +struct pci_dev *pdev = box->pci_dev; +int box_ctl =uncore_pci_box_ctl (box); +u32 config; + +pci_read_config_dword (pdev, box_ctl, &config); + config &= ~SNBEP_PMON_BOX_CTL_FRZ ; +pci_write_config_dword (pdev, box_ctl, config); +} + +static void snbep_uncore_pci_enable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct pci_dev *pdev = box->pci_dev; +struct hw_perf_event *hwc = &event->hw; + +pci_write_config_dword (pdev, hwc->config_base, hwc->config | +SNBEP_PMON_CTL_EN ); +} + +static void snbep_uncore_pci_disable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct pci_dev *pdev = box->pci_dev; +struct hw_perf_event *hwc = &event->hw; + +pci_write_config_dword (pdev, hwc->config_base, hwc->config); +} + +static u64 snbep_uncore_pci_read_counter (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct pci_dev *pdev = box->pci_dev; +struct hw_perf_event *hwc = &event->hw; +u64 count; + +pci_read_config_dword (pdev, hwc->event_base, (u32 *)&count); +pci_read_config_dword (pdev, hwc->event_base +4 , (u32 *)&count +1 ); +return count; +} + +static void snbep_uncore_pci_init_box (struct intel_uncore_box *box) +{ +struct pci_dev *pdev = box->pci_dev; +pci_write_config_dword (pdev,SNBEP_PCI_PMON_BOX_CTL , +SNBEP_PMON_BOX_CTL_INT ); +} + +static void snbep_uncore_msr_disable_box (struct intel_uncore_box *box) +{ +u64 config; +unsigned msr; + + msr =uncore_msr_box_ctl (box); +if (msr) { +rdmsrl (msr, config); + config |=SNBEP_PMON_BOX_CTL_FRZ ; +wrmsrl (msr, config); +return ; + } +} + +static void snbep_uncore_msr_enable_box (struct intel_uncore_box *box) +{ +u64 config; +unsigned msr; + + msr =uncore_msr_box_ctl (box); +if (msr) { +rdmsrl (msr, config); + config &= ~SNBEP_PMON_BOX_CTL_FRZ ; +wrmsrl (msr, config); +return ; + } +} + +static void snbep_uncore_msr_enable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +wrmsrl (hwc->config_base, hwc->config |SNBEP_PMON_CTL_EN ); +} + +static void snbep_uncore_msr_disable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +wrmsrl (hwc->config_base, hwc->config); +} + +static u64 snbep_uncore_msr_read_counter (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; +u64 count; + +rdmsrl (hwc->event_base, count); +return count; +} + +static void snbep_uncore_msr_init_box (struct intel_uncore_box *box) +{ +unsigned msr =uncore_msr_box_ctl (box); +if (msr) +wrmsrl (msr,SNBEP_PMON_BOX_CTL_INT ); +} + +static struct attribute *snbep_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh8.attr, +NULL , +}; + +static struct attribute *snbep_uncore_ubox_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh5.attr, +NULL , +}; + +static struct attribute *snbep_uncore_pcu_formats_attr[] = { + &format_attr_event.attr, + &format_attr_occ_sel.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh5.attr, + &format_attr_occ_invert.attr, + &format_attr_occ_edge.attr, +NULL , +}; + +static struct uncore_event_desc snbep_uncore_imc_events[] = { +INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"config=0xffff" ), +/* read */ +INTEL_UNCORE_EVENT_DESC (CAS_COUNT_RD ,"event=0x4,umask=0x3" ), +/* write */ +INTEL_UNCORE_EVENT_DESC (CAS_COUNT_WR ,"event=0x4,umask=0xc" ), + {/* end: all zeroes */ }, +}; + +static struct uncore_event_desc snbep_uncore_qpi_events[] = { +INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"event=0x14" ), +/* outgoing data+nondata flits */ +INTEL_UNCORE_EVENT_DESC (TxL_FLITS_ACTIVE,"event=0x0,umask=0x6" ), +/* DRS data received */ +INTEL_UNCORE_EVENT_DESC (DRS_DATA ,"event=0x2,umask=0x8" ), +/* NCB data received */ +INTEL_UNCORE_EVENT_DESC (NCB_DATA ,"event=0x3,umask=0x4" ), + {/* end: all zeroes */ }, +}; + +static struct attribute_group snbep_uncore_format_group = { + .name ="format" , + .attrs = snbep_uncore_formats_attr, +}; + +static struct attribute_group snbep_uncore_ubox_format_group = { + .name ="format" , + .attrs = snbep_uncore_ubox_formats_attr, +}; + +static struct attribute_group snbep_uncore_pcu_format_group = { + .name ="format" , + .attrs = snbep_uncore_pcu_formats_attr, +}; + +static struct intel_uncore_ops snbep_uncore_msr_ops = { + .init_box = snbep_uncore_msr_init_box, + .disable_box = snbep_uncore_msr_disable_box, + .enable_box = snbep_uncore_msr_enable_box, + .disable_event = snbep_uncore_msr_disable_event, + .enable_event = snbep_uncore_msr_enable_event, + .read_counter = snbep_uncore_msr_read_counter, +}; + +static struct intel_uncore_ops snbep_uncore_pci_ops = { + .init_box = snbep_uncore_pci_init_box, + .disable_box = snbep_uncore_pci_disable_box, + .enable_box = snbep_uncore_pci_enable_box, + .disable_event = snbep_uncore_pci_disable_event, + .enable_event = snbep_uncore_pci_enable_event, + .read_counter = snbep_uncore_pci_read_counter, +}; + +static struct event_constraint snbep_uncore_cbo_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x01 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x02 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x04 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x05 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x07 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x11 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x12 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x13 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x1b ,0xc ), +UNCORE_EVENT_CONSTRAINT (0x1c ,0xc ), +UNCORE_EVENT_CONSTRAINT (0x1d ,0xc ), +UNCORE_EVENT_CONSTRAINT (0x1e ,0xc ), +UNCORE_EVENT_CONSTRAINT (0x1f ,0xe ), +UNCORE_EVENT_CONSTRAINT (0x21 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x23 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x31 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x32 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x33 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x34 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x35 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x36 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x37 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x38 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x39 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x3b ,0x1 ), +EVENT_CONSTRAINT_END +}; + +static struct event_constraint snbep_uncore_r2pcie_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x10 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x11 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x12 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x23 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x24 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x25 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x26 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x32 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x33 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x34 ,0x3 ), +EVENT_CONSTRAINT_END +}; + +static struct event_constraint snbep_uncore_r3qpi_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x10 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x11 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x12 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x13 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x20 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x21 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x22 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x23 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x24 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x25 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x26 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x30 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x31 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x32 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x33 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x34 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x36 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x37 ,0x3 ), +EVENT_CONSTRAINT_END +}; + +static struct intel_uncore_type snbep_uncore_ubox = { + .name ="ubox" , + .num_counters =2 , + .num_boxes =1 , + .perf_ctr_bits =44 , + .fixed_ctr_bits =48 , + .perf_ctr =SNBEP_U_MSR_PMON_CTR0 , + .event_ctl =SNBEP_U_MSR_PMON_CTL0 , + .event_mask =SNBEP_U_MSR_PMON_RAW_EVENT_MASK , + .fixed_ctr =SNBEP_U_MSR_PMON_UCLK_FIXED_CTR , + .fixed_ctl =SNBEP_U_MSR_PMON_UCLK_FIXED_CTL , + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_ubox_format_group, +}; + +static struct intel_uncore_type snbep_uncore_cbo = { + .name ="cbo" , + .num_counters =4 , + .num_boxes =8 , + .perf_ctr_bits =44 , + .event_ctl =SNBEP_C0_MSR_PMON_CTL0 , + .perf_ctr =SNBEP_C0_MSR_PMON_CTR0 , + .event_mask =SNBEP_PMON_RAW_EVENT_MASK , + .box_ctl =SNBEP_C0_MSR_PMON_BOX_CTL , + .msr_offset =SNBEP_CBO_MSR_OFFSET , + .constraints = snbep_uncore_cbo_constraints, + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_format_group, +}; + +static struct intel_uncore_type snbep_uncore_pcu = { + .name ="pcu" , + .num_counters =4 , + .num_boxes =1 , + .perf_ctr_bits =48 , + .perf_ctr =SNBEP_PCU_MSR_PMON_CTR0 , + .event_ctl =SNBEP_PCU_MSR_PMON_CTL0 , + .event_mask =SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK , + .box_ctl =SNBEP_PCU_MSR_PMON_BOX_CTL , + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_pcu_format_group, +}; + +static struct intel_uncore_type *snbep_msr_uncores[] = { + &snbep_uncore_ubox, + &snbep_uncore_cbo, + &snbep_uncore_pcu, +NULL , +}; + +#define SNBEP_UNCORE_PCI_COMMON_INIT () \ + .perf_ctr = SNBEP_PCI_PMON_CTR0, \ + .event_ctl = SNBEP_PCI_PMON_CTL0, \ + .event_mask = SNBEP_PMON_RAW_EVENT_MASK, \ + .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \ + .ops = &snbep_uncore_pci_ops, \ + .format_group = &snbep_uncore_format_group + +static struct intel_uncore_type snbep_uncore_ha = { + .name ="ha" , + .num_counters =4 , + .num_boxes =1 , + .perf_ctr_bits =48 , +SNBEP_UNCORE_PCI_COMMON_INIT (), +}; + +static struct intel_uncore_type snbep_uncore_imc = { + .name ="imc" , + .num_counters =4 , + .num_boxes =4 , + .perf_ctr_bits =48 , + .fixed_ctr_bits =48 , + .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, + .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, + .event_descs = snbep_uncore_imc_events, +SNBEP_UNCORE_PCI_COMMON_INIT (), +}; + +static struct intel_uncore_type snbep_uncore_qpi = { + .name ="qpi" , + .num_counters =4 , + .num_boxes =2 , + .perf_ctr_bits =48 , + .event_descs = snbep_uncore_qpi_events, +SNBEP_UNCORE_PCI_COMMON_INIT (), +}; + + +static struct intel_uncore_type snbep_uncore_r2pcie = { + .name ="r2pcie" , + .num_counters =4 , + .num_boxes =1 , + .perf_ctr_bits =44 , + .constraints = snbep_uncore_r2pcie_constraints, +SNBEP_UNCORE_PCI_COMMON_INIT (), +}; + +static struct intel_uncore_type snbep_uncore_r3qpi = { + .name ="r3qpi" , + .num_counters =3 , + .num_boxes =2 , + .perf_ctr_bits =44 , + .constraints = snbep_uncore_r3qpi_constraints, +SNBEP_UNCORE_PCI_COMMON_INIT (), +}; + +static struct intel_uncore_type *snbep_pci_uncores[] = { + &snbep_uncore_ha, + &snbep_uncore_imc, + &snbep_uncore_qpi, + &snbep_uncore_r2pcie, + &snbep_uncore_r3qpi, +NULL , +}; + +static DEFINE_PCI_DEVICE_TABLE (snbep_uncore_pci_ids) = { + {/* Home Agent */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_HA ), + .driver_data = (unsigned long )&snbep_uncore_ha, + }, + {/* MC Channel 0 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_IMC0 ), + .driver_data = (unsigned long )&snbep_uncore_imc, + }, + {/* MC Channel 1 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_IMC1 ), + .driver_data = (unsigned long )&snbep_uncore_imc, + }, + {/* MC Channel 2 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_IMC2 ), + .driver_data = (unsigned long )&snbep_uncore_imc, + }, + {/* MC Channel 3 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_IMC3 ), + .driver_data = (unsigned long )&snbep_uncore_imc, + }, + {/* QPI Port 0 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_QPI0 ), + .driver_data = (unsigned long )&snbep_uncore_qpi, + }, + {/* QPI Port 1 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_QPI1 ), + .driver_data = (unsigned long )&snbep_uncore_qpi, + }, + {/* P2PCIe */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_R2PCIE ), + .driver_data = (unsigned long )&snbep_uncore_r2pcie, + }, + {/* R3QPI Link 0 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_R3QPI0 ), + .driver_data = (unsigned long )&snbep_uncore_r3qpi, + }, + {/* R3QPI Link 1 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_R3QPI1 ), + .driver_data = (unsigned long )&snbep_uncore_r3qpi, + }, + {/* end: all zeroes */ } +}; + +static struct pci_driver snbep_uncore_pci_driver = { + .name ="snbep_uncore" , + .id_table = snbep_uncore_pci_ids, +}; + +/* +* build pci bus to socket mapping +*/ +static void snbep_pci2phy_map_init (void ) +{ +struct pci_dev *ubox_dev =NULL ; +int i, bus, nodeid; +u32 config; + +while (1 ) { +/* find the UBOX device */ + ubox_dev =pci_get_device (PCI_VENDOR_ID_INTEL , +PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX , + ubox_dev); +if (!ubox_dev) +break ; + bus = ubox_dev->bus->number; +/* get the Node ID of the local register */ +pci_read_config_dword (ubox_dev,0x40 , &config); + nodeid = config; +/* get the Node ID mapping */ +pci_read_config_dword (ubox_dev,0x54 , &config); +/* +* every three bits in the Node ID mapping register maps +* to a particular node. +*/ +for (i =0 ; i <8 ; i++) { +if (nodeid == ((config >> (3 * i)) &0x7 )) { + pcibus_to_physid[bus] = i; +break ; + } + } + }; +return ; +} +/* end of Sandy Bridge-EP uncore support */ +/* Sandy Bridge uncore support */ static void snb_uncore_msr_enable_event(struct intel_uncore_box *box,
@@ -894,6 +1370,11 @@ static int __init uncore_pci_init(void)int ret;switch (boot_cpu_data.x86_model) { +case 45 :/* Sandy Bridge-EP */ + pci_uncores = snbep_pci_uncores; + uncore_pci_driver = &snbep_uncore_pci_driver; +snbep_pci2phy_map_init (); +break ;default :return 0 ; }
@@ -1154,6 +1635,9 @@ static int __init uncore_cpu_init(void)case 42 :/* Sandy Bridge */ msr_uncores = snb_msr_uncores;break ; +case 45 :/* Sandy Birdge-EP */ + msr_uncores = snbep_msr_uncores; +break ;default :return 0 ; }
arch/x86/kernel/cpu/perf_event_intel_uncore.h +86 -0
92 lines not on this page · raw message
include/linux/pci_ids.h +11 -0
@@ -2756,6 +2756,17 @@#define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27#define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e#define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f +#define PCI_DEVICE_ID_INTEL_UNC_HA 0x3c46 +#define PCI_DEVICE_ID_INTEL_UNC_IMC0 0x3cb0 +#define PCI_DEVICE_ID_INTEL_UNC_IMC1 0x3cb1 +#define PCI_DEVICE_ID_INTEL_UNC_IMC2 0x3cb4 +#define PCI_DEVICE_ID_INTEL_UNC_IMC3 0x3cb5 +#define PCI_DEVICE_ID_INTEL_UNC_QPI0 0x3c41 +#define PCI_DEVICE_ID_INTEL_UNC_QPI1 0x3c42 +#define PCI_DEVICE_ID_INTEL_UNC_R2PCIE 0x3c43 +#define PCI_DEVICE_ID_INTEL_UNC_R3QPI0 0x3c44 +#define PCI_DEVICE_ID_INTEL_UNC_R3QPI1 0x3c45 +#define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX 0x3ce0#define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f#define PCI_DEVICE_ID_INTEL_5100_16 0x65f0#define PCI_DEVICE_ID_INTEL_5100_21 0x65f5
Signature · 1 line
1.7.6.5
Re: [PATCH V6 08/13] perf: Add Sandy Bridge-EP uncore support
arch/x86/kernel/cpu/perf_event_intel_uncore.c DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); · line 275
Quoted 13 lines · Zheng
arch/x86/kernel/cpu/perf_event_intel_uncore.c +13
-0+static struct event_constraint snbep_uncore_r2pcie_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x10 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x11 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x12 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x23 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x24 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x25 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x26 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x32 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x33 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x34 ,0x3 ), +EVENT_CONSTRAINT_END +};
My E5-2600 Uncore Perf. Mon. Guide, March 2012 (Ref.# 327043-001) doesn't seem to list events 0x26 and up.
I'm staring at 2.8.5, table 2-108.
Is my document out-dated or what's up?
the r3qpi table seems to match, but the cbox one is funny again, event 0x01 doesn't appear in the doc, nor does 0x3b, 0x38, 0x23.
FWIW, cbox event constraint 0x1f needs to be an EVENT_CONSTRAINT_OVERLAP, see the comment near that macro definition.
Re: [PATCH V6 08/13] perf: Add Sandy Bridge-EP uncore support
Quoted 18 lines · Peter Zijlstra
arch/x86/kernel/cpu/perf_event_intel_uncore.c DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); · line 275
Quoted 13 lines · Zheng
arch/x86/kernel/cpu/perf_event_intel_uncore.c +13
-0+static struct event_constraint snbep_uncore_r2pcie_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x10 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x11 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x12 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x23 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x24 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x25 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x26 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x32 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x33 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x34 ,0x3 ), +EVENT_CONSTRAINT_END +};My E5-2600 Uncore Perf. Mon. Guide, March 2012 (Ref.# 327043-001) doesn't seem to list events
0x26and up.
Quoted 7 lines
I'm staring at 2.8.5, table 2-108.
Is my document out-dated or what's up?
the r3qpi table seems to match, but the cbox one is funny again, event
0x01doesn't appear in the doc, nor does0x3b,0x38,0x23.
Sorry, my document is out-dated. These events were listed in the old document. should we remove them ?
Quoted 3 lines
FWIW, cbox event constraint
0x1fneeds to be anEVENT_CONSTRAINT_OVERLAP, see the comment near that macro definition.
thanks for reminding
Regards
Yan, Zheng
Re: [PATCH V6 08/13] perf: Add Sandy Bridge-EP uncore support
Quoted 2 lines · Zheng
Sorry, my document is out-dated. These events were listed in the old document. should we remove them ?
No idea, ask someone from the hardware team for clarification.
If these events were scrapped because they failed to pass validation or so, it doesn't really matter if we include the constraints since the results are screwy anyway -- unless of course programming these events 'wrong' will screw over something else.
Re: [PATCH V6 08/13] perf: Add Sandy Bridge-EP uncore support
In reply to Yan, ZhengQuoted 7 lines · Zheng
From: "Yan, Zheng" <[email protected]>
Add Intel Nehalem and Sandy Bridge uncore pmu support. The uncore subsystem in Sandy Bridge-EP consists of 8 components (Ubox, Cacheing Agent, Home Agent, Memory controller, Power Control, QPI Link Layer, R2PCIe, R3QPI).
I did not find in this patch the support for the C-Box Filter register (SNBEP_C0_MSR_PMON_BOX_FILTER). Based on the description
in the manual, looks like a valuable filter to support, especially for the core/thread filtering capability.
There is only one such filter per box, and it can be used by any events. So looks like we have another offcore_resp style register to manage here. Need to ensure the value of that filter is shared by all 4 counters. If you were to support that, you'd have to enable the tid filter on the CBox config regs and export that via sysfs. Also I assume you'd pass the value of that filter either in config1 or in the upper 32 bits of the config reg.
What's your take on that?
Quoted 638 lines
Signed-off-by Zheng Yan <[email protected]>---
arch/x86/kernel/cpu/perf_event_intel_uncore.c | 484 +++++++++++++++++++++++++arch/x86/kernel/cpu/perf_event_intel_uncore.h| 86 +++++include/linux/pci_ids.h| 11 +3 files changed, 581 insertions(+), 0 deletions(-)arch/x86/kernel/cpu/perf_event_intel_uncore.c +481
-0@@ -21,6 +21,482 @@ DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); DEFINE_UNCORE_FORMAT_ATTR(cmask5, cmask, "config:24-28"); DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31"); +DEFINE_UNCORE_FORMAT_ATTR (thresh8, thresh,"config:24-31" ); +DEFINE_UNCORE_FORMAT_ATTR (thresh5, thresh,"config:24-28" ); +DEFINE_UNCORE_FORMAT_ATTR (occ_sel, occ_sel,"config:14-15" ); +DEFINE_UNCORE_FORMAT_ATTR (occ_invert, occ_invert,"config:30" ); +DEFINE_UNCORE_FORMAT_ATTR (occ_edge, occ_edge,"config:14-51" ); + +/* Sandy Bridge-EP uncore support */ +static void snbep_uncore_pci_disable_box (struct intel_uncore_box *box) +{ + struct pci_dev *pdev = box->pci_dev; + int box_ctl = uncore_pci_box_ctl(box); + u32 config; + + pci_read_config_dword(pdev, box_ctl, &config); + config |= SNBEP_PMON_BOX_CTL_FRZ; + pci_write_config_dword(pdev, box_ctl, config); +} + +static void snbep_uncore_pci_enable_box (struct intel_uncore_box *box) +{ + struct pci_dev *pdev = box->pci_dev; + int box_ctl = uncore_pci_box_ctl(box); + u32 config; + + pci_read_config_dword(pdev, box_ctl, &config); + config &= ~SNBEP_PMON_BOX_CTL_FRZ; + pci_write_config_dword(pdev, box_ctl, config); +} + +static void snbep_uncore_pci_enable_event (struct intel_uncore_box *box, + struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + + pci_write_config_dword(pdev, hwc->config_base, hwc->config | + SNBEP_PMON_CTL_EN); +} + +static void snbep_uncore_pci_disable_event (struct intel_uncore_box *box, + struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + + pci_write_config_dword(pdev, hwc->config_base, hwc->config); +} + +static u64 snbep_uncore_pci_read_counter (struct intel_uncore_box *box, + struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + u64 count; + + pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count); + pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1); + return count; +} + +static void snbep_uncore_pci_init_box (struct intel_uncore_box *box) +{ + struct pci_dev *pdev = box->pci_dev; + pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, + SNBEP_PMON_BOX_CTL_INT); +} + +static void snbep_uncore_msr_disable_box (struct intel_uncore_box *box) +{ + u64 config; + unsigned msr; + + msr = uncore_msr_box_ctl(box); + if (msr) { + rdmsrl(msr, config); + config |= SNBEP_PMON_BOX_CTL_FRZ; + wrmsrl(msr, config); + return; + } +} + +static void snbep_uncore_msr_enable_box (struct intel_uncore_box *box) +{ + u64 config; + unsigned msr; + + msr = uncore_msr_box_ctl(box); + if (msr) { + rdmsrl(msr, config); + config &= ~SNBEP_PMON_BOX_CTL_FRZ; + wrmsrl(msr, config); + return; + } +} + +static void snbep_uncore_msr_enable_event (struct intel_uncore_box *box, + struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + + wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN); +} + +static void snbep_uncore_msr_disable_event (struct intel_uncore_box *box, + struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + + wrmsrl(hwc->config_base, hwc->config); +} + +static u64 snbep_uncore_msr_read_counter (struct intel_uncore_box *box, + struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + u64 count; + + rdmsrl(hwc->event_base, count); + return count; +} + +static void snbep_uncore_msr_init_box (struct intel_uncore_box *box) +{ + unsigned msr = uncore_msr_box_ctl(box); + if (msr) + wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT); +} + +static struct attribute *snbep_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh8.attr, + NULL, +}; + +static struct attribute *snbep_uncore_ubox_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh5.attr, + NULL, +}; + +static struct attribute *snbep_uncore_pcu_formats_attr[] = { + &format_attr_event.attr, + &format_attr_occ_sel.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh5.attr, + &format_attr_occ_invert.attr, + &format_attr_occ_edge.attr, + NULL, +}; + +static struct uncore_event_desc snbep_uncore_imc_events[] = { + INTEL_UNCORE_EVENT_DESC(CLOCKTICKS, "config=0xffff"), + /* read */ + INTEL_UNCORE_EVENT_DESC(CAS_COUNT_RD, "event=0x4,umask=0x3"), + /* write */ + INTEL_UNCORE_EVENT_DESC(CAS_COUNT_WR, "event=0x4,umask=0xc"), + { /* end: all zeroes */ }, +}; + +static struct uncore_event_desc snbep_uncore_qpi_events[] = { + INTEL_UNCORE_EVENT_DESC(CLOCKTICKS, "event=0x14"), + /* outgoing data+nondata flits */ + INTEL_UNCORE_EVENT_DESC(TxL_FLITS_ACTIVE, "event=0x0,umask=0x6"), + /* DRS data received */ + INTEL_UNCORE_EVENT_DESC(DRS_DATA, "event=0x2,umask=0x8"), + /* NCB data received */ + INTEL_UNCORE_EVENT_DESC(NCB_DATA, "event=0x3,umask=0x4"), + { /* end: all zeroes */ }, +}; + +static struct attribute_group snbep_uncore_format_group = { + .name = "format", + .attrs = snbep_uncore_formats_attr, +}; + +static struct attribute_group snbep_uncore_ubox_format_group = { + .name = "format", + .attrs = snbep_uncore_ubox_formats_attr, +}; + +static struct attribute_group snbep_uncore_pcu_format_group = { + .name = "format", + .attrs = snbep_uncore_pcu_formats_attr, +}; + +static struct intel_uncore_ops snbep_uncore_msr_ops = { + .init_box = snbep_uncore_msr_init_box, + .disable_box = snbep_uncore_msr_disable_box, + .enable_box = snbep_uncore_msr_enable_box, + .disable_event = snbep_uncore_msr_disable_event, + .enable_event = snbep_uncore_msr_enable_event, + .read_counter = snbep_uncore_msr_read_counter, +}; + +static struct intel_uncore_ops snbep_uncore_pci_ops = { + .init_box = snbep_uncore_pci_init_box, + .disable_box = snbep_uncore_pci_disable_box, + .enable_box = snbep_uncore_pci_enable_box, + .disable_event = snbep_uncore_pci_disable_event, + .enable_event = snbep_uncore_pci_enable_event, + .read_counter = snbep_uncore_pci_read_counter, +}; + +static struct event_constraint snbep_uncore_cbo_constraints[] = { + UNCORE_EVENT_CONSTRAINT(0x01, 0x1), + UNCORE_EVENT_CONSTRAINT(0x02, 0x3), + UNCORE_EVENT_CONSTRAINT(0x04, 0x3), + UNCORE_EVENT_CONSTRAINT(0x05, 0x3), + UNCORE_EVENT_CONSTRAINT(0x07, 0x3), + UNCORE_EVENT_CONSTRAINT(0x11, 0x1), + UNCORE_EVENT_CONSTRAINT(0x12, 0x3), + UNCORE_EVENT_CONSTRAINT(0x13, 0x3), + UNCORE_EVENT_CONSTRAINT(0x1b, 0xc), + UNCORE_EVENT_CONSTRAINT(0x1c, 0xc), + UNCORE_EVENT_CONSTRAINT(0x1d, 0xc), + UNCORE_EVENT_CONSTRAINT(0x1e, 0xc), + UNCORE_EVENT_CONSTRAINT(0x1f, 0xe), + UNCORE_EVENT_CONSTRAINT(0x21, 0x3), + UNCORE_EVENT_CONSTRAINT(0x23, 0x3), + UNCORE_EVENT_CONSTRAINT(0x31, 0x3), + UNCORE_EVENT_CONSTRAINT(0x32, 0x3), + UNCORE_EVENT_CONSTRAINT(0x33, 0x3), + UNCORE_EVENT_CONSTRAINT(0x34, 0x3), + UNCORE_EVENT_CONSTRAINT(0x35, 0x3), + UNCORE_EVENT_CONSTRAINT(0x36, 0x1), + UNCORE_EVENT_CONSTRAINT(0x37, 0x3), + UNCORE_EVENT_CONSTRAINT(0x38, 0x3), + UNCORE_EVENT_CONSTRAINT(0x39, 0x3), + UNCORE_EVENT_CONSTRAINT(0x3b, 0x1), + EVENT_CONSTRAINT_END +}; + +static struct event_constraint snbep_uncore_r2pcie_constraints[] = { + UNCORE_EVENT_CONSTRAINT(0x10, 0x3), + UNCORE_EVENT_CONSTRAINT(0x11, 0x3), + UNCORE_EVENT_CONSTRAINT(0x12, 0x1), + UNCORE_EVENT_CONSTRAINT(0x23, 0x3), + UNCORE_EVENT_CONSTRAINT(0x24, 0x3), + UNCORE_EVENT_CONSTRAINT(0x25, 0x3), + UNCORE_EVENT_CONSTRAINT(0x26, 0x3), + UNCORE_EVENT_CONSTRAINT(0x32, 0x3), + UNCORE_EVENT_CONSTRAINT(0x33, 0x3), + UNCORE_EVENT_CONSTRAINT(0x34, 0x3), + EVENT_CONSTRAINT_END +}; + +static struct event_constraint snbep_uncore_r3qpi_constraints[] = { + UNCORE_EVENT_CONSTRAINT(0x10, 0x3), + UNCORE_EVENT_CONSTRAINT(0x11, 0x3), + UNCORE_EVENT_CONSTRAINT(0x12, 0x3), + UNCORE_EVENT_CONSTRAINT(0x13, 0x1), + UNCORE_EVENT_CONSTRAINT(0x20, 0x3), + UNCORE_EVENT_CONSTRAINT(0x21, 0x3), + UNCORE_EVENT_CONSTRAINT(0x22, 0x3), + UNCORE_EVENT_CONSTRAINT(0x23, 0x3), + UNCORE_EVENT_CONSTRAINT(0x24, 0x3), + UNCORE_EVENT_CONSTRAINT(0x25, 0x3), + UNCORE_EVENT_CONSTRAINT(0x26, 0x3), + UNCORE_EVENT_CONSTRAINT(0x30, 0x3), + UNCORE_EVENT_CONSTRAINT(0x31, 0x3), + UNCORE_EVENT_CONSTRAINT(0x32, 0x3), + UNCORE_EVENT_CONSTRAINT(0x33, 0x3), + UNCORE_EVENT_CONSTRAINT(0x34, 0x3), + UNCORE_EVENT_CONSTRAINT(0x36, 0x3), + UNCORE_EVENT_CONSTRAINT(0x37, 0x3), + EVENT_CONSTRAINT_END +}; + +static struct intel_uncore_type snbep_uncore_ubox = { + .name = "ubox", + .num_counters = 2, + .num_boxes = 1, + .perf_ctr_bits = 44, + .fixed_ctr_bits = 48, + .perf_ctr = SNBEP_U_MSR_PMON_CTR0, + .event_ctl = SNBEP_U_MSR_PMON_CTL0, + .event_mask = SNBEP_U_MSR_PMON_RAW_EVENT_MASK, + .fixed_ctr = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR, + .fixed_ctl = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL, + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_ubox_format_group, +}; + +static struct intel_uncore_type snbep_uncore_cbo = { + .name = "cbo", + .num_counters = 4, + .num_boxes = 8, + .perf_ctr_bits = 44, + .event_ctl = SNBEP_C0_MSR_PMON_CTL0, + .perf_ctr = SNBEP_C0_MSR_PMON_CTR0, + .event_mask = SNBEP_PMON_RAW_EVENT_MASK, + .box_ctl = SNBEP_C0_MSR_PMON_BOX_CTL, + .msr_offset = SNBEP_CBO_MSR_OFFSET, + .constraints = snbep_uncore_cbo_constraints, + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_format_group, +}; + +static struct intel_uncore_type snbep_uncore_pcu = { + .name = "pcu", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .perf_ctr = SNBEP_PCU_MSR_PMON_CTR0, + .event_ctl = SNBEP_PCU_MSR_PMON_CTL0, + .event_mask = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK, + .box_ctl = SNBEP_PCU_MSR_PMON_BOX_CTL, + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_pcu_format_group, +}; + +static struct intel_uncore_type *snbep_msr_uncores[] = { + &snbep_uncore_ubox, + &snbep_uncore_cbo, + &snbep_uncore_pcu, + NULL, +}; + +#define SNBEP_UNCORE_PCI_COMMON_INIT () \ + .perf_ctr = SNBEP_PCI_PMON_CTR0, \ + .event_ctl = SNBEP_PCI_PMON_CTL0, \ + .event_mask = SNBEP_PMON_RAW_EVENT_MASK, \ + .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \ + .ops = &snbep_uncore_pci_ops, \ + .format_group = &snbep_uncore_format_group + +static struct intel_uncore_type snbep_uncore_ha = { + .name = "ha", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + SNBEP_UNCORE_PCI_COMMON_INIT(), +}; + +static struct intel_uncore_type snbep_uncore_imc = { + .name = "imc", + .num_counters = 4, + .num_boxes = 4, + .perf_ctr_bits = 48, + .fixed_ctr_bits = 48, + .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, + .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, + .event_descs = snbep_uncore_imc_events, + SNBEP_UNCORE_PCI_COMMON_INIT(), +}; + +static struct intel_uncore_type snbep_uncore_qpi = { + .name = "qpi", + .num_counters = 4, + .num_boxes = 2, + .perf_ctr_bits = 48, + .event_descs = snbep_uncore_qpi_events, + SNBEP_UNCORE_PCI_COMMON_INIT(), +}; + + +static struct intel_uncore_type snbep_uncore_r2pcie = { + .name = "r2pcie", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 44, + .constraints = snbep_uncore_r2pcie_constraints, + SNBEP_UNCORE_PCI_COMMON_INIT(), +}; + +static struct intel_uncore_type snbep_uncore_r3qpi = { + .name = "r3qpi", + .num_counters = 3, + .num_boxes = 2, + .perf_ctr_bits = 44, + .constraints = snbep_uncore_r3qpi_constraints, + SNBEP_UNCORE_PCI_COMMON_INIT(), +}; + +static struct intel_uncore_type *snbep_pci_uncores[] = { + &snbep_uncore_ha, + &snbep_uncore_imc, + &snbep_uncore_qpi, + &snbep_uncore_r2pcie, + &snbep_uncore_r3qpi, + NULL, +}; + +static DEFINE_PCI_DEVICE_TABLE (snbep_uncore_pci_ids) = { + { /* Home Agent */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA), + .driver_data = (unsigned long)&snbep_uncore_ha, + }, + { /* MC Channel 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0), + .driver_data = (unsigned long)&snbep_uncore_imc, + }, + { /* MC Channel 1 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1), + .driver_data = (unsigned long)&snbep_uncore_imc, + }, + { /* MC Channel 2 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2), + .driver_data = (unsigned long)&snbep_uncore_imc, + }, + { /* MC Channel 3 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3), + .driver_data = (unsigned long)&snbep_uncore_imc, + }, + { /* QPI Port 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0), + .driver_data = (unsigned long)&snbep_uncore_qpi, + }, + { /* QPI Port 1 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1), + .driver_data = (unsigned long)&snbep_uncore_qpi, + }, + { /* P2PCIe */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE), + .driver_data = (unsigned long)&snbep_uncore_r2pcie, + }, + { /* R3QPI Link 0 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0), + .driver_data = (unsigned long)&snbep_uncore_r3qpi, + }, + { /* R3QPI Link 1 */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1), + .driver_data = (unsigned long)&snbep_uncore_r3qpi, + }, + { /* end: all zeroes */ } +}; + +static struct pci_driver snbep_uncore_pci_driver = { + .name = "snbep_uncore", + .id_table = snbep_uncore_pci_ids, +}; + +/* +* build pci bus to socket mapping +*/ +static void snbep_pci2phy_map_init (void ) +{ + struct pci_dev *ubox_dev = NULL; + int i, bus, nodeid; + u32 config; + + while (1) { + /* find the UBOX device */ + ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX, + ubox_dev); + if (!ubox_dev) + break; + bus = ubox_dev->bus->number; + /* get the Node ID of the local register */ + pci_read_config_dword(ubox_dev, 0x40, &config); + nodeid = config; + /* get the Node ID mapping */ + pci_read_config_dword(ubox_dev, 0x54, &config); + /* + * every three bits in the Node ID mapping register maps + * to a particular node. + */ + for (i = 0; i < 8; i++) { + if (nodeid == ((config >> (3 * i)) & 0x7)) { + pcibus_to_physid[bus] = i; + break; + } + } + }; + return; +} +/* end of Sandy Bridge-EP uncore support */ + /* Sandy Bridge uncore support */ static void snb_uncore_msr_enable_event(struct intel_uncore_box *box,@@ -894,6 +1370,11 @@ static int __init uncore_pci_init(void) int ret; switch (boot_cpu_data.x86_model) { + case 45: /* Sandy Bridge-EP */ + pci_uncores = snbep_pci_uncores; + uncore_pci_driver = &snbep_uncore_pci_driver; + snbep_pci2phy_map_init(); + break;default:
return 0;
}arch/x86/kernel/cpu/perf_event_intel_uncore.c +0
-0@@ -1154,6 +1635,9 @@ static int __init uncore_cpu_init(void)case 42: /* Sandy Bridge */
msr_uncores =snb_msr_uncores;
break;
+ case 45: /* Sandy Birdge-EP */
+msr_uncores=snbep_msr_uncores;
+ break;
default:
return 0;
}arch/x86/kernel/cpu/perf_event_intel_uncore.h +86
-0@@ -65,6 +65,92 @@ #define NHM_UNC_PERFEVTSEL0 0x3c0 #define NHM_UNC_UNCORE_PMC0 0x3b0 +/* SNB-EP Box level control */ +#define SNBEP_PMON_BOX_CTL_RST_CTRL (1 << 0) +#define SNBEP_PMON_BOX_CTL_RST_CTRS (1 << 1) +#define SNBEP_PMON_BOX_CTL_FRZ (1 << 8) +#define SNBEP_PMON_BOX_CTL_FRZ_EN (1 << 16) +#define SNBEP_PMON_BOX_CTL_INT (SNBEP_PMON_BOX_CTL_RST_CTRL | \ + SNBEP_PMON_BOX_CTL_RST_CTRS | \ + SNBEP_PMON_BOX_CTL_FRZ_EN) +/* SNB-EP event control */ +#define SNBEP_PMON_CTL_EV_SEL_MASK 0x000000ff +#define SNBEP_PMON_CTL_UMASK_MASK 0x0000ff00 +#define SNBEP_PMON_CTL_RST (1 << 17) +#define SNBEP_PMON_CTL_EDGE_DET (1 << 18) +#define SNBEP_PMON_CTL_EV_SEL_EXT (1 << 21)/* only for QPI */ +#define SNBEP_PMON_CTL_EN (1 << 22) +#define SNBEP_PMON_CTL_INVERT (1 << 23) +#define SNBEP_PMON_CTL_TRESH_MASK 0xff000000 +#define SNBEP_PMON_RAW_EVENT_MASK (SNBEP_PMON_CTL_EV_SEL_MASK | \ + SNBEP_PMON_CTL_UMASK_MASK | \ + SNBEP_PMON_CTL_EDGE_DET | \ + SNBEP_PMON_CTL_INVERT | \ + SNBEP_PMON_CTL_TRESH_MASK) + +/* SNB-EP Ubox event control */ +#define SNBEP_U_MSR_PMON_CTL_TRESH_MASK 0x1f000000 +#define SNBEP_U_MSR_PMON_RAW_EVENT_MASK \ + (SNBEP_PMON_CTL_EV_SEL_MASK | \ + SNBEP_PMON_CTL_UMASK_MASK | \ + SNBEP_PMON_CTL_EDGE_DET | \ + SNBEP_PMON_CTL_INVERT | \ + SNBEP_U_MSR_PMON_CTL_TRESH_MASK) + +/* SNB-EP PCU event control */ +#define SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK 0x0000c000 +#define SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK 0x1f000000 +#define SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT (1 << 30) +#define SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET (1 << 31) +#define SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK \ + (SNBEP_PMON_CTL_EV_SEL_MASK | \ + SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \ + SNBEP_PMON_CTL_EDGE_DET | \ + SNBEP_PMON_CTL_INVERT | \ + SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \ + SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \ + SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET) + +/* SNB-EP pci control register */ +#define SNBEP_PCI_PMON_BOX_CTL 0xf4 +#define SNBEP_PCI_PMON_CTL0 0xd8 +/* SNB-EP pci counter register */ +#define SNBEP_PCI_PMON_CTR0 0xa0 + +/* SNB-EP home agent register */ +#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH0 0x40 +#define SNBEP_HA_PCI_PMON_BOX_ADDRMATCH1 0x44 +#define SNBEP_HA_PCI_PMON_BOX_OPCODEMATCH 0x48 +/* SNB-EP memory controller register */ +#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTL 0xf0 +#define SNBEP_MC_CHy_PCI_PMON_FIXED_CTR 0xd0 +/* SNB-EP QPI register */ +#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH0 0x228 +#define SNBEP_Q_Py_PCI_PMON_PKT_MATCH1 0x22c +#define SNBEP_Q_Py_PCI_PMON_PKT_MASK0 0x238 +#define SNBEP_Q_Py_PCI_PMON_PKT_MASK1 0x23c + +/* SNB-EP Ubox register */ +#define SNBEP_U_MSR_PMON_CTR0 0xc16 +#define SNBEP_U_MSR_PMON_CTL0 0xc10 + +#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTL 0xc08 +#define SNBEP_U_MSR_PMON_UCLK_FIXED_CTR 0xc09 + +/* SNB-EP Cbo register */ +#define SNBEP_C0_MSR_PMON_CTR0 0xd16 +#define SNBEP_C0_MSR_PMON_CTL0 0xd10 +#define SNBEP_C0_MSR_PMON_BOX_FILTER 0xd14 +#define SNBEP_C0_MSR_PMON_BOX_CTL 0xd04 +#define SNBEP_CBO_MSR_OFFSET 0x20 + +/* SNB-EP PCU register */ +#define SNBEP_PCU_MSR_PMON_CTR0 0xc36 +#define SNBEP_PCU_MSR_PMON_CTL0 0xc30 +#define SNBEP_PCU_MSR_PMON_BOX_FILTER 0xc34 +#define SNBEP_PCU_MSR_PMON_BOX_CTL 0xc24 +#define SNBEP_PCU_MSR_CORE_C3_CTR 0x3fc +#define SNBEP_PCU_MSR_CORE_C6_CTR 0x3fd struct intel_uncore_ops; struct intel_uncore_pmu;include/linux/pci_ids.h +11
-1@@ -2756,6 +2756,17 @@ #define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27 #define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e #define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f +#define PCI_DEVICE_ID_INTEL_UNC_HA 0x3c46 +#define PCI_DEVICE_ID_INTEL_UNC_IMC0 0x3cb0 +#define PCI_DEVICE_ID_INTEL_UNC_IMC1 0x3cb1 +#define PCI_DEVICE_ID_INTEL_UNC_IMC2 0x3cb4 +#define PCI_DEVICE_ID_INTEL_UNC_IMC3 0x3cb5 +#define PCI_DEVICE_ID_INTEL_UNC_QPI0 0x3c41 +#define PCI_DEVICE_ID_INTEL_UNC_QPI1 0x3c42 +#define PCI_DEVICE_ID_INTEL_UNC_R2PCIE 0x3c43 +#define PCI_DEVICE_ID_INTEL_UNC_R3QPI0 0x3c44 +#define PCI_DEVICE_ID_INTEL_UNC_R3QPI1 0x3c45 +#define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX 0x3ce0 #define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f #define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 #define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 --1.7.6.5
Re: [PATCH V6 08/13] perf: Add Sandy Bridge-EP uncore support
Quoted 21 lines · Stephane Eranian
Quoted 7 lines · Zheng
Quoted 7 lines
From: "Yan, Zheng" <[email protected]>
Add Intel Nehalem and Sandy Bridge uncore pmu support. The uncore subsystem in Sandy Bridge-EP consists of 8 components (Ubox, Cacheing Agent, Home Agent, Memory controller, Power Control, QPI Link Layer, R2PCIe, R3QPI).
I did not find in this patch the support for the C-Box Filter register (
SNBEP_C0_MSR_PMON_BOX_FILTER). Based on the description
in the manual, looks like a valuable filter to support, especially for the core/thread filtering capability.There is only one such filter per box, and it can be used by any events. So looks like we have another
offcore_respstyle register to manage here. Need to ensure the value of that filter is shared by all 4 counters. If you were to support that, you'd have to enable the tid filter on the CBox config regs and export that via sysfs. Also I assume you'd pass the value of that filter either in config1 or in the upper 32 bits of the config reg.
Quoted 2 lines
What's your take on that?
I'm working on uncore support for Nehalem-EX which has extensive use of shared extra registers. Once that work done, adding C-Box filter support should be easy.
Regards
Yan, Zheng
Re: [PATCH V6 08/13] perf: Add Sandy Bridge-EP uncore support
Quoted 22 lines · Zheng
Quoted 21 lines · Stephane Eranian
Quoted 7 lines · Zheng
Quoted 7 lines
From: "Yan, Zheng" <[email protected]>
Add Intel Nehalem and Sandy Bridge uncore pmu support. The uncore subsystem in Sandy Bridge-EP consists of 8 components (Ubox, Cacheing Agent, Home Agent, Memory controller, Power Control, QPI Link Layer, R2PCIe, R3QPI).
I did not find in this patch the support for the C-Box Filter register (
SNBEP_C0_MSR_PMON_BOX_FILTER). Based on the description
in the manual, looks like a valuable filter to support, especially for the core/thread filtering capability.There is only one such filter per box, and it can be used by any events. So looks like we have another
offcore_respstyle register to manage here. Need to ensure the value of that filter is shared by all 4 counters. If you were to support that, you'd have to enable the tid filter on the CBox config regs and export that via sysfs. Also I assume you'd pass the value of that filter either in config1 or in the upper 32 bits of the config reg.
Quoted 7 lines
Quoted 2 lines
What's your take on that?
I'm working on uncore support for Nehalem-EX which has extensive use of shared extra registers. Once that work done, adding C-Box filter support should be easy.
Ok. Note that the code logic to handle shared regs is already there and is used for OFFCORE_RSP*, LBR_SELECT and LD_LAT (soon). Would be nice to reuse that framework for this as well. Though I understand you're looking at per box sharing as opposed to per physical core sharing or cross HT sharing.
Quoted 5 lines
Regards
Yan, Zheng
Re: [PATCH V6 08/13] perf: Add Sandy Bridge-EP uncore support
Quoted 30 lines · Stephane Eranian
Quoted 22 lines · Zheng
Quoted 21 lines · Stephane Eranian
Quoted 7 lines · Zheng
Quoted 7 lines
From: "Yan, Zheng" <[email protected]>
Add Intel Nehalem and Sandy Bridge uncore pmu support. The uncore subsystem in Sandy Bridge-EP consists of 8 components (Ubox, Cacheing Agent, Home Agent, Memory controller, Power Control, QPI Link Layer, R2PCIe, R3QPI).
I did not find in this patch the support for the C-Box Filter register (
SNBEP_C0_MSR_PMON_BOX_FILTER). Based on the description
in the manual, looks like a valuable filter to support, especially for the core/thread filtering capability.There is only one such filter per box, and it can be used by any events. So looks like we have another
offcore_respstyle register to manage here. Need to ensure the value of that filter is shared by all 4 counters. If you were to support that, you'd have to enable the tid filter on the CBox config regs and export that via sysfs. Also I assume you'd pass the value of that filter either in config1 or in the upper 32 bits of the config reg.Quoted 7 lines
Quoted 2 lines
What's your take on that?
I'm working on uncore support for Nehalem-EX which has extensive use of shared extra registers. Once that work done, adding C-Box filter support should be easy.
Quoted 6 lines
Ok. Note that the code logic to handle shared regs is already there and is used for OFFCORE_RSP*,
LBR_SELECTandLD_LAT(soon). Would be nice to reuse that framework for this as well. Though I understand you're looking at per box sharing as opposed to per physical core sharing or cross HT sharing.
The use of shared extra registers in Nehalem-EX uncore is more complex. Some events require programming two extra registers. Some extra registers have several fields, each field is for different event. I don't think I can reuse that framework.
Regards
Yan, Zheng
[tip:perf/core] perf/x86: Add Intel Nehalem and Sandy Bridge-EP uncore support
In reply to Yan, ZhengCommit-ID: 7c94ee2e0917b2ea56498bff939c8aa55da27207 Gitweb: http://git.kernel.org/tip/7c94ee2e0917b2ea56498bff939c8aa55da27207 Author: Yan, Zheng <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:37 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:23 +0200
perf/x86: Add Intel Nehalem and Sandy Bridge-EP uncore support
The uncore subsystem in Sandy Bridge-EP consists of 8 components:
Ubox, Cacheing Agent, Home Agent, Memory controller, Power Control, QPI Link Layer, R2PCIe, R3QPI.
--- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 484 +++++++++++++++++++++++++ arch/x86/kernel/cpu/perf_event_intel_uncore.h | 86 +++++ include/linux/pci_ids.h | 11 + 3 files changed, 581 insertions(+), 0 deletions(-)
arch/x86/kernel/cpu/perf_event_intel_uncore.c +484 -0
@@ -21,6 +21,482 @@ DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");DEFINE_UNCORE_FORMAT_ATTR (inv, inv,"config:23" );DEFINE_UNCORE_FORMAT_ATTR (cmask5, cmask,"config:24-28" );DEFINE_UNCORE_FORMAT_ATTR (cmask8, cmask,"config:24-31" ); +DEFINE_UNCORE_FORMAT_ATTR (thresh8, thresh,"config:24-31" ); +DEFINE_UNCORE_FORMAT_ATTR (thresh5, thresh,"config:24-28" ); +DEFINE_UNCORE_FORMAT_ATTR (occ_sel, occ_sel,"config:14-15" ); +DEFINE_UNCORE_FORMAT_ATTR (occ_invert, occ_invert,"config:30" ); +DEFINE_UNCORE_FORMAT_ATTR (occ_edge, occ_edge,"config:14-51" ); + +/* Sandy Bridge-EP uncore support */ +static void snbep_uncore_pci_disable_box (struct intel_uncore_box *box) +{ +struct pci_dev *pdev = box->pci_dev; +int box_ctl =uncore_pci_box_ctl (box); +u32 config; + +pci_read_config_dword (pdev, box_ctl, &config); + config |=SNBEP_PMON_BOX_CTL_FRZ ; +pci_write_config_dword (pdev, box_ctl, config); +} + +static void snbep_uncore_pci_enable_box (struct intel_uncore_box *box) +{ +struct pci_dev *pdev = box->pci_dev; +int box_ctl =uncore_pci_box_ctl (box); +u32 config; + +pci_read_config_dword (pdev, box_ctl, &config); + config &= ~SNBEP_PMON_BOX_CTL_FRZ ; +pci_write_config_dword (pdev, box_ctl, config); +} + +static void snbep_uncore_pci_enable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct pci_dev *pdev = box->pci_dev; +struct hw_perf_event *hwc = &event->hw; + +pci_write_config_dword (pdev, hwc->config_base, hwc->config | +SNBEP_PMON_CTL_EN ); +} + +static void snbep_uncore_pci_disable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct pci_dev *pdev = box->pci_dev; +struct hw_perf_event *hwc = &event->hw; + +pci_write_config_dword (pdev, hwc->config_base, hwc->config); +} + +static u64 snbep_uncore_pci_read_counter (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct pci_dev *pdev = box->pci_dev; +struct hw_perf_event *hwc = &event->hw; +u64 count; + +pci_read_config_dword (pdev, hwc->event_base, (u32 *)&count); +pci_read_config_dword (pdev, hwc->event_base +4 , (u32 *)&count +1 ); +return count; +} + +static void snbep_uncore_pci_init_box (struct intel_uncore_box *box) +{ +struct pci_dev *pdev = box->pci_dev; +pci_write_config_dword (pdev,SNBEP_PCI_PMON_BOX_CTL , +SNBEP_PMON_BOX_CTL_INT ); +} + +static void snbep_uncore_msr_disable_box (struct intel_uncore_box *box) +{ +u64 config; +unsigned msr; + + msr =uncore_msr_box_ctl (box); +if (msr) { +rdmsrl (msr, config); + config |=SNBEP_PMON_BOX_CTL_FRZ ; +wrmsrl (msr, config); +return ; + } +} + +static void snbep_uncore_msr_enable_box (struct intel_uncore_box *box) +{ +u64 config; +unsigned msr; + + msr =uncore_msr_box_ctl (box); +if (msr) { +rdmsrl (msr, config); + config &= ~SNBEP_PMON_BOX_CTL_FRZ ; +wrmsrl (msr, config); +return ; + } +} + +static void snbep_uncore_msr_enable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +wrmsrl (hwc->config_base, hwc->config |SNBEP_PMON_CTL_EN ); +} + +static void snbep_uncore_msr_disable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +wrmsrl (hwc->config_base, hwc->config); +} + +static u64 snbep_uncore_msr_read_counter (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; +u64 count; + +rdmsrl (hwc->event_base, count); +return count; +} + +static void snbep_uncore_msr_init_box (struct intel_uncore_box *box) +{ +unsigned msr =uncore_msr_box_ctl (box); +if (msr) +wrmsrl (msr,SNBEP_PMON_BOX_CTL_INT ); +} + +static struct attribute *snbep_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh8.attr, +NULL , +}; + +static struct attribute *snbep_uncore_ubox_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh5.attr, +NULL , +}; + +static struct attribute *snbep_uncore_pcu_formats_attr[] = { + &format_attr_event.attr, + &format_attr_occ_sel.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh5.attr, + &format_attr_occ_invert.attr, + &format_attr_occ_edge.attr, +NULL , +}; + +static struct uncore_event_desc snbep_uncore_imc_events[] = { +INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"config=0xffff" ), +/* read */ +INTEL_UNCORE_EVENT_DESC (CAS_COUNT_RD ,"event=0x4,umask=0x3" ), +/* write */ +INTEL_UNCORE_EVENT_DESC (CAS_COUNT_WR ,"event=0x4,umask=0xc" ), + {/* end: all zeroes */ }, +}; + +static struct uncore_event_desc snbep_uncore_qpi_events[] = { +INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"event=0x14" ), +/* outgoing data+nondata flits */ +INTEL_UNCORE_EVENT_DESC (TxL_FLITS_ACTIVE,"event=0x0,umask=0x6" ), +/* DRS data received */ +INTEL_UNCORE_EVENT_DESC (DRS_DATA ,"event=0x2,umask=0x8" ), +/* NCB data received */ +INTEL_UNCORE_EVENT_DESC (NCB_DATA ,"event=0x3,umask=0x4" ), + {/* end: all zeroes */ }, +}; + +static struct attribute_group snbep_uncore_format_group = { + .name ="format" , + .attrs = snbep_uncore_formats_attr, +}; + +static struct attribute_group snbep_uncore_ubox_format_group = { + .name ="format" , + .attrs = snbep_uncore_ubox_formats_attr, +}; + +static struct attribute_group snbep_uncore_pcu_format_group = { + .name ="format" , + .attrs = snbep_uncore_pcu_formats_attr, +}; + +static struct intel_uncore_ops snbep_uncore_msr_ops = { + .init_box = snbep_uncore_msr_init_box, + .disable_box = snbep_uncore_msr_disable_box, + .enable_box = snbep_uncore_msr_enable_box, + .disable_event = snbep_uncore_msr_disable_event, + .enable_event = snbep_uncore_msr_enable_event, + .read_counter = snbep_uncore_msr_read_counter, +}; + +static struct intel_uncore_ops snbep_uncore_pci_ops = { + .init_box = snbep_uncore_pci_init_box, + .disable_box = snbep_uncore_pci_disable_box, + .enable_box = snbep_uncore_pci_enable_box, + .disable_event = snbep_uncore_pci_disable_event, + .enable_event = snbep_uncore_pci_enable_event, + .read_counter = snbep_uncore_pci_read_counter, +}; + +static struct event_constraint snbep_uncore_cbox_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x01 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x02 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x04 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x05 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x07 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x11 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x12 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x13 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x1b ,0xc ), +UNCORE_EVENT_CONSTRAINT (0x1c ,0xc ), +UNCORE_EVENT_CONSTRAINT (0x1d ,0xc ), +UNCORE_EVENT_CONSTRAINT (0x1e ,0xc ), +UNCORE_EVENT_CONSTRAINT (0x1f ,0xe ), +UNCORE_EVENT_CONSTRAINT (0x21 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x23 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x31 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x32 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x33 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x34 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x35 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x36 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x37 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x38 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x39 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x3b ,0x1 ), +EVENT_CONSTRAINT_END +}; + +static struct event_constraint snbep_uncore_r2pcie_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x10 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x11 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x12 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x23 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x24 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x25 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x26 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x32 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x33 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x34 ,0x3 ), +EVENT_CONSTRAINT_END +}; + +static struct event_constraint snbep_uncore_r3qpi_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x10 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x11 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x12 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x13 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x20 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x21 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x22 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x23 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x24 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x25 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x26 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x30 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x31 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x32 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x33 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x34 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x36 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x37 ,0x3 ), +EVENT_CONSTRAINT_END +}; + +static struct intel_uncore_type snbep_uncore_ubox = { + .name ="ubox" , + .num_counters =2 , + .num_boxes =1 , + .perf_ctr_bits =44 , + .fixed_ctr_bits =48 , + .perf_ctr =SNBEP_U_MSR_PMON_CTR0 , + .event_ctl =SNBEP_U_MSR_PMON_CTL0 , + .event_mask =SNBEP_U_MSR_PMON_RAW_EVENT_MASK , + .fixed_ctr =SNBEP_U_MSR_PMON_UCLK_FIXED_CTR , + .fixed_ctl =SNBEP_U_MSR_PMON_UCLK_FIXED_CTL , + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_ubox_format_group, +}; + +static struct intel_uncore_type snbep_uncore_cbox = { + .name ="cbox" , + .num_counters =4 , + .num_boxes =8 , + .perf_ctr_bits =44 , + .event_ctl =SNBEP_C0_MSR_PMON_CTL0 , + .perf_ctr =SNBEP_C0_MSR_PMON_CTR0 , + .event_mask =SNBEP_PMON_RAW_EVENT_MASK , + .box_ctl =SNBEP_C0_MSR_PMON_BOX_CTL , + .msr_offset =SNBEP_CBO_MSR_OFFSET , + .constraints = snbep_uncore_cbox_constraints, + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_format_group, +}; + +static struct intel_uncore_type snbep_uncore_pcu = { + .name ="pcu" , + .num_counters =4 , + .num_boxes =1 , + .perf_ctr_bits =48 , + .perf_ctr =SNBEP_PCU_MSR_PMON_CTR0 , + .event_ctl =SNBEP_PCU_MSR_PMON_CTL0 , + .event_mask =SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK , + .box_ctl =SNBEP_PCU_MSR_PMON_BOX_CTL , + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_pcu_format_group, +}; + +static struct intel_uncore_type *snbep_msr_uncores[] = { + &snbep_uncore_ubox, + &snbep_uncore_cbox, + &snbep_uncore_pcu, +NULL , +}; + +#define SNBEP_UNCORE_PCI_COMMON_INIT () \ + .perf_ctr = SNBEP_PCI_PMON_CTR0, \ + .event_ctl = SNBEP_PCI_PMON_CTL0, \ + .event_mask = SNBEP_PMON_RAW_EVENT_MASK, \ + .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \ + .ops = &snbep_uncore_pci_ops, \ + .format_group = &snbep_uncore_format_group + +static struct intel_uncore_type snbep_uncore_ha = { + .name ="ha" , + .num_counters =4 , + .num_boxes =1 , + .perf_ctr_bits =48 , +SNBEP_UNCORE_PCI_COMMON_INIT (), +}; + +static struct intel_uncore_type snbep_uncore_imc = { + .name ="imc" , + .num_counters =4 , + .num_boxes =4 , + .perf_ctr_bits =48 , + .fixed_ctr_bits =48 , + .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, + .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, + .event_descs = snbep_uncore_imc_events, +SNBEP_UNCORE_PCI_COMMON_INIT (), +}; + +static struct intel_uncore_type snbep_uncore_qpi = { + .name ="qpi" , + .num_counters =4 , + .num_boxes =2 , + .perf_ctr_bits =48 , + .event_descs = snbep_uncore_qpi_events, +SNBEP_UNCORE_PCI_COMMON_INIT (), +}; + + +static struct intel_uncore_type snbep_uncore_r2pcie = { + .name ="r2pcie" , + .num_counters =4 , + .num_boxes =1 , + .perf_ctr_bits =44 , + .constraints = snbep_uncore_r2pcie_constraints, +SNBEP_UNCORE_PCI_COMMON_INIT (), +}; + +static struct intel_uncore_type snbep_uncore_r3qpi = { + .name ="r3qpi" , + .num_counters =3 , + .num_boxes =2 , + .perf_ctr_bits =44 , + .constraints = snbep_uncore_r3qpi_constraints, +SNBEP_UNCORE_PCI_COMMON_INIT (), +}; + +static struct intel_uncore_type *snbep_pci_uncores[] = { + &snbep_uncore_ha, + &snbep_uncore_imc, + &snbep_uncore_qpi, + &snbep_uncore_r2pcie, + &snbep_uncore_r3qpi, +NULL , +}; + +static DEFINE_PCI_DEVICE_TABLE (snbep_uncore_pci_ids) = { + {/* Home Agent */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_HA ), + .driver_data = (unsigned long )&snbep_uncore_ha, + }, + {/* MC Channel 0 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_IMC0 ), + .driver_data = (unsigned long )&snbep_uncore_imc, + }, + {/* MC Channel 1 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_IMC1 ), + .driver_data = (unsigned long )&snbep_uncore_imc, + }, + {/* MC Channel 2 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_IMC2 ), + .driver_data = (unsigned long )&snbep_uncore_imc, + }, + {/* MC Channel 3 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_IMC3 ), + .driver_data = (unsigned long )&snbep_uncore_imc, + }, + {/* QPI Port 0 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_QPI0 ), + .driver_data = (unsigned long )&snbep_uncore_qpi, + }, + {/* QPI Port 1 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_QPI1 ), + .driver_data = (unsigned long )&snbep_uncore_qpi, + }, + {/* P2PCIe */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_R2PCIE ), + .driver_data = (unsigned long )&snbep_uncore_r2pcie, + }, + {/* R3QPI Link 0 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_R3QPI0 ), + .driver_data = (unsigned long )&snbep_uncore_r3qpi, + }, + {/* R3QPI Link 1 */ +PCI_DEVICE (PCI_VENDOR_ID_INTEL ,PCI_DEVICE_ID_INTEL_UNC_R3QPI1 ), + .driver_data = (unsigned long )&snbep_uncore_r3qpi, + }, + {/* end: all zeroes */ } +}; + +static struct pci_driver snbep_uncore_pci_driver = { + .name ="snbep_uncore" , + .id_table = snbep_uncore_pci_ids, +}; + +/* +* build pci bus to socket mapping +*/ +static void snbep_pci2phy_map_init (void ) +{ +struct pci_dev *ubox_dev =NULL ; +int i, bus, nodeid; +u32 config; + +while (1 ) { +/* find the UBOX device */ + ubox_dev =pci_get_device (PCI_VENDOR_ID_INTEL , +PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX , + ubox_dev); +if (!ubox_dev) +break ; + bus = ubox_dev->bus->number; +/* get the Node ID of the local register */ +pci_read_config_dword (ubox_dev,0x40 , &config); + nodeid = config; +/* get the Node ID mapping */ +pci_read_config_dword (ubox_dev,0x54 , &config); +/* +* every three bits in the Node ID mapping register maps +* to a particular node. +*/ +for (i =0 ; i <8 ; i++) { +if (nodeid == ((config >> (3 * i)) &0x7 )) { + pcibus_to_physid[bus] = i; +break ; + } + } + }; +return ; +} +/* end of Sandy Bridge-EP uncore support */ +/* Sandy Bridge uncore support */ static void snb_uncore_msr_enable_event(struct intel_uncore_box *box,
@@ -894,6 +1370,11 @@ static int __init uncore_pci_init(void)int ret;switch (boot_cpu_data.x86_model) { +case 45 :/* Sandy Bridge-EP */ + pci_uncores = snbep_pci_uncores; + uncore_pci_driver = &snbep_uncore_pci_driver; +snbep_pci2phy_map_init (); +break ;default :return 0 ; }
@@ -1155,6 +1636,9 @@ static int __init uncore_cpu_init(void)case 42 :/* Sandy Bridge */ msr_uncores = snb_msr_uncores;break ; +case 45 :/* Sandy Birdge-EP */ + msr_uncores = snbep_msr_uncores; +break ;default :return 0 ; }
arch/x86/kernel/cpu/perf_event_intel_uncore.h +86 -0
92 lines not on this page · raw message
include/linux/pci_ids.h +11 -0
@@ -2755,6 +2755,17 @@#define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27#define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e#define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f +#define PCI_DEVICE_ID_INTEL_UNC_HA 0x3c46 +#define PCI_DEVICE_ID_INTEL_UNC_IMC0 0x3cb0 +#define PCI_DEVICE_ID_INTEL_UNC_IMC1 0x3cb1 +#define PCI_DEVICE_ID_INTEL_UNC_IMC2 0x3cb4 +#define PCI_DEVICE_ID_INTEL_UNC_IMC3 0x3cb5 +#define PCI_DEVICE_ID_INTEL_UNC_QPI0 0x3c41 +#define PCI_DEVICE_ID_INTEL_UNC_QPI1 0x3c42 +#define PCI_DEVICE_ID_INTEL_UNC_R2PCIE 0x3c43 +#define PCI_DEVICE_ID_INTEL_UNC_R3QPI0 0x3c44 +#define PCI_DEVICE_ID_INTEL_UNC_R3QPI1 0x3c45 +#define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX 0x3ce0#define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f#define PCI_DEVICE_ID_INTEL_5100_16 0x65f0#define PCI_DEVICE_ID_INTEL_5100_21 0x65f5
Re: [PATCH V6 08/13] perf: Add Sandy Bridge-EP uncore support
In reply to Yan, ZhengQuoted 375 lines · Zheng
From: "Yan, Zheng" <[email protected]>
Add Intel Nehalem and Sandy Bridge uncore pmu support. The uncore subsystem in Sandy Bridge-EP consists of 8 components (Ubox, Cacheing Agent, Home Agent, Memory controller, Power Control, QPI Link Layer, R2PCIe, R3QPI).
Signed-off-by Zheng Yan <[email protected]>--- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 484 +++++++++++++++++++++++++ arch/x86/kernel/cpu/perf_event_intel_uncore.h | 86 +++++ include/linux/pci_ids.h | 11 + 3 files changed, 581 insertions(+), 0 deletions(-)arch/x86/kernel/cpu/perf_event_intel_uncore.c +352
-0@@ -21,6 +21,482 @@ DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");DEFINE_UNCORE_FORMAT_ATTR (inv, inv,"config:23" );DEFINE_UNCORE_FORMAT_ATTR (cmask5, cmask,"config:24-28" );DEFINE_UNCORE_FORMAT_ATTR (cmask8, cmask,"config:24-31" ); +DEFINE_UNCORE_FORMAT_ATTR (thresh8, thresh,"config:24-31" ); +DEFINE_UNCORE_FORMAT_ATTR (thresh5, thresh,"config:24-28" ); +DEFINE_UNCORE_FORMAT_ATTR (occ_sel, occ_sel,"config:14-15" ); +DEFINE_UNCORE_FORMAT_ATTR (occ_invert, occ_invert,"config:30" ); +DEFINE_UNCORE_FORMAT_ATTR (occ_edge, occ_edge,"config:14-51" ); + +/* Sandy Bridge-EP uncore support */ +static void snbep_uncore_pci_disable_box (struct intel_uncore_box *box) +{ +struct pci_dev *pdev = box->pci_dev; +int box_ctl =uncore_pci_box_ctl (box); +u32 config; + +pci_read_config_dword (pdev, box_ctl, &config); + config |=SNBEP_PMON_BOX_CTL_FRZ ; +pci_write_config_dword (pdev, box_ctl, config); +} + +static void snbep_uncore_pci_enable_box (struct intel_uncore_box *box) +{ +struct pci_dev *pdev = box->pci_dev; +int box_ctl =uncore_pci_box_ctl (box); +u32 config; + +pci_read_config_dword (pdev, box_ctl, &config); + config &= ~SNBEP_PMON_BOX_CTL_FRZ ; +pci_write_config_dword (pdev, box_ctl, config); +} + +static void snbep_uncore_pci_enable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct pci_dev *pdev = box->pci_dev; +struct hw_perf_event *hwc = &event->hw; + +pci_write_config_dword (pdev, hwc->config_base, hwc->config | +SNBEP_PMON_CTL_EN ); +} + +static void snbep_uncore_pci_disable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct pci_dev *pdev = box->pci_dev; +struct hw_perf_event *hwc = &event->hw; + +pci_write_config_dword (pdev, hwc->config_base, hwc->config); +} + +static u64 snbep_uncore_pci_read_counter (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct pci_dev *pdev = box->pci_dev; +struct hw_perf_event *hwc = &event->hw; +u64 count; + +pci_read_config_dword (pdev, hwc->event_base, (u32 *)&count); +pci_read_config_dword (pdev, hwc->event_base +4 , (u32 *)&count +1 ); +return count; +} + +static void snbep_uncore_pci_init_box (struct intel_uncore_box *box) +{ +struct pci_dev *pdev = box->pci_dev; +pci_write_config_dword (pdev,SNBEP_PCI_PMON_BOX_CTL , +SNBEP_PMON_BOX_CTL_INT ); +} + +static void snbep_uncore_msr_disable_box (struct intel_uncore_box *box) +{ +u64 config; +unsigned msr; + + msr =uncore_msr_box_ctl (box); +if (msr) { +rdmsrl (msr, config); + config |=SNBEP_PMON_BOX_CTL_FRZ ; +wrmsrl (msr, config); +return ; + } +} + +static void snbep_uncore_msr_enable_box (struct intel_uncore_box *box) +{ +u64 config; +unsigned msr; + + msr =uncore_msr_box_ctl (box); +if (msr) { +rdmsrl (msr, config); + config &= ~SNBEP_PMON_BOX_CTL_FRZ ; +wrmsrl (msr, config); +return ; + } +} + +static void snbep_uncore_msr_enable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +wrmsrl (hwc->config_base, hwc->config |SNBEP_PMON_CTL_EN ); +} + +static void snbep_uncore_msr_disable_event (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; + +wrmsrl (hwc->config_base, hwc->config); +} + +static u64 snbep_uncore_msr_read_counter (struct intel_uncore_box *box, +struct perf_event *event) +{ +struct hw_perf_event *hwc = &event->hw; +u64 count; + +rdmsrl (hwc->event_base, count); +return count; +} + +static void snbep_uncore_msr_init_box (struct intel_uncore_box *box) +{ +unsigned msr =uncore_msr_box_ctl (box); +if (msr) +wrmsrl (msr,SNBEP_PMON_BOX_CTL_INT ); +} + +static struct attribute *snbep_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh8.attr, +NULL , +}; + +static struct attribute *snbep_uncore_ubox_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh5.attr, +NULL , +}; + +static struct attribute *snbep_uncore_pcu_formats_attr[] = { + &format_attr_event.attr, + &format_attr_occ_sel.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_thresh5.attr, + &format_attr_occ_invert.attr, + &format_attr_occ_edge.attr, +NULL , +}; + +static struct uncore_event_desc snbep_uncore_imc_events[] = { +INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"config=0xffff" ), +/* read */ +INTEL_UNCORE_EVENT_DESC (CAS_COUNT_RD ,"event=0x4,umask=0x3" ), +/* write */ +INTEL_UNCORE_EVENT_DESC (CAS_COUNT_WR ,"event=0x4,umask=0xc" ), + {/* end: all zeroes */ }, +}; + +static struct uncore_event_desc snbep_uncore_qpi_events[] = { +INTEL_UNCORE_EVENT_DESC (CLOCKTICKS ,"event=0x14" ), +/* outgoing data+nondata flits */ +INTEL_UNCORE_EVENT_DESC (TxL_FLITS_ACTIVE,"event=0x0,umask=0x6" ), +/* DRS data received */ +INTEL_UNCORE_EVENT_DESC (DRS_DATA ,"event=0x2,umask=0x8" ), +/* NCB data received */ +INTEL_UNCORE_EVENT_DESC (NCB_DATA ,"event=0x3,umask=0x4" ), + {/* end: all zeroes */ }, +}; + +static struct attribute_group snbep_uncore_format_group = { + .name ="format" , + .attrs = snbep_uncore_formats_attr, +}; + +static struct attribute_group snbep_uncore_ubox_format_group = { + .name ="format" , + .attrs = snbep_uncore_ubox_formats_attr, +}; + +static struct attribute_group snbep_uncore_pcu_format_group = { + .name ="format" , + .attrs = snbep_uncore_pcu_formats_attr, +}; + +static struct intel_uncore_ops snbep_uncore_msr_ops = { + .init_box = snbep_uncore_msr_init_box, + .disable_box = snbep_uncore_msr_disable_box, + .enable_box = snbep_uncore_msr_enable_box, + .disable_event = snbep_uncore_msr_disable_event, + .enable_event = snbep_uncore_msr_enable_event, + .read_counter = snbep_uncore_msr_read_counter, +}; + +static struct intel_uncore_ops snbep_uncore_pci_ops = { + .init_box = snbep_uncore_pci_init_box, + .disable_box = snbep_uncore_pci_disable_box, + .enable_box = snbep_uncore_pci_enable_box, + .disable_event = snbep_uncore_pci_disable_event, + .enable_event = snbep_uncore_pci_enable_event, + .read_counter = snbep_uncore_pci_read_counter, +}; + +static struct event_constraint snbep_uncore_cbo_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x01 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x02 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x04 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x05 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x07 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x11 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x12 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x13 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x1b ,0xc ), +UNCORE_EVENT_CONSTRAINT (0x1c ,0xc ), +UNCORE_EVENT_CONSTRAINT (0x1d ,0xc ), +UNCORE_EVENT_CONSTRAINT (0x1e ,0xc ), +UNCORE_EVENT_CONSTRAINT (0x1f ,0xe ), +UNCORE_EVENT_CONSTRAINT (0x21 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x23 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x31 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x32 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x33 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x34 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x35 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x36 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x37 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x38 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x39 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x3b ,0x1 ), +EVENT_CONSTRAINT_END +}; + +static struct event_constraint snbep_uncore_r2pcie_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x10 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x11 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x12 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x23 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x24 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x25 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x26 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x32 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x33 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x34 ,0x3 ), +EVENT_CONSTRAINT_END +}; + +static struct event_constraint snbep_uncore_r3qpi_constraints[] = { +UNCORE_EVENT_CONSTRAINT (0x10 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x11 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x12 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x13 ,0x1 ), +UNCORE_EVENT_CONSTRAINT (0x20 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x21 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x22 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x23 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x24 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x25 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x26 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x30 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x31 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x32 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x33 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x34 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x36 ,0x3 ), +UNCORE_EVENT_CONSTRAINT (0x37 ,0x3 ), +EVENT_CONSTRAINT_END +}; + +static struct intel_uncore_type snbep_uncore_ubox = { + .name ="ubox" , + .num_counters =2 , + .num_boxes =1 , + .perf_ctr_bits =44 , + .fixed_ctr_bits =48 , + .perf_ctr =SNBEP_U_MSR_PMON_CTR0 , + .event_ctl =SNBEP_U_MSR_PMON_CTL0 , + .event_mask =SNBEP_U_MSR_PMON_RAW_EVENT_MASK , + .fixed_ctr =SNBEP_U_MSR_PMON_UCLK_FIXED_CTR , + .fixed_ctl =SNBEP_U_MSR_PMON_UCLK_FIXED_CTL , + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_ubox_format_group, +}; + +static struct intel_uncore_type snbep_uncore_cbo = { + .name ="cbo" , + .num_counters =4 , + .num_boxes =8 , + .perf_ctr_bits =44 , + .event_ctl =SNBEP_C0_MSR_PMON_CTL0 , + .perf_ctr =SNBEP_C0_MSR_PMON_CTR0 , + .event_mask =SNBEP_PMON_RAW_EVENT_MASK , + .box_ctl =SNBEP_C0_MSR_PMON_BOX_CTL , + .msr_offset =SNBEP_CBO_MSR_OFFSET , + .constraints = snbep_uncore_cbo_constraints, + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_format_group, +}; + +static struct intel_uncore_type snbep_uncore_pcu = { + .name ="pcu" , + .num_counters =4 , + .num_boxes =1 , + .perf_ctr_bits =48 , + .perf_ctr =SNBEP_PCU_MSR_PMON_CTR0 , + .event_ctl =SNBEP_PCU_MSR_PMON_CTL0 , + .event_mask =SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK , + .box_ctl =SNBEP_PCU_MSR_PMON_BOX_CTL , + .ops = &snbep_uncore_msr_ops, + .format_group = &snbep_uncore_pcu_format_group, +}; + +static struct intel_uncore_type *snbep_msr_uncores[] = { + &snbep_uncore_ubox, + &snbep_uncore_cbo, + &snbep_uncore_pcu, +NULL , +}; + +#define SNBEP_UNCORE_PCI_COMMON_INIT () \ + .perf_ctr = SNBEP_PCI_PMON_CTR0, \ + .event_ctl = SNBEP_PCI_PMON_CTL0, \ + .event_mask = SNBEP_PMON_RAW_EVENT_MASK, \ + .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \ + .ops = &snbep_uncore_pci_ops, \ + .format_group = &snbep_uncore_format_group + +static struct intel_uncore_type snbep_uncore_ha = { + .name ="ha" , + .num_counters =4 , + .num_boxes =1 , + .perf_ctr_bits =48 , +SNBEP_UNCORE_PCI_COMMON_INIT (), +}; + +static struct intel_uncore_type snbep_uncore_imc = { + .name ="imc" , + .num_counters =4 , + .num_boxes =4 , + .perf_ctr_bits =48 , + .fixed_ctr_bits =48 , + .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR, + .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL, + .event_descs = snbep_uncore_imc_events, +SNBEP_UNCORE_PCI_COMMON_INIT (), +};
arch/x86/kernel/cpu/perf_event_intel_uncore.c DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); · line 385
Quoted 10 lines
arch/x86/kernel/cpu/perf_event_intel_uncore.c +10
-0+ +static struct intel_uncore_type snbep_uncore_qpi = { + .name ="qpi" , + .num_counters =4 , + .num_boxes =2 , + .perf_ctr_bits =48 , + .event_descs = snbep_uncore_qpi_events, +SNBEP_UNCORE_PCI_COMMON_INIT (), +}; +
No.
The event_mask field for QPI cannot be the default one.
The event_sel field has a one bit extension at bit position 21. You don't want to mask it. It is needed for a bunch of QPI events. In fact, I believe it is required as it is an extension of the event code.
PATCH v6 9/13 perf, tool: Use data struct for arg passing in event parse function
In reply to Yan, ZhengFrom: Jiri Olsa <[email protected]>
Moving all the bison arguments into the structure. In upcomming patches we are going to
- add more arguments
- reuse the grammer for term parsing
so it's more clear to pack/separate related arguments.
--- tools/perf/util/parse-events.c | 16 +++++++----- tools/perf/util/parse-events.h | 8 ++++- tools/perf/util/parse-events.y | 52 +++++++++++++++++++++++++++------------- 3 files changed, 50 insertions(+), 26 deletions(-)
tools/perf/util/parse-events.c +9 -7
@@ -26,7 +26,7 @@ struct event_symbol {#ifdef PARSER_DEBUG extern int parse_events_debug;#endif -int parse_events_parse (struct list_head *list,int *idx); +int parse_events_parse (void *data);#define CHW (x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x#define CSW (x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -789,25 +789,27 @@ int parse_events_modifier(struct list_head *list, char *str)int parse_events (struct perf_evlist *evlist,const char *str,int unset__used ) { -LIST_HEAD (list); -LIST_HEAD (list_tmp); +struct parse_events_data__events data = { + .list =LIST_HEAD_INIT (data.list), + .idx = evlist->nr_entries, + };YY_BUFFER_STATE buffer; -int ret, idx = evlist->nr_entries; +int ret; buffer =parse_events__scan_string (str);#ifdef PARSER_DEBUG parse_events_debug =1 ;#endif - ret =parse_events_parse (&list, &idx); + ret =parse_events_parse (&data);parse_events__flush_buffer (buffer);parse_events__delete_buffer (buffer);parse_events_lex_destroy ();if (!ret) { -int entries = idx - evlist->nr_entries; -perf_evlist__splice_list_tail (evlist, &list, entries); +int entries = data.idx - evlist->nr_entries; +perf_evlist__splice_list_tail (evlist, &data.list, entries);return 0 ; }
tools/perf/util/parse-events.h +6 -2
@@ -63,6 +63,11 @@ struct parse_events__term {struct list_head list; }; +struct parse_events_data__events { +struct list_head list; +int idx; +}; +int parse_events__is_hardcoded_term (struct parse_events__term *term);int parse_events__term_num (struct parse_events__term **_term,int type_term,char *config,long num);
@@ -83,8 +88,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx, char *pmu , struct list_head *head_config);void parse_events_update_lists (struct list_head *list_event,struct list_head *list_all); -void parse_events_error (struct list_head *list_all, -int *idx,char const *msg); +void parse_events_error (void *data,char const *msg);int parse_events__test (void );void print_events (const char *event_glob);
tools/perf/util/parse-events.y +35 -17
168 lines not on this page · raw message
Signature · 1 line
1.7.6.5
[tip:perf/core] perf/tool: Use data struct for arg passing in event parse function
Commit-ID: 46010ab2607aed9484816a8f1679c2ec3c8e7dcf Gitweb: http://git.kernel.org/tip/46010ab2607aed9484816a8f1679c2ec3c8e7dcf Author: Jiri Olsa <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:38 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:24 +0200
perf/tool: Use data struct for arg passing in event parse function
Moving all the bison arguments into the structure. In upcomming patches we are going to:
- add more arguments
- reuse the grammer for term parsing
so it's more clear to pack/separate related arguments.
--- tools/perf/util/parse-events.c | 16 +++++++----- tools/perf/util/parse-events.h | 8 ++++- tools/perf/util/parse-events.y | 52 +++++++++++++++++++++++++++------------- 3 files changed, 50 insertions(+), 26 deletions(-)
tools/perf/util/parse-events.c +9 -7
@@ -26,7 +26,7 @@ struct event_symbol {#ifdef PARSER_DEBUG extern int parse_events_debug;#endif -int parse_events_parse (struct list_head *list,int *idx); +int parse_events_parse (void *data);#define CHW (x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x#define CSW (x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -789,25 +789,27 @@ int parse_events_modifier(struct list_head *list, char *str)int parse_events (struct perf_evlist *evlist,const char *str,int unset__used ) { -LIST_HEAD (list); -LIST_HEAD (list_tmp); +struct parse_events_data__events data = { + .list =LIST_HEAD_INIT (data.list), + .idx = evlist->nr_entries, + };YY_BUFFER_STATE buffer; -int ret, idx = evlist->nr_entries; +int ret; buffer =parse_events__scan_string (str);#ifdef PARSER_DEBUG parse_events_debug =1 ;#endif - ret =parse_events_parse (&list, &idx); + ret =parse_events_parse (&data);parse_events__flush_buffer (buffer);parse_events__delete_buffer (buffer);parse_events_lex_destroy ();if (!ret) { -int entries = idx - evlist->nr_entries; -perf_evlist__splice_list_tail (evlist, &list, entries); +int entries = data.idx - evlist->nr_entries; +perf_evlist__splice_list_tail (evlist, &data.list, entries);return 0 ; }
tools/perf/util/parse-events.h +6 -2
@@ -63,6 +63,11 @@ struct parse_events__term {struct list_head list; }; +struct parse_events_data__events { +struct list_head list; +int idx; +}; +int parse_events__is_hardcoded_term (struct parse_events__term *term);int parse_events__term_num (struct parse_events__term **_term,int type_term,char *config,long num);
@@ -83,8 +88,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx, char *pmu , struct list_head *head_config);void parse_events_update_lists (struct list_head *list_event,struct list_head *list_all); -void parse_events_error (struct list_head *list_all, -int *idx,char const *msg); +void parse_events_error (void *data,char const *msg);int parse_events__test (void );void print_events (const char *event_glob);
tools/perf/util/parse-events.y +35 -17
168 lines not on this page · raw message
PATCH v6 10/13 perf, tool: Make the event parser reentrantable
In reply to Yan, ZhengFrom: Jiri Olsa <[email protected]>
Making the event parser reentrantable by creating separate scanner for each parsing. The scanner is passed to the bison as and argument to the lexer.
--- tools/perf/util/parse-events.c | 35 ++++++++---- tools/perf/util/parse-events.h | 2 +- tools/perf/util/parse-events.l | 116 +++++++++++++++++++++++----------------- tools/perf/util/parse-events.y | 9 ++- 4 files changed, 98 insertions(+), 64 deletions(-)
tools/perf/util/parse-events.c +24 -11
@@ -11,6 +11,7 @@#include "cache.h" #include "header.h" #include "debugfs.h" +#include "parse-events-bison.h" #include "parse-events-flex.h" #include "pmu.h"
@@ -26,7 +27,7 @@ struct event_symbol {#ifdef PARSER_DEBUG extern int parse_events_debug;#endif -int parse_events_parse (void *data); +int parse_events_parse (void *data,void *scanner);#define CHW (x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x#define CSW (x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -787,26 +788,38 @@ int parse_events_modifier(struct list_head *list, char *str)return 0 ; } -int parse_events (struct perf_evlist *evlist,const char *str,int unset__used ) +static int parse_events__scanner (const char *str,void *data) { -struct parse_events_data__events data = { - .list =LIST_HEAD_INIT (data.list), - .idx = evlist->nr_entries, - };YY_BUFFER_STATE buffer; +void *scanner;int ret; - buffer =parse_events__scan_string (str); + ret =parse_events_lex_init (&scanner); +if (ret) +return ret; + + buffer =parse_events__scan_string (str, scanner);#ifdef PARSER_DEBUG parse_events_debug =1 ;#endif - ret =parse_events_parse (&data); + ret =parse_events_parse (data, scanner); + +parse_events__flush_buffer (buffer, scanner); +parse_events__delete_buffer (buffer, scanner); +parse_events_lex_destroy (scanner); +return ret; +} -parse_events__flush_buffer (buffer); -parse_events__delete_buffer (buffer); -parse_events_lex_destroy (); +int parse_events (struct perf_evlist *evlist,const char *str,int unset__used ) +{ +struct parse_events_data__events data = { + .list =LIST_HEAD_INIT (data.list), + .idx = evlist->nr_entries, + }; +int ret; + ret =parse_events__scanner (str, &data);if (!ret) {int entries = data.idx - evlist->nr_entries;perf_evlist__splice_list_tail (evlist, &data.list, entries);
tools/perf/util/parse-events.h +1 -1
@@ -88,7 +88,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx, char *pmu , struct list_head *head_config);void parse_events_update_lists (struct list_head *list_event,struct list_head *list_all); -void parse_events_error (void *data,char const *msg); +void parse_events_error (void *data,void *scanner,char const *msg);int parse_events__test (void );void print_events (const char *event_glob);
tools/perf/util/parse-events.l +67 -49
196 lines not on this page · raw message
tools/perf/util/parse-events.y +6 -3
@@ -1,6 +1,8 @@ - +%pure-parser %name-prefix "parse_events_" %parse-param {void *_data} +%parse-param {void *scanner} +%lex-param {void* scanner} %{
@@ -11,8 +13,9 @@ #include "types.h" #include "util.h" #include "parse-events.h" +#include "parse-events-bison.h" -extern int parse_events_lex (void); +extern int parse_events_lex (YYSTYPE* lvalp, void* scanner); #define ABORT_ON(val) \ do { \
@@ -286,7 +289,7 @@ sep_slash_dc: '/' | ':' | %% -void parse_events_error(void *data __used, +void parse_events_error(void *data __used, void *scanner __used, char const *msg __used) { }
Signature · 1 line
1.7.6.5
[tip:perf/core] perf/tool: Make the event parser re-entrant
Commit-ID: ac20de6fff445d6deb0c44c25946d198f79f2f00 Gitweb: http://git.kernel.org/tip/ac20de6fff445d6deb0c44c25946d198f79f2f00 Author: Zheng Yan <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:39 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:24 +0200
perf/tool: Make the event parser re-entrant
Make the event parser reentrant by creating separate scanner for each parsing. The scanner is passed to the bison as and argument to the lexer.
--- tools/perf/util/parse-events.c | 35 ++++++++---- tools/perf/util/parse-events.h | 2 +- tools/perf/util/parse-events.l | 116 +++++++++++++++++++++++----------------- tools/perf/util/parse-events.y | 9 ++- 4 files changed, 98 insertions(+), 64 deletions(-)
tools/perf/util/parse-events.c +24 -11
@@ -11,6 +11,7 @@#include "cache.h" #include "header.h" #include "debugfs.h" +#include "parse-events-bison.h" #include "parse-events-flex.h" #include "pmu.h"
@@ -26,7 +27,7 @@ struct event_symbol {#ifdef PARSER_DEBUG extern int parse_events_debug;#endif -int parse_events_parse (void *data); +int parse_events_parse (void *data,void *scanner);#define CHW (x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x#define CSW (x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -787,26 +788,38 @@ int parse_events_modifier(struct list_head *list, char *str)return 0 ; } -int parse_events (struct perf_evlist *evlist,const char *str,int unset__used ) +static int parse_events__scanner (const char *str,void *data) { -struct parse_events_data__events data = { - .list =LIST_HEAD_INIT (data.list), - .idx = evlist->nr_entries, - };YY_BUFFER_STATE buffer; +void *scanner;int ret; - buffer =parse_events__scan_string (str); + ret =parse_events_lex_init (&scanner); +if (ret) +return ret; + + buffer =parse_events__scan_string (str, scanner);#ifdef PARSER_DEBUG parse_events_debug =1 ;#endif - ret =parse_events_parse (&data); + ret =parse_events_parse (data, scanner); + +parse_events__flush_buffer (buffer, scanner); +parse_events__delete_buffer (buffer, scanner); +parse_events_lex_destroy (scanner); +return ret; +} -parse_events__flush_buffer (buffer); -parse_events__delete_buffer (buffer); -parse_events_lex_destroy (); +int parse_events (struct perf_evlist *evlist,const char *str,int unset__used ) +{ +struct parse_events_data__events data = { + .list =LIST_HEAD_INIT (data.list), + .idx = evlist->nr_entries, + }; +int ret; + ret =parse_events__scanner (str, &data);if (!ret) {int entries = data.idx - evlist->nr_entries;perf_evlist__splice_list_tail (evlist, &data.list, entries);
tools/perf/util/parse-events.h +1 -1
@@ -88,7 +88,7 @@ int parse_events_add_pmu(struct list_head **list, int *idx, char *pmu , struct list_head *head_config);void parse_events_update_lists (struct list_head *list_event,struct list_head *list_all); -void parse_events_error (void *data,char const *msg); +void parse_events_error (void *data,void *scanner,char const *msg);int parse_events__test (void );void print_events (const char *event_glob);
tools/perf/util/parse-events.l +67 -49
196 lines not on this page · raw message
tools/perf/util/parse-events.y +6 -3
@@ -1,6 +1,8 @@ - +%pure-parser %name-prefix "parse_events_" %parse-param {void *_data} +%parse-param {void *scanner} +%lex-param {void* scanner} %{
@@ -11,8 +13,9 @@ #include "types.h" #include "util.h" #include "parse-events.h" +#include "parse-events-bison.h" -extern int parse_events_lex (void); +extern int parse_events_lex (YYSTYPE* lvalp, void* scanner); #define ABORT_ON(val) \ do { \
@@ -286,7 +289,7 @@ sep_slash_dc: '/' | ':' | %% -void parse_events_error(void *data __used, +void parse_events_error(void *data __used, void *scanner __used, char const *msg __used) { }
PATCH v6 11/13 perf, tool: Add support to reuse event grammar to parse out terms
In reply to Yan, ZhengFrom: Jiri Olsa <[email protected]>
We want to reuse the event grammar for parsing aliased terms. The obvious reason is we dont need to add new code when there's already support for this in event grammar.
Doing this by adding terms and event start entries into event parse grammar. The grammar forks on the begining based on the starting token, which is supplied via bison interface into the lexer. The lexer then returns the starting token as the first token, thus making the grammar switch accordingly.
Currently 2 starting tokens/grammars are supported:
PE_START_TERMS, PE_START_EVENTS
The PE_START_TERMS related grammar uses 'event_config' part of the grammar for term parsing.
--- tools/perf/util/parse-events.c | 28 +++++++++++++++++++++++++--- tools/perf/util/parse-events.h | 5 +++++ tools/perf/util/parse-events.l | 13 +++++++++++++ tools/perf/util/parse-events.y | 12 ++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-)
tools/perf/util/parse-events.c +25 -3
@@ -12,6 +12,7 @@#include "header.h" #include "debugfs.h" #include "parse-events-bison.h" +#define YY_EXTRA_TYPE int#include "parse-events-flex.h" #include "pmu.h"
@@ -788,13 +789,13 @@ int parse_events_modifier(struct list_head *list, char *str)return 0 ; } -static int parse_events__scanner (const char *str,void *data) +static int parse_events__scanner (const char *str,void *data,int start_token) {YY_BUFFER_STATE buffer;void *scanner;int ret; - ret =parse_events_lex_init (&scanner); + ret =parse_events_lex_init_extra (start_token, &scanner);if (ret)return ret;
@@ -811,6 +812,27 @@ static int parse_events__scanner(const char *str, void *data)return ret; } +/* +* parse event config string, return a list of event terms. +*/ +int parse_events_terms (struct list_head *terms,const char *str) +{ +struct parse_events_data__terms data = { + .terms =NULL , + }; +int ret; + + ret =parse_events__scanner (str, &data,PE_START_TERMS ); +if (!ret) { +list_splice (data.terms, terms); +free (data.terms); +return 0 ; + } + +parse_events__free_terms (data.terms); +return ret; +} +int parse_events (struct perf_evlist *evlist,const char *str,int unset__used ) {struct parse_events_data__events data = {
@@ -819,7 +841,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) };int ret; - ret =parse_events__scanner (str, &data); + ret =parse_events__scanner (str, &data,PE_START_EVENTS );if (!ret) {int entries = data.idx - evlist->nr_entries;perf_evlist__splice_list_tail (evlist, &data.list, entries);
tools/perf/util/parse-events.h +5 -0
@@ -33,6 +33,7 @@ extern int parse_events_option(const struct option *opt, const char *str, int unset);extern int parse_events (struct perf_evlist *evlist,const char *str,int unset); +extern int parse_events_terms (struct list_head *terms,const char *str);extern int parse_filter (const struct option *opt,const char *str,int unset);#define EVENTS_HELP_MAX (128*1024)
@@ -68,6 +69,10 @@ struct parse_events_data__events {int idx; }; +struct parse_events_data__terms { +struct list_head *terms; +}; +int parse_events__is_hardcoded_term (struct parse_events__term *term);int parse_events__term_num (struct parse_events__term **_term,int type_term,char *config,long num);
tools/perf/util/parse-events.l +13 -0
@@ -79,6 +79,19 @@ modifier_event [ukhpGH]{1,8} modifier_bp [rwx] %% + +%{ + { + int start_token; + + start_token = (int) parse_events_get_extra(yyscanner); + if (start_token) { + parse_events_set_extra(NULL, yyscanner); + return start_token; + } + } +%} + cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
tools/perf/util/parse-events.y +12 -0
@@ -25,6 +25,7 @@ do { \ %} +%token PE_START_EVENTS PE_START_TERMS %token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM %token PE_NAME %token PE_MODIFIER_EVENT PE_MODIFIER_BP
@@ -60,6 +61,11 @@ do { \ } %% +start: +PE_START_EVENTS events +| +PE_START_TERMS terms + events: events ',' event | event
@@ -209,6 +215,12 @@ PE_RAW $$ = list; } +terms: event_config +{ + struct parse_events_data__terms *data = _data; + data->terms = $1; +} + event_config: event_config ',' event_term {
Signature · 1 line
1.7.6.5
[tip:perf/core] perf/tool: Add support to reuse event grammar to parse out terms
Commit-ID: 90e2b22dee908c13df256140a0d6527e3e8ea3f4 Gitweb: http://git.kernel.org/tip/90e2b22dee908c13df256140a0d6527e3e8ea3f4 Author: Jiri Olsa <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:40 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:25 +0200
perf/tool: Add support to reuse event grammar to parse out terms
We want to reuse the event grammar for parsing aliased terms. The obvious reason is we dont need to add new code when there's already support for this in event grammar.
Doing this by adding terms and event start entries into event parse grammar. The grammar forks on the begining based on the starting token, which is supplied via bison interface into the lexer. The lexer then returns the starting token as the first token, thus making the grammar switch accordingly.
Currently 2 starting tokens/grammars are supported:
PE_START_TERMS, PE_START_EVENTS
The PE_START_TERMS related grammar uses 'event_config' part of the grammar for term parsing.
--- tools/perf/util/parse-events.c | 28 +++++++++++++++++++++++++--- tools/perf/util/parse-events.h | 5 +++++ tools/perf/util/parse-events.l | 13 +++++++++++++ tools/perf/util/parse-events.y | 12 ++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-)
tools/perf/util/parse-events.c +25 -3
@@ -12,6 +12,7 @@#include "header.h" #include "debugfs.h" #include "parse-events-bison.h" +#define YY_EXTRA_TYPE int#include "parse-events-flex.h" #include "pmu.h"
@@ -788,13 +789,13 @@ int parse_events_modifier(struct list_head *list, char *str)return 0 ; } -static int parse_events__scanner (const char *str,void *data) +static int parse_events__scanner (const char *str,void *data,int start_token) {YY_BUFFER_STATE buffer;void *scanner;int ret; - ret =parse_events_lex_init (&scanner); + ret =parse_events_lex_init_extra (start_token, &scanner);if (ret)return ret;
@@ -811,6 +812,27 @@ static int parse_events__scanner(const char *str, void *data)return ret; } +/* +* parse event config string, return a list of event terms. +*/ +int parse_events_terms (struct list_head *terms,const char *str) +{ +struct parse_events_data__terms data = { + .terms =NULL , + }; +int ret; + + ret =parse_events__scanner (str, &data,PE_START_TERMS ); +if (!ret) { +list_splice (data.terms, terms); +free (data.terms); +return 0 ; + } + +parse_events__free_terms (data.terms); +return ret; +} +int parse_events (struct perf_evlist *evlist,const char *str,int unset__used ) {struct parse_events_data__events data = {
@@ -819,7 +841,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) };int ret; - ret =parse_events__scanner (str, &data); + ret =parse_events__scanner (str, &data,PE_START_EVENTS );if (!ret) {int entries = data.idx - evlist->nr_entries;perf_evlist__splice_list_tail (evlist, &data.list, entries);
tools/perf/util/parse-events.h +5 -0
@@ -33,6 +33,7 @@ extern int parse_events_option(const struct option *opt, const char *str, int unset);extern int parse_events (struct perf_evlist *evlist,const char *str,int unset); +extern int parse_events_terms (struct list_head *terms,const char *str);extern int parse_filter (const struct option *opt,const char *str,int unset);#define EVENTS_HELP_MAX (128*1024)
@@ -68,6 +69,10 @@ struct parse_events_data__events {int idx; }; +struct parse_events_data__terms { +struct list_head *terms; +}; +int parse_events__is_hardcoded_term (struct parse_events__term *term);int parse_events__term_num (struct parse_events__term **_term,int type_term,char *config,long num);
tools/perf/util/parse-events.l +13 -0
@@ -79,6 +79,19 @@ modifier_event [ukhpGH]{1,8} modifier_bp [rwx] %% + +%{ + { + int start_token; + + start_token = (int) parse_events_get_extra(yyscanner); + if (start_token) { + parse_events_set_extra(NULL, yyscanner); + return start_token; + } + } +%} + cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
tools/perf/util/parse-events.y +12 -0
@@ -25,6 +25,7 @@ do { \ %} +%token PE_START_EVENTS PE_START_TERMS %token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM %token PE_NAME %token PE_MODIFIER_EVENT PE_MODIFIER_BP
@@ -60,6 +61,11 @@ do { \ } %% +start: +PE_START_EVENTS events +| +PE_START_TERMS terms + events: events ',' event | event
@@ -209,6 +215,12 @@ PE_RAW $$ = list; } +terms: event_config +{ + struct parse_events_data__terms *data = _data; + data->terms = $1; +} + event_config: event_config ',' event_term {
PATCH v6 12/13 perf, tool: Add pmu event alias support
In reply to Yan, ZhengFrom: Jiri Olsa <[email protected]>
Adding support to specify alias term within the event description.
The definition of pmu event alias is located at:
${sysfs_mount}/bus/event_source/devices/${pmu}/events/
Each file in the 'events' directory defines a event alias. Its contents is like:
config=1,config1=2
Using pmu event alias, event could be now specified like:
uncore/CLOCKTICKS/ or uncore/event=CLOCKTICKS/
--- tools/perf/util/parse-events.c | 10 +++ tools/perf/util/parse-events.h | 2 + tools/perf/util/pmu.c | 166 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/pmu.h | 11 +++- 4 files changed, 188 insertions(+), 1 deletions(-)
tools/perf/util/parse-events.c +10 -0
@@ -701,6 +701,9 @@ int parse_events_add_pmu(struct list_head **list, int *idx,memset (&attr,0 ,sizeof (attr)); +if (perf_pmu__check_alias (pmu, head_config)) +return -EINVAL ; +/* * Configure hardcoded terms first, no need to check * return value when called with fail == 0 ;)
@@ -1143,6 +1146,13 @@ int parse_events__term_str(struct parse_events__term **term, config, str, 0); } +int parse_events__term_clone (struct parse_events__term **new, +struct parse_events__term *term) +{ +return new_term (new, term->type_val, term->type_term, term->config, + term->val.str, term->val.num); +} +void parse_events__free_terms (struct list_head *terms) {struct parse_events__term *term, *h;
tools/perf/util/parse-events.h +2 -0
@@ -78,6 +78,8 @@ int parse_events__term_num(struct parse_events__term **_term, int type_term, char *config, long num);int parse_events__term_str (struct parse_events__term **_term,int type_term,char *config,char *str); +int parse_events__term_clone (struct parse_events__term **new, +struct parse_events__term *term);void parse_events__free_terms (struct list_head *terms);int parse_events_modifier (struct list_head *list,char *str); int parse_events_add_tracepoint(struct list_head **list, int *idx,
tools/perf/util/pmu.c +166 -0
192 lines not on this page · raw message
tools/perf/util/pmu.h +10 -1
@@ -19,17 +19,26 @@ struct perf_pmu__format {struct list_head list; }; +struct perf_pmu__alias { +char *name; +struct list_head terms; +struct list_head list; +}; +struct perf_pmu {char *name;__u32 type;struct list_head format; +struct list_head aliases;struct list_head list; };struct perf_pmu *perf_pmu__find (char *name);int perf_pmu__config (struct perf_pmu *pmu,struct perf_event_attr *attr,struct list_head *head_terms); - +int perf_pmu__check_alias (struct perf_pmu *pmu,struct list_head *head_terms); +struct list_head *perf_pmu__alias (struct perf_pmu *pmu, +struct list_head *head_terms);int perf_pmu_wrap (void );void perf_pmu_error (struct list_head *list,char *name,char const *msg);
Signature · 1 line
1.7.6.5
[tip:perf/core] perf/tool: Add PMU event alias support
Commit-ID: a6146d5040cce560f700221158d77dd335eed332 Gitweb: http://git.kernel.org/tip/a6146d5040cce560f700221158d77dd335eed332 Author: Zheng Yan <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:41 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:26 +0200
perf/tool: Add PMU event alias support
Add support to specify alias term within the event description.
The definition of pmu event alias is located at:
${sysfs_mount}/bus/event_source/devices/${pmu}/events/Each file in the 'events' directory defines a event alias. Its contents are like:
config=1,config1=2
Using pmu event alias, an event can be now specified like:
uncore/CLOCKTICKS/ or uncore/event=CLOCKTICKS/
--- tools/perf/util/parse-events.c | 10 +++ tools/perf/util/parse-events.h | 2 + tools/perf/util/pmu.c | 166 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/pmu.h | 11 +++- 4 files changed, 188 insertions(+), 1 deletions(-)
tools/perf/util/parse-events.c +10 -0
@@ -701,6 +701,9 @@ int parse_events_add_pmu(struct list_head **list, int *idx,memset (&attr,0 ,sizeof (attr)); +if (perf_pmu__check_alias (pmu, head_config)) +return -EINVAL ; +/* * Configure hardcoded terms first, no need to check * return value when called with fail == 0 ;)
@@ -1143,6 +1146,13 @@ int parse_events__term_str(struct parse_events__term **term, config, str, 0); } +int parse_events__term_clone (struct parse_events__term **new, +struct parse_events__term *term) +{ +return new_term (new, term->type_val, term->type_term, term->config, + term->val.str, term->val.num); +} +void parse_events__free_terms (struct list_head *terms) {struct parse_events__term *term, *h;
tools/perf/util/parse-events.h +2 -0
@@ -78,6 +78,8 @@ int parse_events__term_num(struct parse_events__term **_term, int type_term, char *config, long num);int parse_events__term_str (struct parse_events__term **_term,int type_term,char *config,char *str); +int parse_events__term_clone (struct parse_events__term **new, +struct parse_events__term *term);void parse_events__free_terms (struct list_head *terms);int parse_events_modifier (struct list_head *list,char *str); int parse_events_add_tracepoint(struct list_head **list, int *idx,
tools/perf/util/pmu.c +166 -0
192 lines not on this page · raw message
tools/perf/util/pmu.h +10 -1
@@ -19,17 +19,26 @@ struct perf_pmu__format {struct list_head list; }; +struct perf_pmu__alias { +char *name; +struct list_head terms; +struct list_head list; +}; +struct perf_pmu {char *name;__u32 type;struct list_head format; +struct list_head aliases;struct list_head list; };struct perf_pmu *perf_pmu__find (char *name);int perf_pmu__config (struct perf_pmu *pmu,struct perf_event_attr *attr,struct list_head *head_terms); - +int perf_pmu__check_alias (struct perf_pmu *pmu,struct list_head *head_terms); +struct list_head *perf_pmu__alias (struct perf_pmu *pmu, +struct list_head *head_terms);int perf_pmu_wrap (void );void perf_pmu_error (struct list_head *list,char *name,char const *msg);
PATCH v6 13/13 perf, tool: Add automated test for pure terms parsing
In reply to Yan, ZhengFrom: Jiri Olsa <[email protected]>
Adding automated test for parsing terms out of the event grammar. Also slightly changing current event parsing test functions to follow up more generic namespace.
--- tools/perf/util/parse-events-test.c | 122 +++++++++++++++++++++++++++++++++-- 1 files changed, 117 insertions(+), 5 deletions(-)
tools/perf/util/parse-events-test.c +117 -5
@@ -430,6 +430,49 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)return 0 ; } +static int test__checkterms_simple (struct list_head *terms) +{ +struct parse_events__term *term; + +/* config=10 */ + term = list_entry(terms->next, struct parse_events__term, list); +TEST_ASSERT_VAL ("wrong type term" , + term->type_term ==PARSE_EVENTS__TERM_TYPE_CONFIG ); +TEST_ASSERT_VAL ("wrong type val" , + term->type_val ==PARSE_EVENTS__TERM_TYPE_NUM ); +TEST_ASSERT_VAL ("wrong val" , term->val.num ==10 ); +TEST_ASSERT_VAL ("wrong config" , !term->config); + +/* config1 */ + term = list_entry(term->list.next, struct parse_events__term, list); +TEST_ASSERT_VAL ("wrong type term" , + term->type_term ==PARSE_EVENTS__TERM_TYPE_CONFIG1 ); +TEST_ASSERT_VAL ("wrong type val" , + term->type_val ==PARSE_EVENTS__TERM_TYPE_NUM ); +TEST_ASSERT_VAL ("wrong val" , term->val.num ==1 ); +TEST_ASSERT_VAL ("wrong config" , !term->config); + +/* config2=3 */ + term = list_entry(term->list.next, struct parse_events__term, list); +TEST_ASSERT_VAL ("wrong type term" , + term->type_term ==PARSE_EVENTS__TERM_TYPE_CONFIG2 ); +TEST_ASSERT_VAL ("wrong type val" , + term->type_val ==PARSE_EVENTS__TERM_TYPE_NUM ); +TEST_ASSERT_VAL ("wrong val" , term->val.num ==3 ); +TEST_ASSERT_VAL ("wrong config" , !term->config); + +/* umask=1*/ + term = list_entry(term->list.next, struct parse_events__term, list); +TEST_ASSERT_VAL ("wrong type term" , + term->type_term ==PARSE_EVENTS__TERM_TYPE_USER ); +TEST_ASSERT_VAL ("wrong type val" , + term->type_val ==PARSE_EVENTS__TERM_TYPE_NUM ); +TEST_ASSERT_VAL ("wrong val" , term->val.num ==1 ); +TEST_ASSERT_VAL ("wrong config" , !strcmp (term->config,"umask" )); + +return 0 ; +} +struct test__event_st {const char *name;__u32 type;
@@ -559,7 +602,23 @@ static struct test__event_st test__events_pmu[] = {#define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \ sizeof(struct test__event_st)) -static int test (struct test__event_st *e) +struct test__term { +const char *str; +__u32 type; +int (*check)(struct list_head *terms); +}; + +static struct test__term test__terms[] = { + [0 ] = { + .str ="config=10,config1,config2=3,umask=1" , + .check = test__checkterms_simple, + }, +}; + +#define TEST__TERMS_CNT (sizeof(test__terms) / \ + sizeof(struct test__term)) + +static int test_event (struct test__event_st *e) {struct perf_evlist *evlist;int ret;
@@ -590,7 +649,48 @@ static int test_events(struct test__event_st *events, unsigned cnt)struct test__event_st *e = &events[i];pr_debug ("running test %d '%s'\n" , i, e->name); - ret =test (e); + ret =test_event (e); +if (ret) +break ; + } + +return ret; +} + +static int test_term (struct test__term *t) +{ +struct list_head *terms; +int ret; + + terms =malloc (sizeof (*terms)); +if (!terms) +return -ENOMEM ; + +INIT_LIST_HEAD (terms); + + ret =parse_events_terms (terms, t->str); +if (ret) { +pr_debug ("failed to parse terms '%s', err %d\n" , + t->str , ret); +return ret; + } + + ret = t->check (terms); +parse_events__free_terms (terms); + +return ret; +} + +static int test_terms (struct test__term *terms,unsigned cnt) +{ +int ret =0 ; +unsigned i; + +for (i =0 ; i < cnt; i++) { +struct test__term *t = &terms[i]; + +pr_debug ("running test %d '%s'\n" , i, t->str); + ret =test_term (t);if (ret)break ; }
@@ -617,9 +717,21 @@ int parse_events__test(void) {int ret; - ret =test_events (test__events,TEST__EVENTS_CNT ); -if (!ret &&test_pmu ()) - ret =test_events (test__events_pmu,TEST__EVENTS_PMU_CNT ); +do { + ret =test_events (test__events,TEST__EVENTS_CNT ); +if (ret) +break ; + +if (test_pmu ()) { + ret =test_events (test__events_pmu, +TEST__EVENTS_PMU_CNT ); +if (ret) +break ; + } + + ret =test_terms (test__terms,TEST__TERMS_CNT ); + + }while (0 );return ret; }
Signature · 1 line
1.7.6.5
[tip:perf/core] perf/tool: Add automated test for pure terms parsing
Commit-ID: 4429392e1484319df4209d41a98244c76d0caf56 Gitweb: http://git.kernel.org/tip/4429392e1484319df4209d41a98244c76d0caf56 Author: Jiri Olsa <[email protected]> AuthorDate: Fri, 15 Jun 2012 14:31:42 +0800 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 18 Jun 2012 12:13:26 +0200
perf/tool: Add automated test for pure terms parsing
Adding automated test for parsing terms out of the event grammar. Also slightly changing current event parsing test functions to follow up more generic namespace.
--- tools/perf/util/parse-events-test.c | 122 +++++++++++++++++++++++++++++++++-- 1 files changed, 117 insertions(+), 5 deletions(-)
tools/perf/util/parse-events-test.c +117 -5
@@ -430,6 +430,49 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)return 0 ; } +static int test__checkterms_simple (struct list_head *terms) +{ +struct parse_events__term *term; + +/* config=10 */ + term = list_entry(terms->next, struct parse_events__term, list); +TEST_ASSERT_VAL ("wrong type term" , + term->type_term ==PARSE_EVENTS__TERM_TYPE_CONFIG ); +TEST_ASSERT_VAL ("wrong type val" , + term->type_val ==PARSE_EVENTS__TERM_TYPE_NUM ); +TEST_ASSERT_VAL ("wrong val" , term->val.num ==10 ); +TEST_ASSERT_VAL ("wrong config" , !term->config); + +/* config1 */ + term = list_entry(term->list.next, struct parse_events__term, list); +TEST_ASSERT_VAL ("wrong type term" , + term->type_term ==PARSE_EVENTS__TERM_TYPE_CONFIG1 ); +TEST_ASSERT_VAL ("wrong type val" , + term->type_val ==PARSE_EVENTS__TERM_TYPE_NUM ); +TEST_ASSERT_VAL ("wrong val" , term->val.num ==1 ); +TEST_ASSERT_VAL ("wrong config" , !term->config); + +/* config2=3 */ + term = list_entry(term->list.next, struct parse_events__term, list); +TEST_ASSERT_VAL ("wrong type term" , + term->type_term ==PARSE_EVENTS__TERM_TYPE_CONFIG2 ); +TEST_ASSERT_VAL ("wrong type val" , + term->type_val ==PARSE_EVENTS__TERM_TYPE_NUM ); +TEST_ASSERT_VAL ("wrong val" , term->val.num ==3 ); +TEST_ASSERT_VAL ("wrong config" , !term->config); + +/* umask=1*/ + term = list_entry(term->list.next, struct parse_events__term, list); +TEST_ASSERT_VAL ("wrong type term" , + term->type_term ==PARSE_EVENTS__TERM_TYPE_USER ); +TEST_ASSERT_VAL ("wrong type val" , + term->type_val ==PARSE_EVENTS__TERM_TYPE_NUM ); +TEST_ASSERT_VAL ("wrong val" , term->val.num ==1 ); +TEST_ASSERT_VAL ("wrong config" , !strcmp (term->config,"umask" )); + +return 0 ; +} +struct test__event_st {const char *name;__u32 type;
@@ -559,7 +602,23 @@ static struct test__event_st test__events_pmu[] = {#define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \ sizeof(struct test__event_st)) -static int test (struct test__event_st *e) +struct test__term { +const char *str; +__u32 type; +int (*check)(struct list_head *terms); +}; + +static struct test__term test__terms[] = { + [0 ] = { + .str ="config=10,config1,config2=3,umask=1" , + .check = test__checkterms_simple, + }, +}; + +#define TEST__TERMS_CNT (sizeof(test__terms) / \ + sizeof(struct test__term)) + +static int test_event (struct test__event_st *e) {struct perf_evlist *evlist;int ret;
@@ -590,7 +649,48 @@ static int test_events(struct test__event_st *events, unsigned cnt)struct test__event_st *e = &events[i];pr_debug ("running test %d '%s'\n" , i, e->name); - ret =test (e); + ret =test_event (e); +if (ret) +break ; + } + +return ret; +} + +static int test_term (struct test__term *t) +{ +struct list_head *terms; +int ret; + + terms =malloc (sizeof (*terms)); +if (!terms) +return -ENOMEM ; + +INIT_LIST_HEAD (terms); + + ret =parse_events_terms (terms, t->str); +if (ret) { +pr_debug ("failed to parse terms '%s', err %d\n" , + t->str , ret); +return ret; + } + + ret = t->check (terms); +parse_events__free_terms (terms); + +return ret; +} + +static int test_terms (struct test__term *terms,unsigned cnt) +{ +int ret =0 ; +unsigned i; + +for (i =0 ; i < cnt; i++) { +struct test__term *t = &terms[i]; + +pr_debug ("running test %d '%s'\n" , i, t->str); + ret =test_term (t);if (ret)break ; }
@@ -617,9 +717,21 @@ int parse_events__test(void) {int ret; - ret =test_events (test__events,TEST__EVENTS_CNT ); -if (!ret &&test_pmu ()) - ret =test_events (test__events_pmu,TEST__EVENTS_PMU_CNT ); +do { + ret =test_events (test__events,TEST__EVENTS_CNT ); +if (ret) +break ; + +if (test_pmu ()) { + ret =test_events (test__events_pmu, +TEST__EVENTS_PMU_CNT ); +if (ret) +break ; + } + + ret =test_terms (test__terms,TEST__TERMS_CNT ); + + }while (0 );return ret; }
ok, so with this stuff something like:
perf stat -ae uncore/event=clockticks/ foo
will register a counter per cpu, which is somewhat silly since we only need one per node. What would be the best way to 'fix' this?
We could of course create another variant of -a which iterates nodes instead of cpus, -N or so.
Alternatively we could try and describe this in sysfs in some way, one possibility would be to include a link to /sys/devices/system/{cpu,node} or somesuch and use that link to iterate the correct space.
Any other suggestions?
Quoted 8 lines · Peter Zijlstra
ok, so with this stuff something like:
perf stat -ae uncore/event=clockticks/ foo
will register a counter per cpu, which is somewhat silly since we only need one per node. What would be the best way to 'fix' this?
Quoted 9 lines
We could of course create another variant of -a which iterates nodes instead of cpus, -N or so.
Alternatively we could try and describe this in sysfs in some way, one possibility would be to include a link to
/sys/devices/system/{cpu,node}or somesuch and use that link to iterate the correct space.Any other suggestions?
How about treat the 'cpu' parameter for uncore event as socket id instead of cpu id?
Regards
Yan, Zheng
Quoted 12 lines · Zheng
Quoted 11 lines · Peter Zijlstra
ok, so with this stuff something like:
perf stat -ae uncore/event=clockticks/ foo
will register a counter per cpu, which is somewhat silly since we only need one per node. What would be the best way to 'fix' this?
We could of course create another variant of -a which iterates nodes instead of cpus, -N or so.
Quoted 9 lines
Quoted 6 lines
Alternatively we could try and describe this in sysfs in some way, one possibility would be to include a link to
/sys/devices/system/{cpu,node}or somesuch and use that link to iterate the correct space.Any other suggestions?
How about treat the 'cpu' parameter for uncore event as socket id instead of cpu id?
But that does not address the use case of Peter, i.e., no cpu parameter passed. Looks like sysfs might be the only way to do this in a portable manner.
Quoted 17 lines · Stephane Eranian
Quoted 16 lines · Zheng
Quoted 15 lines · Peter Zijlstra
ok, so with this stuff something like:
perf stat -ae uncore/event=clockticks/ foo
will register a counter per cpu, which is somewhat silly since we only need one per node. What would be the best way to 'fix' this?
We could of course create another variant of -a which iterates nodes instead of cpus, -N or so.
Alternatively we could try and describe this in sysfs in some way, one possibility would be to include a link to
/sys/devices/system/{cpu,node}or somesuch and use that link to iterate the correct space.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Any other suggestions?
How about treat the 'cpu' parameter for uncore event as socket id instead of cpu id?
But that does not address the use case of Peter, i.e., no cpu parameter passed. Looks like sysfs might be the only way to do this in a portable manner.
It does. For example, on a dual socket system, perf can only register uncore counter with 'cpu' parameter is equal to 0 or 1. This method is hacky, but it requires minimal change for the kernel and perf tool.
Regards
Yan, Zheng
Quoted 23 lines · Zheng
Quoted 22 lines · Stephane Eranian
Quoted 21 lines · Zheng
Quoted 8 lines · Peter Zijlstra
ok, so with this stuff something like:
perf stat -ae uncore/event=clockticks/ foo
will register a counter per cpu, which is somewhat silly since we only need one per node. What would be the best way to 'fix' this?
Quoted 9 lines
We could of course create another variant of -a which iterates nodes instead of cpus, -N or so.
Alternatively we could try and describe this in sysfs in some way, one possibility would be to include a link to
/sys/devices/system/{cpu,node}or somesuch and use that link to iterate the correct space.Any other suggestions?
How about treat the 'cpu' parameter for uncore event as socket id instead of cpu id?
Quoted 7 lines
Quoted 3 lines
But that does not address the use case of Peter, i.e., no cpu parameter passed. Looks like sysfs might be the only way to do this in a portable manner.
It does. For example, on a dual socket system, perf can only register uncore counter with 'cpu' parameter is equal to 0 or 1. This method is hacky, but it requires minimal change for the kernel and perf tool.
I was saying, I don't want to have to pass -C x with -a and yet have perf stat only instantiate the event once per socket. I think that's what PeterZ was asking about.
Quoted 3 lines
Regards
Yan, Zheng
Quoted 6 lines · Stephane Eranian
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
How about treat the 'cpu' parameter for uncore event as socket id instead of cpu id?
But that does not address the use case of Peter, i.e., no cpu parameter passed. Looks like sysfs might be the only way to do this in a portable manner.
Quoted 7 lines
Quoted 4 lines
It does. For example, on a dual socket system, perf can only register uncore counter with 'cpu' parameter is equal to 0 or 1. This method is hacky, but it requires minimal change for the kernel and perf tool.
I was saying, I don't want to have to pass -C x with -a and yet have perf stat only instantiate the event once per socket. I think that's what PeterZ was asking about.
What Zheng is saying is that -a will iterate [0..nr_cpus), but since we're interpreting the sys_perf_event_open(.cpu) argument as node, we'll fail the syscall with -EINVAL or so for .cpu >= nr_node_ids.
This way, we'll only create one counter per node.
I would work, but its not pretty since we still don't know what we're iterating.
Quoted 12 lines · Peter Zijlstra
Quoted 10 lines · Stephane Eranian
Quoted 10 lines
Quoted 6 lines
Quoted 3 lines
How about treat the 'cpu' parameter for uncore event as socket id instead of cpu id?
But that does not address the use case of Peter, i.e., no cpu parameter passed. Looks like sysfs might be the only way to do this in a portable manner.
It does. For example, on a dual socket system, perf can only register uncore counter with 'cpu' parameter is equal to 0 or 1. This method is hacky, but it requires minimal change for the kernel and perf tool.
Quoted 8 lines
Quoted 3 lines
I was saying, I don't want to have to pass -C x with -a and yet have perf stat only instantiate the event once per socket. I think that's what PeterZ was asking about.
What Zheng is saying is that -a will iterate [0..nr_cpus), but since we're interpreting the
sys_perf_event_open(.cpu)argument as node, we'll fail the syscall with-EINVALor so for .cpu >=nr_node_ids.
Ok, but how do you distinguish EINVAL is this case from an error with a non uncore event? Unless you return a unique error code, I don't see how you'd solve that. In general, I don't like it when perf switches events or CPUs under the cover.
When happens with -a -A?
Quoted 4 lines
This way, we'll only create one counter per node.
I would work, but its not pretty since we still don't know what we're iterating.
Not pretty.
Quoted 29 lines · Stephane Eranian
Quoted 12 lines · Peter Zijlstra
Quoted 10 lines · Stephane Eranian
Quoted 10 lines
Quoted 6 lines
Quoted 3 lines
How about treat the 'cpu' parameter for uncore event as socket id instead of cpu id?
But that does not address the use case of Peter, i.e., no cpu parameter passed. Looks like sysfs might be the only way to do this in a portable manner.
It does. For example, on a dual socket system, perf can only register uncore counter with 'cpu' parameter is equal to 0 or 1. This method is hacky, but it requires minimal change for the kernel and perf tool.
Quoted 8 lines
Quoted 3 lines
I was saying, I don't want to have to pass -C x with -a and yet have perf stat only instantiate the event once per socket. I think that's what PeterZ was asking about.
What Zheng is saying is that -a will iterate [0..nr_cpus), but since we're interpreting the
sys_perf_event_open(.cpu)argument as node, we'll fail the syscall with-EINVALor so for .cpu >=nr_node_ids.Ok, but how do you distinguish EINVAL is this case from an error with a non uncore event? Unless you return a unique error code, I don't see how you'd solve that. In general, I don't like it when perf switches events or CPUs under the cover.
When happens with -a -A?
Quoted 6 lines
Quoted 4 lines
This way, we'll only create one counter per node.
I would work, but its not pretty since we still don't know what we're iterating.
Not pretty.
Ok, I will try implementing the sysfs link approach that Peter suggested.
Thanks
Yan, Zheng