Skip to contentSkip to conversation

perf: introduce model specific events and AMD IBS

PATCH In review Robert Richter 4 participants 55 messages Apr 13, 2010 – May 28, 2010

Subsystems (6)
x86 PowerPC perf events Tracing +2 more subsystems
lore
Share & tools
lore
#0 lore raw

cover perf: introduce model specific events and AMD IBS

This patch series introduces model specific events and impments AMD IBS (Instruction Based Sampling) for perf_events.

IBS is documented here:

BIOS and Kernel Developer’s Guide (BKDG) For AMD Family 10h Processors
http://support.amd.com/us/Processor_TechDocs/31116.pdf

AMD64 Architecture Programmer’s Manual Volume 2: System Programming
http://support.amd.com/us/Processor_TechDocs/24593.pdf

The general approach is to introduce a flag to mark an event as model specific. With that flag set a model specific ibs (raw) config value can be passed to the pmu for setup. When there are ibs samples available, it is sent back as a raw data sample to the userland. So we have a raw config value and raw sampling data. This requires the userland to setup ibs and further extract and process sampling data.

Patches 1-8 rework and refactor the code to prepare the ibs implementation. This is done in patches 9-12.

I will add ibs example code to libpfm4.

-Robert

#1 lore raw

PATCH 1/12 perf, x86: move perfctr init code to x86_setup_perfctr()

Split __hw_perf_event_init() to configure pmu events other than perfctrs. Perfctr code is moved to a separate function x86_setup_perfctr(). This and the following patches refactor the code.

Split in multiple patches for better review.

---
 arch/x86/kernel/cpu/perf_event.c |   20 ++++++++++++++------
 1 files changed, 14 insertions(+), 6 deletions(-)
arch/x86/kernel/cpu/perf_event.c +14 -6
index 626154a..d275277 100644
@@ -426,6 +426,8 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event_attr *attr)
 	return 0;
 }
 
+static int x86_setup_perfctr(struct perf_event *event);
+
 static int x86_pmu_hw_config(struct perf_event *event)
 {
 	/*
@@ -453,9 +455,6 @@ static int x86_pmu_hw_config(struct perf_event *event)
  */
 static int __hw_perf_event_init(struct perf_event *event)
 {
-	struct perf_event_attr *attr = &event->attr;
-	struct hw_perf_event *hwc = &event->hw;
-	u64 config;
 	int err;
 
 	if (!x86_pmu_initialized())
@@ -482,15 +481,24 @@ static int __hw_perf_event_init(struct perf_event *event)
 
 	event->destroy = hw_perf_event_destroy;
 
-	hwc->idx = -1;
-	hwc->last_cpu = -1;
-	hwc->last_tag = ~0ULL;
+	event->hw.idx = -1;
+	event->hw.last_cpu = -1;
+	event->hw.last_tag = ~0ULL;
 
 	/* Processor specifics */
 	err = x86_pmu.hw_config(event);
 	if (err)
 		return err;
 
+	return x86_setup_perfctr(event);
+}
+
+static int x86_setup_perfctr(struct perf_event *event)
+{
+	struct perf_event_attr *attr = &event->attr;
+	struct hw_perf_event *hwc = &event->hw;
+	u64 config;
+
 	if (!hwc->sample_period) {
 		hwc->sample_period = x86_pmu.max_period;
 		hwc->last_period = hwc->sample_period;
Signature · 1 line
1.7.0.3
#2 lore raw

[tip:perf/core] perf, x86: Move perfctr init code to x86_setup_perfctr()

Commit-ID:  4261e0e0efd9e04b6c69e0773c3cf4d6f337c416
Gitweb:     http://git.kernel.org/tip/4261e0e0efd9e04b6c69e0773c3cf4d6f337c416
Author:     Robert Richter <[email protected]>
AuthorDate: Tue, 13 Apr 2010 22:23:10 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 7 May 2010 11:30:59 +0200

perf, x86: Move perfctr init code to x86_setup_perfctr()

Split __hw_perf_event_init() to configure pmu events other than perfctrs. Perfctr code is moved to a separate function x86_setup_perfctr(). This and the following patches refactor the code.

Split in multiple patches for better review.

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c |   20 ++++++++++++++------
 1 files changed, 14 insertions(+), 6 deletions(-)
arch/x86/kernel/cpu/perf_event.c +14 -6
index 7de7061..801441a 100644
@@ -426,6 +426,8 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event_attr *attr)
 	return 0;
 }
 
+static int x86_setup_perfctr(struct perf_event *event);
+
 static int x86_pmu_hw_config(struct perf_event *event)
 {
 	/*
@@ -453,9 +455,6 @@ static int x86_pmu_hw_config(struct perf_event *event)
  */
 static int __hw_perf_event_init(struct perf_event *event)
 {
-	struct perf_event_attr *attr = &event->attr;
-	struct hw_perf_event *hwc = &event->hw;
-	u64 config;
 	int err;
 
 	if (!x86_pmu_initialized())
@@ -482,15 +481,24 @@ static int __hw_perf_event_init(struct perf_event *event)
 
 	event->destroy = hw_perf_event_destroy;
 
-	hwc->idx = -1;
-	hwc->last_cpu = -1;
-	hwc->last_tag = ~0ULL;
+	event->hw.idx = -1;
+	event->hw.last_cpu = -1;
+	event->hw.last_tag = ~0ULL;
 
 	/* Processor specifics */
 	err = x86_pmu.hw_config(event);
 	if (err)
 		return err;
 
+	return x86_setup_perfctr(event);
+}
+
+static int x86_setup_perfctr(struct perf_event *event)
+{
+	struct perf_event_attr *attr = &event->attr;
+	struct hw_perf_event *hwc = &event->hw;
+	u64 config;
+
 	if (!hwc->sample_period) {
 		hwc->sample_period = x86_pmu.max_period;
 		hwc->last_period = hwc->sample_period;
#3 lore raw

PATCH 2/12 perf, x86: moving x86_setup_perfctr()

In reply to Robert Richter

Moving x86_setup_perfctr(), no other changes made.

---
 arch/x86/kernel/cpu/perf_event.c |  120 +++++++++++++++++++-------------------
 1 files changed, 59 insertions(+), 61 deletions(-)
arch/x86/kernel/cpu/perf_event.c +59 -61
index d275277..84b6107 100644
@@ -426,7 +426,65 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event_attr *attr)
 	return 0;
 }
 
-static int x86_setup_perfctr(struct perf_event *event);
+static int x86_setup_perfctr(struct perf_event *event)
+{
+	struct perf_event_attr *attr = &event->attr;
+	struct hw_perf_event *hwc = &event->hw;
+	u64 config;
+
+	if (!hwc->sample_period) {
+		hwc->sample_period = x86_pmu.max_period;
+		hwc->last_period = hwc->sample_period;
+		atomic64_set(&hwc->period_left, hwc->sample_period);
+	} else {
+		/*
+		 * If we have a PMU initialized but no APIC
+		 * interrupts, we cannot sample hardware
+		 * events (user-space has to fall back and
+		 * sample via a hrtimer based software event):
+		 */
+		if (!x86_pmu.apic)
+			return -EOPNOTSUPP;
+	}
+
+	if (attr->type == PERF_TYPE_RAW)
+		return 0;
+
+	if (attr->type == PERF_TYPE_HW_CACHE)
+		return set_ext_hw_attr(hwc, attr);
+
+	if (attr->config >= x86_pmu.max_events)
+		return -EINVAL;
+
+	/*
+	 * The generic map:
+	 */
+	config = x86_pmu.event_map(attr->config);
+
+	if (config == 0)
+		return -ENOENT;
+
+	if (config == -1LL)
+		return -EINVAL;
+
+	/*
+	 * Branch tracing:
+	 */
+	if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
+	    (hwc->sample_period == 1)) {
+		/* BTS is not supported by this architecture. */
+		if (!x86_pmu.bts)
+			return -EOPNOTSUPP;
+
+		/* BTS is currently only allowed for user-mode. */
+		if (!attr->exclude_kernel)
+			return -EOPNOTSUPP;
+	}
+
+	hwc->config |= config;
+
+	return 0;
+}
 
 static int x86_pmu_hw_config(struct perf_event *event)
 {
@@ -493,66 +551,6 @@ static int __hw_perf_event_init(struct perf_event *event)
 	return x86_setup_perfctr(event);
 }
 
-static int x86_setup_perfctr(struct perf_event *event)
-{
-	struct perf_event_attr *attr = &event->attr;
-	struct hw_perf_event *hwc = &event->hw;
-	u64 config;
-
-	if (!hwc->sample_period) {
-		hwc->sample_period = x86_pmu.max_period;
-		hwc->last_period = hwc->sample_period;
-		atomic64_set(&hwc->period_left, hwc->sample_period);
-	} else {
-		/*
-		 * If we have a PMU initialized but no APIC
-		 * interrupts, we cannot sample hardware
-		 * events (user-space has to fall back and
-		 * sample via a hrtimer based software event):
-		 */
-		if (!x86_pmu.apic)
-			return -EOPNOTSUPP;
-	}
-
-	if (attr->type == PERF_TYPE_RAW)
-		return 0;
-
-	if (attr->type == PERF_TYPE_HW_CACHE)
-		return set_ext_hw_attr(hwc, attr);
-
-	if (attr->config >= x86_pmu.max_events)
-		return -EINVAL;
-
-	/*
-	 * The generic map:
-	 */
-	config = x86_pmu.event_map(attr->config);
-
-	if (config == 0)
-		return -ENOENT;
-
-	if (config == -1LL)
-		return -EINVAL;
-
-	/*
-	 * Branch tracing:
-	 */
-	if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
-	    (hwc->sample_period == 1)) {
-		/* BTS is not supported by this architecture. */
-		if (!x86_pmu.bts)
-			return -EOPNOTSUPP;
-
-		/* BTS is currently only allowed for user-mode. */
-		if (!attr->exclude_kernel)
-			return -EOPNOTSUPP;
-	}
-
-	hwc->config |= config;
-
-	return 0;
-}
-
 static void x86_pmu_disable_all(void)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
Signature · 1 line
1.7.0.3
#4 lore raw

[tip:perf/core] perf, x86: Move x86_setup_perfctr()

Commit-ID:  c1726f343b3bfc2ee037e191907c632a31903021
Gitweb:     http://git.kernel.org/tip/c1726f343b3bfc2ee037e191907c632a31903021
Author:     Robert Richter <[email protected]>
AuthorDate: Tue, 13 Apr 2010 22:23:11 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 7 May 2010 11:31:00 +0200

perf, x86: Move x86_setup_perfctr()

Move x86_setup_perfctr(), no other changes made.

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c |  120 +++++++++++++++++++-------------------
 1 files changed, 59 insertions(+), 61 deletions(-)
arch/x86/kernel/cpu/perf_event.c +59 -61
index 801441a..3d3bceb 100644
@@ -426,7 +426,65 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event_attr *attr)
 	return 0;
 }
 
-static int x86_setup_perfctr(struct perf_event *event);
+static int x86_setup_perfctr(struct perf_event *event)
+{
+	struct perf_event_attr *attr = &event->attr;
+	struct hw_perf_event *hwc = &event->hw;
+	u64 config;
+
+	if (!hwc->sample_period) {
+		hwc->sample_period = x86_pmu.max_period;
+		hwc->last_period = hwc->sample_period;
+		atomic64_set(&hwc->period_left, hwc->sample_period);
+	} else {
+		/*
+		 * If we have a PMU initialized but no APIC
+		 * interrupts, we cannot sample hardware
+		 * events (user-space has to fall back and
+		 * sample via a hrtimer based software event):
+		 */
+		if (!x86_pmu.apic)
+			return -EOPNOTSUPP;
+	}
+
+	if (attr->type == PERF_TYPE_RAW)
+		return 0;
+
+	if (attr->type == PERF_TYPE_HW_CACHE)
+		return set_ext_hw_attr(hwc, attr);
+
+	if (attr->config >= x86_pmu.max_events)
+		return -EINVAL;
+
+	/*
+	 * The generic map:
+	 */
+	config = x86_pmu.event_map(attr->config);
+
+	if (config == 0)
+		return -ENOENT;
+
+	if (config == -1LL)
+		return -EINVAL;
+
+	/*
+	 * Branch tracing:
+	 */
+	if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
+	    (hwc->sample_period == 1)) {
+		/* BTS is not supported by this architecture. */
+		if (!x86_pmu.bts)
+			return -EOPNOTSUPP;
+
+		/* BTS is currently only allowed for user-mode. */
+		if (!attr->exclude_kernel)
+			return -EOPNOTSUPP;
+	}
+
+	hwc->config |= config;
+
+	return 0;
+}
 
 static int x86_pmu_hw_config(struct perf_event *event)
 {
@@ -493,66 +551,6 @@ static int __hw_perf_event_init(struct perf_event *event)
 	return x86_setup_perfctr(event);
 }
 
-static int x86_setup_perfctr(struct perf_event *event)
-{
-	struct perf_event_attr *attr = &event->attr;
-	struct hw_perf_event *hwc = &event->hw;
-	u64 config;
-
-	if (!hwc->sample_period) {
-		hwc->sample_period = x86_pmu.max_period;
-		hwc->last_period = hwc->sample_period;
-		atomic64_set(&hwc->period_left, hwc->sample_period);
-	} else {
-		/*
-		 * If we have a PMU initialized but no APIC
-		 * interrupts, we cannot sample hardware
-		 * events (user-space has to fall back and
-		 * sample via a hrtimer based software event):
-		 */
-		if (!x86_pmu.apic)
-			return -EOPNOTSUPP;
-	}
-
-	if (attr->type == PERF_TYPE_RAW)
-		return 0;
-
-	if (attr->type == PERF_TYPE_HW_CACHE)
-		return set_ext_hw_attr(hwc, attr);
-
-	if (attr->config >= x86_pmu.max_events)
-		return -EINVAL;
-
-	/*
-	 * The generic map:
-	 */
-	config = x86_pmu.event_map(attr->config);
-
-	if (config == 0)
-		return -ENOENT;
-
-	if (config == -1LL)
-		return -EINVAL;
-
-	/*
-	 * Branch tracing:
-	 */
-	if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
-	    (hwc->sample_period == 1)) {
-		/* BTS is not supported by this architecture. */
-		if (!x86_pmu.bts)
-			return -EOPNOTSUPP;
-
-		/* BTS is currently only allowed for user-mode. */
-		if (!attr->exclude_kernel)
-			return -EOPNOTSUPP;
-	}
-
-	hwc->config |= config;
-
-	return 0;
-}
-
 static void x86_pmu_disable_all(void)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
#5 lore raw

PATCH 3/12 perf, x86: call x86_setup_perfctr() from .hw_config()

In reply to Robert Richter

The perfctr setup calls are in the corresponding .hw_config() functions now. This makes it possible to introduce config functions for other pmu events that are not perfctr specific.

Also, all of a sudden the code looks much nicer.

---
 arch/x86/kernel/cpu/perf_event.c    |    9 ++-------
 arch/x86/kernel/cpu/perf_event_p4.c |    2 +-
 2 files changed, 3 insertions(+), 8 deletions(-)
arch/x86/kernel/cpu/perf_event.c +2 -7
index 84b6107..5945128 100644
@@ -505,7 +505,7 @@ static int x86_pmu_hw_config(struct perf_event *event)
 	if (event->attr.type == PERF_TYPE_RAW)
 		event->hw.config |= event->attr.config & X86_RAW_EVENT_MASK;
 
-	return 0;
+	return x86_setup_perfctr(event);
 }
 
 /*
@@ -543,12 +543,7 @@ static int __hw_perf_event_init(struct perf_event *event)
 	event->hw.last_cpu = -1;
 	event->hw.last_tag = ~0ULL;
 
-	/* Processor specifics */
-	err = x86_pmu.hw_config(event);
-	if (err)
-		return err;
-
-	return x86_setup_perfctr(event);
+	return x86_pmu.hw_config(event);
 }
 
 static void x86_pmu_disable_all(void)
arch/x86/kernel/cpu/perf_event_p4.c +1 -1
index 15367cc..9e00205 100644
@@ -455,7 +455,7 @@ static int p4_hw_config(struct perf_event *event)
 		(p4_config_pack_escr(P4_ESCR_MASK_HT) |
 		 p4_config_pack_cccr(P4_CCCR_MASK_HT));
 
-	return 0;
+	return x86_setup_perfctr(event);
 }
 
 static inline void p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
Signature · 1 line
1.7.0.3
#6 lore raw

[tip:perf/core] perf, x86: Call x86_setup_perfctr() from .hw_config()

Commit-ID:  9d0fcba67e47ff398a6fa86476d4884d472dc98a
Gitweb:     http://git.kernel.org/tip/9d0fcba67e47ff398a6fa86476d4884d472dc98a
Author:     Robert Richter <[email protected]>
AuthorDate: Tue, 13 Apr 2010 22:23:12 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 7 May 2010 11:31:00 +0200

perf, x86: Call x86_setup_perfctr() from .hw_config()

The perfctr setup calls are in the corresponding .hw_config() functions now. This makes it possible to introduce config functions for other pmu events that are not perfctr specific.

Also, all of a sudden the code looks much nicer.

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c    |    9 ++-------
 arch/x86/kernel/cpu/perf_event_p4.c |    2 +-
 2 files changed, 3 insertions(+), 8 deletions(-)
arch/x86/kernel/cpu/perf_event.c +2 -7
index 3d3bceb..c2c1e10 100644
@@ -505,7 +505,7 @@ static int x86_pmu_hw_config(struct perf_event *event)
 	if (event->attr.type == PERF_TYPE_RAW)
 		event->hw.config |= event->attr.config & X86_RAW_EVENT_MASK;
 
-	return 0;
+	return x86_setup_perfctr(event);
 }
 
 /*
@@ -543,12 +543,7 @@ static int __hw_perf_event_init(struct perf_event *event)
 	event->hw.last_cpu = -1;
 	event->hw.last_tag = ~0ULL;
 
-	/* Processor specifics */
-	err = x86_pmu.hw_config(event);
-	if (err)
-		return err;
-
-	return x86_setup_perfctr(event);
+	return x86_pmu.hw_config(event);
 }
 
 static void x86_pmu_disable_all(void)
arch/x86/kernel/cpu/perf_event_p4.c +1 -1
index 15367cc..9e00205 100644
@@ -455,7 +455,7 @@ static int p4_hw_config(struct perf_event *event)
 		(p4_config_pack_escr(P4_ESCR_MASK_HT) |
 		 p4_config_pack_cccr(P4_CCCR_MASK_HT));
 
-	return 0;
+	return x86_setup_perfctr(event);
 }
 
 static inline void p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc)
#7 lore raw

PATCH 4/12 perf: introduce flag for model specific events

In reply to Robert Richter

This patch introduces a flag to mark events as model specific. The flag can be used to setup hardware events other than generic performance counters by passing special config data to the pmu. The data can be interpreted different from generic events and can be used for other purposes.

The concept of PMU model-specific arguments was practiced already in Perfmon2. Perfmon2 provides an interface to pass model specific config values to the pmu and receive event specific samples back. The implementation of the model specific flag extends the perf_event i/f by this feature too.

The userland program must be aware of the cpu model to create model specific events. This could be done for example by checking the cpu and family.

The model_spec flag can be arbitrarily reused on other models or architectures. For backward compatibility all architectures must return an error, if model_spec events are not supported and the bit is set.

E.g., this flag is used to setup IBS on an AMD cpu. IBS is not common to pmu features from other vendors or architectures. The pmu must be setup with a special config value. Sample data is returned in a certain format back to the userland. An IBS event is passed in the config field of the event attributes and with model_spec and raw event flag enabled. The samples are then passed back in a raw sample.

---
 arch/powerpc/kernel/perf_event.c |    3 +++
 arch/sh/kernel/perf_event.c      |    3 +++
 arch/sparc/kernel/perf_event.c   |    3 +++
 arch/x86/kernel/cpu/perf_event.c |    3 +++
 include/linux/perf_event.h       |    3 ++-
 5 files changed, 14 insertions(+), 1 deletions(-)
arch/powerpc/kernel/perf_event.c +3 -0
index 08460a2..8e68e15 100644
@@ -1037,6 +1037,9 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
 	event->hw.config_base = ev;
 	event->hw.idx = 0;
 
+	if (attr->model_spec)
+		return ERR_PTR(-EOPNOTSUPP);
+
 	/*
 	 * If we are not running on a hypervisor, force the
 	 * exclude_hv bit to 0 so that we don't care what
arch/sh/kernel/perf_event.c +3 -0
index 81b6de4..eef545a 100644
@@ -109,6 +109,9 @@ static int __hw_perf_event_init(struct perf_event *event)
 	if (!sh_pmu_initialized())
 		return -ENODEV;
 
+	if (attr->model_spec)
+		return -EOPNOTSUPP;
+
 	/*
 	 * All of the on-chip counters are "limited", in that they have
 	 * no interrupts, and are therefore unable to do sampling without
arch/sparc/kernel/perf_event.c +3 -0
index e277193..5c1d2a4 100644
@@ -1083,6 +1083,9 @@ static int __hw_perf_event_init(struct perf_event *event)
 	} else
 		return -EOPNOTSUPP;
 
+	if (attr->model_spec)
+		return -EOPNOTSUPP;
+
 	/* We save the enable bits in the config_base.  */
 	hwc->config_base = sparc_pmu->irq_bit;
 	if (!attr->exclude_user)
arch/x86/kernel/cpu/perf_event.c +3 -0
index 5945128..9eeffad 100644
@@ -432,6 +432,9 @@ static int x86_setup_perfctr(struct perf_event *event)
 	struct hw_perf_event *hwc = &event->hw;
 	u64 config;
 
+	if (attr->model_spec)
+		return -EOPNOTSUPP;
+
 	if (!hwc->sample_period) {
 		hwc->sample_period = x86_pmu.max_period;
 		hwc->last_period = hwc->sample_period;
include/linux/perf_event.h +2 -1
index 6e96cc8..e90ba6e 100644
@@ -204,8 +204,9 @@ struct perf_event_attr {
 				task           :  1, /* trace fork/exit       */
 				watermark      :  1, /* wakeup_watermark      */
 				precise        :  1, /* OoO invariant counter */
+				model_spec     :  1, /* model specific hw event */
 
-				__reserved_1   : 48;
+				__reserved_1   : 47;
 
 	union {
 		__u32		wakeup_events;	  /* wakeup every n events */
Signature · 1 line
1.7.0.3
#8 lore raw

PATCH 5/12 perf, x86: pass enable bit mask to __x86_pmu_enable_event()

In reply to Robert Richter

To reuse this function for events with different enable bit masks, this mask is part of the function's argument list now.

The function will be used later to control ibs events too.

---
 arch/x86/kernel/cpu/perf_event.c       |    9 +++++----
 arch/x86/kernel/cpu/perf_event_intel.c |    5 +++--
 2 files changed, 8 insertions(+), 6 deletions(-)
arch/x86/kernel/cpu/perf_event.c +5 -4
index 9eeffad..f66f52a 100644
@@ -847,10 +847,10 @@ void hw_perf_enable(void)
 	x86_pmu.enable_all(added);
 }
 
-static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc)
+static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
+					  u64 enable_mask)
 {
-	wrmsrl(hwc->config_base + hwc->idx,
-			      hwc->config | ARCH_PERFMON_EVENTSEL_ENABLE);
+	wrmsrl(hwc->config_base + hwc->idx, hwc->config | enable_mask);
 }
 
 static inline void x86_pmu_disable_event(struct perf_event *event)
@@ -922,7 +922,8 @@ static void x86_pmu_enable_event(struct perf_event *event)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	if (cpuc->enabled)
-		__x86_pmu_enable_event(&event->hw);
+		__x86_pmu_enable_event(&event->hw,
+				       ARCH_PERFMON_EVENTSEL_ENABLE);
 }
 
 /*
arch/x86/kernel/cpu/perf_event_intel.c +3 -2
index a099df9..a4b56ac 100644
@@ -513,7 +513,8 @@ static void intel_pmu_nhm_enable_all(int added)
 			if (!event)
 				continue;
 
-			__x86_pmu_enable_event(&event->hw);
+			__x86_pmu_enable_event(&event->hw,
+					       ARCH_PERFMON_EVENTSEL_ENABLE);
 		}
 	}
 	intel_pmu_enable_all(added);
@@ -617,7 +618,7 @@ static void intel_pmu_enable_event(struct perf_event *event)
 	if (unlikely(event->attr.precise))
 		intel_pmu_pebs_enable(event);
 
-	__x86_pmu_enable_event(hwc);
+	__x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE);
 }
 
 /*
Signature · 1 line
1.7.0.3
#9 lore raw

[tip:perf/core] perf, x86: Pass enable bit mask to __x86_pmu_enable_event()

Commit-ID:  31fa58af57c41d2912debf62d47d5811062411f1
Gitweb:     http://git.kernel.org/tip/31fa58af57c41d2912debf62d47d5811062411f1
Author:     Robert Richter <[email protected]>
AuthorDate: Tue, 13 Apr 2010 22:23:14 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 7 May 2010 11:31:00 +0200

perf, x86: Pass enable bit mask to __x86_pmu_enable_event()

To reuse this function for events with different enable bit masks, this mask is part of the function's argument list now.

The function will be used later to control ibs events too.

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c       |    9 +++++----
 arch/x86/kernel/cpu/perf_event_intel.c |    5 +++--
 2 files changed, 8 insertions(+), 6 deletions(-)
arch/x86/kernel/cpu/perf_event.c +5 -4
index c2c1e10..4e218d7 100644
@@ -844,10 +844,10 @@ void hw_perf_enable(void)
 	x86_pmu.enable_all(added);
 }
 
-static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc)
+static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc,
+					  u64 enable_mask)
 {
-	wrmsrl(hwc->config_base + hwc->idx,
-			      hwc->config | ARCH_PERFMON_EVENTSEL_ENABLE);
+	wrmsrl(hwc->config_base + hwc->idx, hwc->config | enable_mask);
 }
 
 static inline void x86_pmu_disable_event(struct perf_event *event)
@@ -919,7 +919,8 @@ static void x86_pmu_enable_event(struct perf_event *event)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	if (cpuc->enabled)
-		__x86_pmu_enable_event(&event->hw);
+		__x86_pmu_enable_event(&event->hw,
+				       ARCH_PERFMON_EVENTSEL_ENABLE);
 }
 
 /*
arch/x86/kernel/cpu/perf_event_intel.c +3 -2
index a099df9..a4b56ac 100644
@@ -513,7 +513,8 @@ static void intel_pmu_nhm_enable_all(int added)
 			if (!event)
 				continue;
 
-			__x86_pmu_enable_event(&event->hw);
+			__x86_pmu_enable_event(&event->hw,
+					       ARCH_PERFMON_EVENTSEL_ENABLE);
 		}
 	}
 	intel_pmu_enable_all(added);
@@ -617,7 +618,7 @@ static void intel_pmu_enable_event(struct perf_event *event)
 	if (unlikely(event->attr.precise))
 		intel_pmu_pebs_enable(event);
 
-	__x86_pmu_enable_event(hwc);
+	__x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE);
 }
 
 /*
#10 lore raw

PATCH 6/12 perf, x86: use weight instead of cmask in for_each_event_constraint()

In reply to Robert Richter

There may exist constraints with a cmask set to zero. In this case for_each_event_constraint() will not work properly. Now weight is used instead of the cmask for loop exit detection. Weight is always a value other than zero since the default contains the HWEIGHT from the counter mask and in other cases a value of zero does not fit too.

This is in preparation of ibs event constraints that wont have a cmask.

---
 arch/x86/kernel/cpu/perf_event.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/kernel/cpu/perf_event.c +1 -1
index f66f52a..feda380 100644
@@ -170,7 +170,7 @@ struct cpu_hw_events {
 	EVENT_CONSTRAINT(0, 0, 0)
 
 #define for_each_event_constraint(e, c)	\
-	for ((e) = (c); (e)->cmask; (e)++)
+	for ((e) = (c); (e)->weight; (e)++)
 
 union perf_capabilities {
 	struct {
Signature · 1 line
1.7.0.3
#11 lore raw

[tip:perf/core] perf, x86: Use weight instead of cmask in for_each_event_constraint()

Commit-ID:  a1f2b70a942b8d858a0ab02567da3999b60a99b2
Gitweb:     http://git.kernel.org/tip/a1f2b70a942b8d858a0ab02567da3999b60a99b2
Author:     Robert Richter <[email protected]>
AuthorDate: Tue, 13 Apr 2010 22:23:15 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 7 May 2010 11:31:01 +0200

perf, x86: Use weight instead of cmask in for_each_event_constraint()

There may exist constraints with a cmask set to zero. In this case for_each_event_constraint() will not work properly. Now weight is used instead of the cmask for loop exit detection. Weight is always a value other than zero since the default contains the HWEIGHT from the counter mask and in other cases a value of zero does not fit too.

This is in preparation of ibs event constraints that wont have a cmask.

LKML-Reference: <[email protected]>

---
 arch/x86/kernel/cpu/perf_event.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/x86/kernel/cpu/perf_event.c +1 -1
index 4e218d7..4a3f1f2 100644
@@ -170,7 +170,7 @@ struct cpu_hw_events {
 	EVENT_CONSTRAINT(0, 0, 0)
 
 #define for_each_event_constraint(e, c)	\
-	for ((e) = (c); (e)->cmask; (e)++)
+	for ((e) = (c); (e)->weight; (e)++)
 
 union perf_capabilities {
 	struct {
#12 lore raw

PATCH 7/12 perf, x86: introduce bit range for special pmu events

In reply to Robert Richter

There are some pmu events such as Intel BTS or AMD IBS that do not fit in the generic or fixed performance counter scheme. The upper bits starting at bit 48 of the 64 bit counter mask are reserved for such events and can be used to handle them. The events can be identified by its index in the bit mask.

---
 arch/x86/include/asm/perf_event.h         |    3 ++-
 arch/x86/kernel/cpu/perf_event.c          |    6 +++---
 arch/x86/kernel/cpu/perf_event_intel.c    |   10 +++++-----
 arch/x86/kernel/cpu/perf_event_intel_ds.c |    4 ++--
 4 files changed, 12 insertions(+), 11 deletions(-)
arch/x86/include/asm/perf_event.h +2 -1
index f6d43db..9f10215 100644
@@ -10,6 +10,7 @@
 
 #define X86_PMC_IDX_GENERIC				        0
 #define X86_PMC_IDX_FIXED				       32
+#define X86_PMC_IDX_SPECIAL				       48
 #define X86_PMC_IDX_MAX					       64
 
 #define MSR_ARCH_PERFMON_PERFCTR0			      0xc1
@@ -107,7 +108,7 @@ union cpuid10_edx {
  * values are used by actual fixed events and higher values are used
  * to indicate other overflow conditions in the PERF_GLOBAL_STATUS msr.
  */
-#define X86_PMC_IDX_FIXED_BTS				(X86_PMC_IDX_FIXED + 16)
+#define X86_PMC_IDX_SPECIAL_BTS				(X86_PMC_IDX_SPECIAL + 0)
 
 /* IbsFetchCtl bits/masks */
 #define IBS_FETCH_RAND_EN		(1ULL<<57)
arch/x86/kernel/cpu/perf_event.c +3 -3
index feda380..2a7c2fc 100644
@@ -281,7 +281,7 @@ x86_perf_event_update(struct perf_event *event)
 	int idx = hwc->idx;
 	s64 delta;
 
-	if (idx == X86_PMC_IDX_FIXED_BTS)
+	if (idx == X86_PMC_IDX_SPECIAL_BTS)
 		return 0;
 
 	/*
@@ -758,7 +758,7 @@ static inline void x86_assign_hw_event(struct perf_event *event,
 	hwc->last_cpu = smp_processor_id();
 	hwc->last_tag = ++cpuc->tags[i];
 
-	if (hwc->idx == X86_PMC_IDX_FIXED_BTS) {
+	if (hwc->idx == X86_PMC_IDX_SPECIAL_BTS) {
 		hwc->config_base = 0;
 		hwc->event_base	= 0;
 	} else if (hwc->idx >= X86_PMC_IDX_FIXED) {
@@ -874,7 +874,7 @@ x86_perf_event_set_period(struct perf_event *event)
 	s64 period = hwc->sample_period;
 	int ret = 0, idx = hwc->idx;
 
-	if (idx == X86_PMC_IDX_FIXED_BTS)
+	if (idx == X86_PMC_IDX_SPECIAL_BTS)
 		return 0;
 
 	/*
arch/x86/kernel/cpu/perf_event_intel.c +5 -5
index a4b56ac..c7e6145 100644
@@ -458,7 +458,7 @@ static void intel_pmu_disable_all(void)
 
 	wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0);
 
-	if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask))
+	if (test_bit(X86_PMC_IDX_SPECIAL_BTS, cpuc->active_mask))
 		intel_pmu_disable_bts();
 
 	intel_pmu_pebs_disable_all();
@@ -473,9 +473,9 @@ static void intel_pmu_enable_all(int added)
 	intel_pmu_lbr_enable_all();
 	wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, x86_pmu.intel_ctrl);
 
-	if (test_bit(X86_PMC_IDX_FIXED_BTS, cpuc->active_mask)) {
+	if (test_bit(X86_PMC_IDX_SPECIAL_BTS, cpuc->active_mask)) {
 		struct perf_event *event =
-			cpuc->events[X86_PMC_IDX_FIXED_BTS];
+			cpuc->events[X86_PMC_IDX_SPECIAL_BTS];
 
 		if (WARN_ON_ONCE(!event))
 			return;
@@ -550,7 +550,7 @@ static void intel_pmu_disable_event(struct perf_event *event)
 {
 	struct hw_perf_event *hwc = &event->hw;
 
-	if (unlikely(hwc->idx == X86_PMC_IDX_FIXED_BTS)) {
+	if (unlikely(hwc->idx == X86_PMC_IDX_SPECIAL_BTS)) {
 		intel_pmu_disable_bts();
 		intel_pmu_drain_bts_buffer();
 		return;
@@ -602,7 +602,7 @@ static void intel_pmu_enable_event(struct perf_event *event)
 {
 	struct hw_perf_event *hwc = &event->hw;
 
-	if (unlikely(hwc->idx == X86_PMC_IDX_FIXED_BTS)) {
+	if (unlikely(hwc->idx == X86_PMC_IDX_SPECIAL_BTS)) {
 		if (!__get_cpu_var(cpu_hw_events).enabled)
 			return;
 
arch/x86/kernel/cpu/perf_event_intel_ds.c +2 -2
index ec8b2e1..e49a68a 100644
@@ -176,7 +176,7 @@ static int reserve_ds_buffers(void)
  */
 
 static struct event_constraint bts_constraint =
-	EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_FIXED_BTS, 0);
+	EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_SPECIAL_BTS, 0);
 
 static void intel_pmu_enable_bts(u64 config)
 {
@@ -223,7 +223,7 @@ static void intel_pmu_drain_bts_buffer(void)
 		u64	to;
 		u64	flags;
 	};
-	struct perf_event *event = cpuc->events[X86_PMC_IDX_FIXED_BTS];
+	struct perf_event *event = cpuc->events[X86_PMC_IDX_SPECIAL_BTS];
 	struct bts_record *at, *top;
 	struct perf_output_handle handle;
 	struct perf_event_header header;
Signature · 1 line
1.7.0.3
#13 lore raw

PATCH 8/12 perf, x86: modify some code to allow the introduction of ibs events

In reply to Robert Richter

The changes are needed to introduce ibs events that are implemented as special x86 events.

---
 arch/x86/kernel/cpu/perf_event.c |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)
arch/x86/kernel/cpu/perf_event.c +9 -9
index 2a7c2fc..67b99a9 100644
@@ -281,7 +281,7 @@ x86_perf_event_update(struct perf_event *event)
 	int idx = hwc->idx;
 	s64 delta;
 
-	if (idx == X86_PMC_IDX_SPECIAL_BTS)
+	if (idx >= X86_PMC_IDX_SPECIAL)
 		return 0;
 
 	/*
@@ -758,10 +758,10 @@ static inline void x86_assign_hw_event(struct perf_event *event,
 	hwc->last_cpu = smp_processor_id();
 	hwc->last_tag = ++cpuc->tags[i];
 
-	if (hwc->idx == X86_PMC_IDX_SPECIAL_BTS) {
-		hwc->config_base = 0;
-		hwc->event_base	= 0;
-	} else if (hwc->idx >= X86_PMC_IDX_FIXED) {
+	if (hwc->idx < X86_PMC_IDX_FIXED) {
+		hwc->config_base = x86_pmu.eventsel;
+		hwc->event_base  = x86_pmu.perfctr;
+	} else if (hwc->idx < X86_PMC_IDX_SPECIAL) {
 		hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL;
 		/*
 		 * We set it so that event_base + idx in wrmsr/rdmsr maps to
@@ -769,9 +769,9 @@ static inline void x86_assign_hw_event(struct perf_event *event,
 		 */
 		hwc->event_base =
 			MSR_ARCH_PERFMON_FIXED_CTR0 - X86_PMC_IDX_FIXED;
-	} else {
-		hwc->config_base = x86_pmu.eventsel;
-		hwc->event_base  = x86_pmu.perfctr;
+	} else if (hwc->idx == X86_PMC_IDX_SPECIAL_BTS) {
+		hwc->config_base = 0;
+		hwc->event_base	= 0;
 	}
 }
 
@@ -874,7 +874,7 @@ x86_perf_event_set_period(struct perf_event *event)
 	s64 period = hwc->sample_period;
 	int ret = 0, idx = hwc->idx;
 
-	if (idx == X86_PMC_IDX_SPECIAL_BTS)
+	if (idx >= X86_PMC_IDX_SPECIAL_BTS)
 		return 0;
 
 	/*
Signature · 1 line
1.7.0.3
#14 lore raw

PATCH 9/12 perf, x86: implement IBS feature detection

In reply to Robert Richter

The new code checks if IBS is available on the cpu. It implements only a basic detection that should be later extended to read ibs cpuid feature flags.

---
 arch/x86/kernel/cpu/perf_event.c     |    5 +++++
 arch/x86/kernel/cpu/perf_event_amd.c |    2 ++
 2 files changed, 7 insertions(+), 0 deletions(-)
arch/x86/kernel/cpu/perf_event.c +5 -0
index 67b99a9..a42d033 100644
@@ -242,6 +242,11 @@ struct x86_pmu {
 	 */
 	unsigned long	lbr_tos, lbr_from, lbr_to; /* MSR base regs       */
 	int		lbr_nr;			   /* hardware stack size */
+
+	/*
+	 * AMD IBS
+	 */
+	int		ibs;			/* cpuid flags */
 };
 
 static struct x86_pmu x86_pmu __read_mostly;
arch/x86/kernel/cpu/perf_event_amd.c +2 -0
index 611df11..246304d 100644
@@ -402,6 +402,8 @@ static __init int amd_pmu_init(void)
 		return -ENODEV;
 
 	x86_pmu = amd_pmu;
+	if (boot_cpu_has(X86_FEATURE_IBS))
+		x86_pmu.ibs = 1;
 
 	/* Events are common for all AMDs */
 	memcpy(hw_cache_event_ids, amd_hw_cache_event_ids,
Signature · 1 line
1.7.0.3
#15 lore raw

PATCH 10/12 perf, x86: setup NMI handler for IBS

In reply to Robert Richter

This implements the perf nmi handler for ibs interrupts. The code was copied from oprofile and should be merged somewhen.

---
 arch/x86/kernel/cpu/perf_event.c     |   10 ++++
 arch/x86/kernel/cpu/perf_event_amd.c |   87 ++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+), 0 deletions(-)
arch/x86/kernel/cpu/perf_event.c +10 -0
index a42d033..8f9674f 100644
@@ -383,12 +383,15 @@ static void release_pmc_hardware(void) {}
 
 static int reserve_ds_buffers(void);
 static void release_ds_buffers(void);
+static int reserve_ibs_hardware(void);
+static void release_ibs_hardware(void);
 
 static void hw_perf_event_destroy(struct perf_event *event)
 {
 	if (atomic_dec_and_mutex_lock(&active_events, &pmc_reserve_mutex)) {
 		release_pmc_hardware();
 		release_ds_buffers();
+		release_ibs_hardware();
 		mutex_unlock(&pmc_reserve_mutex);
 	}
 }
@@ -537,6 +540,13 @@ static int __hw_perf_event_init(struct perf_event *event)
 				if (err)
 					release_pmc_hardware();
 			}
+			if (!err) {
+				err = reserve_ibs_hardware();
+				if (err) {
+					release_ds_buffers();
+					release_pmc_hardware();
+				}
+			}
 		}
 		if (!err)
 			atomic_inc(&active_events);
arch/x86/kernel/cpu/perf_event_amd.c +87 -0

98 lines not on this page · raw message

Signature · 1 line
1.7.0.3
maintainer
#16 lore raw

Re: [PATCH 10/12] perf, x86: setup NMI handler for IBS

Quoted 48 lines · Robert Richter

This implements the perf nmi handler for ibs interrupts. The code was copied from oprofile and should be merged somewhen.

---
 arch/x86/kernel/cpu/perf_event.c     |   10 ++++
 arch/x86/kernel/cpu/perf_event_amd.c |   87 ++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+), 0 deletions(-)
arch/x86/kernel/cpu/perf_event.c +34 -0
index a42d033..8f9674f 100644
 
+static int init_ibs_nmi(void)
+{
+#define IBSCTL_LVTOFFSETVAL		(1 << 8)
+#define IBSCTL				0x1cc
+	struct pci_dev *cpu_cfg;
+	int nodes;
+	u32 value = 0;
+
+	/* per CPU setup */
+	on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1);
+
+	nodes = 0;
+	cpu_cfg = NULL;
+	do {
+		cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD,
+					 PCI_DEVICE_ID_AMD_10H_NB_MISC,
+					 cpu_cfg);
+		if (!cpu_cfg)
+			break;
+		++nodes;
+		pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
+				       | IBSCTL_LVTOFFSETVAL);
+		pci_read_config_dword(cpu_cfg, IBSCTL, &value);
+		if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) {
+			pci_dev_put(cpu_cfg);
+			printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
+				"IBSCTL = 0x%08x", value);
+			return 1;
+		}
+	} while (1);
+
+	if (!nodes) {
+		printk(KERN_DEBUG "No CPU node configured for IBS");
+		return 1;

arch/x86/kernel/cpu/perf_event.c

Quoted 10 lines
arch/x86/kernel/cpu/perf_event.c +10 -0
+	}
+
+	return 0;
+}
+
+/* uninitialize the APIC for the IBS interrupts if needed */
+static void clear_ibs_nmi(void)
+{
+	on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1);
+}

That on_each_cpu() looks wonky, why isn't this in the hotplug hooks?

#17 lore raw

Re: [PATCH 10/12] perf, x86: setup NMI handler for IBS

Quoted 8 lines · Peter Zijlstra

arch/x86/kernel/cpu/perf_event_amd.c static const u64 amd_perfmon_event_map[] = · line 170

Quoted 5 lines
arch/x86/kernel/cpu/perf_event_amd.c +5 -0
+/* uninitialize the APIC for the IBS interrupts if needed */
+static void clear_ibs_nmi(void)
+{
+	on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1);
+}

That on_each_cpu() looks wonky, why isn't this in the hotplug hooks?

Right, it should be there. Will update this patch.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#18 lore raw

Re: [PATCH 10/12] perf, x86: setup NMI handler for IBS

Quoted 11 lines · Robert Richter
Quoted 8 lines · Peter Zijlstra

Review

Quoted 5 lines
(quoted diff) +5 -0
+/* uninitialize the APIC for the IBS interrupts if needed */
+static void clear_ibs_nmi(void)
+{
+	on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1);
+}

That on_each_cpu() looks wonky, why isn't this in the hotplug hooks?

Right, it should be there. Will update this patch.

Peter,

please see my updated version below.

-Robert

---

Quoted 1 line

From bcb2c4aec6bf09fc7c05f31dde9dacd57b9c679c Mon Sep 17 00:00:00 2001

From: Robert Richter <[email protected]>
Date: Mon, 19 Apr 2010 15:32:37 +0200
Subject: [PATCH] perf, x86: setup NMI handler for IBS

This implements the perf nmi handler for ibs interrupts. The code was copied from oprofile and should be merged somewhen.

---
 arch/x86/kernel/cpu/perf_event.c     |    5 ++
 arch/x86/kernel/cpu/perf_event_amd.c |   85 ++++++++++++++++++++++++++++++++++
 2 files changed, 90 insertions(+), 0 deletions(-)
arch/x86/kernel/cpu/perf_event.c +5 -0
index 940107f..0ad8c45 100644
@@ -516,6 +516,8 @@ static int x86_pmu_hw_config(struct perf_event *event)
 	return x86_setup_perfctr(event);
 }
 
+static inline void init_ibs_nmi(void);
+
 /*
  * Setup the hardware configuration for a given attr_type
  */
@@ -537,6 +539,8 @@ static int __hw_perf_event_init(struct perf_event *event)
 				if (err)
 					release_pmc_hardware();
 			}
+			if (!err)
+				init_ibs_nmi();
 		}
 		if (!err)
 			atomic_inc(&active_events);
@@ -1381,6 +1385,7 @@ static void __init pmu_check_apic(void)
 		return;
 
 	x86_pmu.apic = 0;
+	x86_pmu.ibs = 0;
 	pr_info("no APIC, boot with the \"lapic\" boot parameter to force-enable it.\n");
 	pr_info("no hardware sampling interrupt available.\n");
 }
arch/x86/kernel/cpu/perf_event_amd.c +85 -0

108 lines not on this page · raw message

Signature · 6 lines
1.7.0.3

-- 
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#19 lore raw

PATCH 11/12 perf, x86: implement AMD IBS event configuration

In reply to Robert Richter

This patch implements IBS for perf_event. It extends the AMD pmu to handle model specific IBS events.

With the attr.model_spec bit set we can setup hardware events others than generic performance counters. A special PMU 64 bit config value can be passed through the perf_event interface. The concept of PMU model-specific arguments was practiced already in Perfmon2. The type of event (8 bits) is determinded from the config value too, bit 32-39 are reserved for this.

There are two types of IBS events for instruction fetch (IBS_FETCH) and instruction execution (IBS_OP). Both events are implemented as special x86 events. The event allocation is implemented by using special event constraints for ibs. This way, the generic event scheduler can be used to allocate ibs events.

IBS can only be set up with raw (model specific) config values and raw data samples. The event attributes for the syscall should be programmed like this (IBS_FETCH):

        memset(&attr, 0, sizeof(attr));
        attr.type        = PERF_TYPE_RAW;
        attr.sample_type = PERF_SAMPLE_CPU | PERF_SAMPLE_RAW;
        attr.config      = IBS_FETCH_CONFIG_DEFAULT
        attr.config     |=
                ((unsigned long long)MODEL_SPEC_TYPE_IBS_FETCH << 32)
                & MODEL_SPEC_TYPE_MASK;
        attr.model_spec  = 1;

The whole ibs example will be part of libpfm4.

The next patch implements the ibs interrupt handler.

Cc Stephane Eranian <[email protected]>
---
 arch/x86/include/asm/perf_event.h    |    4 +-
 arch/x86/kernel/cpu/perf_event.c     |   20 ++++
 arch/x86/kernel/cpu/perf_event_amd.c |  161 ++++++++++++++++++++++++++++++++-
 3 files changed, 179 insertions(+), 6 deletions(-)
arch/x86/include/asm/perf_event.h +3 -1
index 9f10215..fd5c326 100644
@@ -102,13 +102,15 @@ union cpuid10_edx {
 #define X86_PMC_IDX_FIXED_BUS_CYCLES			(X86_PMC_IDX_FIXED + 2)
 
 /*
- * We model BTS tracing as another fixed-mode PMC.
+ * Masks for special PMU features
  *
  * We choose a value in the middle of the fixed event range, since lower
  * values are used by actual fixed events and higher values are used
  * to indicate other overflow conditions in the PERF_GLOBAL_STATUS msr.
  */
 #define X86_PMC_IDX_SPECIAL_BTS				(X86_PMC_IDX_SPECIAL + 0)
+#define X86_PMC_IDX_SPECIAL_IBS_FETCH			(X86_PMC_IDX_SPECIAL + 1)
+#define X86_PMC_IDX_SPECIAL_IBS_OP			(X86_PMC_IDX_SPECIAL + 2)
 
 /* IbsFetchCtl bits/masks */
 #define IBS_FETCH_RAND_EN		(1ULL<<57)
arch/x86/kernel/cpu/perf_event.c +20 -0
index 8f9674f..e2328f4 100644
@@ -184,6 +184,26 @@ union perf_capabilities {
 };
 
 /*
+ * Model specific hardware events
+ *
+ * With the attr.model_spec bit set we can setup hardware events
+ * others than generic performance counters. A special PMU 64 bit
+ * config value can be passed through the perf_event interface. The
+ * concept of PMU model-specific arguments was practiced already in
+ * Perfmon2. The type of event (8 bits) is determinded from the config
+ * value too, bit 32-39 are reserved for this.
+ */
+#define MODEL_SPEC_TYPE_IBS_FETCH	0
+#define MODEL_SPEC_TYPE_IBS_OP		1
+
+#define MODEL_SPEC_TYPE_MASK		(0xFFULL << 32)
+
+static inline int get_model_spec_type(u64 config)
+{
+	return (config & MODEL_SPEC_TYPE_MASK) >> 32;
+}
+
+/*
  * struct x86_pmu - generic x86 pmu
  */
 struct x86_pmu {
arch/x86/kernel/cpu/perf_event_amd.c +156 -5

207 lines not on this page · raw message

Signature · 1 line
1.7.0.3
#20 lore raw

Re: [PATCH 11/12] perf, x86: implement AMD IBS event configuration

Comments below:

Quoted 135 lines · Robert Richter

This patch implements IBS for perf_event. It extends the AMD pmu to handle model specific IBS events.

With the attr.model_spec bit set we can setup hardware events others than generic performance counters. A special PMU 64 bit config value can be passed through the perf_event interface. The concept of PMU model-specific arguments was practiced already in Perfmon2. The type of event (8 bits) is determinded from the config value too, bit 32-39 are reserved for this.

There are two types of IBS events for instruction fetch (IBS_FETCH) and instruction execution (IBS_OP). Both events are implemented as special x86 events. The event allocation is implemented by using special event constraints for ibs. This way, the generic event scheduler can be used to allocate ibs events.

IBS can only be set up with raw (model specific) config values and raw data samples. The event attributes for the syscall should be programmed like this (IBS_FETCH):

       memset(&attr, 0, sizeof(attr));
       attr.type        = PERF_TYPE_RAW;
       attr.sample_type = PERF_SAMPLE_CPU | PERF_SAMPLE_RAW; attr.config      = IBS_FETCH_CONFIG_DEFAULT attr.config     |=
               ((unsigned long long)MODEL_SPEC_TYPE_IBS_FETCH << 32) & MODEL_SPEC_TYPE_MASK;
       attr.model_spec  = 1;

The whole ibs example will be part of libpfm4.

The next patch implements the ibs interrupt handler.

Cc Stephane Eranian <[email protected]>

---
 arch/x86/include/asm/perf_event.h    |    4 +- arch/x86/kernel/cpu/perf_event.c     |   20 ++++ arch/x86/kernel/cpu/perf_event_amd.c |  161 ++++++++++++++++++++++++++++++++-

 3 files changed, 179 insertions(+), 6 deletions(-)
arch/x86/include/asm/perf_event.h +3 -1
index 9f10215..fd5c326 100644
@@ -102,13 +102,15 @@ union cpuid10_edx {
  #define X86_PMC_IDX_FIXED_BUS_CYCLES                   (X86_PMC_IDX_FIXED + 2)
 
  /*
- * We model BTS tracing as another fixed-mode PMC.
+ * Masks for special PMU features
  *
  * We choose a value in the middle of the fixed event range, since lower
  * values are used by actual fixed events and higher values are used
  * to indicate other overflow conditions in the PERF_GLOBAL_STATUS msr.
  */
  #define X86_PMC_IDX_SPECIAL_BTS                                (X86_PMC_IDX_SPECIAL + 0)
+#define X86_PMC_IDX_SPECIAL_IBS_FETCH                  (X86_PMC_IDX_SPECIAL + 1)
+#define X86_PMC_IDX_SPECIAL_IBS_OP                     (X86_PMC_IDX_SPECIAL + 2)
 
  /* IbsFetchCtl bits/masks */
  #define IBS_FETCH_RAND_EN              (1ULL<<57)
arch/x86/kernel/cpu/perf_event.c +20 -0
index 8f9674f..e2328f4 100644
@@ -184,6 +184,26 @@ union perf_capabilities {
  };
 
  /*
+ * Model specific hardware events
+ *
+ * With the attr.model_spec bit set we can setup hardware events
+ * others than generic performance counters. A special PMU 64 bit
+ * config value can be passed through the perf_event interface. The
+ * concept of PMU model-specific arguments was practiced already in
+ * Perfmon2. The type of event (8 bits) is determinded from the config
+ * value too, bit 32-39 are reserved for this.
+ */
+#define MODEL_SPEC_TYPE_IBS_FETCH      0
+#define MODEL_SPEC_TYPE_IBS_OP         1
+
+#define MODEL_SPEC_TYPE_MASK           (0xFFULL << 32)
+
+static inline int get_model_spec_type(u64 config)
+{
+       return (config & MODEL_SPEC_TYPE_MASK) >> 32;
+}
+
+/*
  * struct x86_pmu - generic x86 pmu
  */
  struct x86_pmu {
arch/x86/kernel/cpu/perf_event_amd.c +4 -0
index 27daead..3dc327c 100644
@@ -2,6 +2,10 @@
 
  #include <linux/pci.h>
 
+#define IBS_FETCH_CONFIG_MASK  (IBS_FETCH_RAND_EN | IBS_FETCH_MAX_CNT)
+#define IBS_OP_CONFIG_MASK     (IBS_OP_CNT_CTL | IBS_OP_MAX_CNT)
+#define AMD64_NUM_COUNTERS     4
+
  static DEFINE_RAW_SPINLOCK(amd_nb_lock);
 

 static __initconst const u64 amd_hw_cache_event_ids

arch/x86/kernel/cpu/perf_event_amd.c +23 -0
@@ -193,6 +197,118 @@ static void release_ibs_hardware(void)
        clear_ibs_nmi();
  }
 
+static inline void amd_pmu_disable_ibs(void)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       u64 val;
+
+       if (test_bit(X86_PMC_IDX_SPECIAL_IBS_FETCH, cpuc->active_mask)) {
+               rdmsrl(MSR_AMD64_IBSFETCHCTL, val);
+               val &= ~IBS_FETCH_ENABLE;
+               wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
+       }
+       if (test_bit(X86_PMC_IDX_SPECIAL_IBS_OP, cpuc->active_mask)) {
+               rdmsrl(MSR_AMD64_IBSOPCTL, val);
+               val &= ~IBS_OP_ENABLE;
+               wrmsrl(MSR_AMD64_IBSOPCTL, val);
+       }
+}
+
+static inline void amd_pmu_enable_ibs(void)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       u64 val;
+
+       if (test_bit(X86_PMC_IDX_SPECIAL_IBS_FETCH, cpuc->active_mask)) {

arch/x86/kernel/cpu/perf_event_amd.c static void release_ibs_hardware(void) · line 232

Quoted 10 lines
arch/x86/kernel/cpu/perf_event_amd.c +10 -0
+               rdmsrl(MSR_AMD64_IBSFETCHCTL, val);
+               val |= IBS_FETCH_ENABLE;
+               wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
+       }
+       if (test_bit(X86_PMC_IDX_SPECIAL_IBS_OP, cpuc->active_mask)) {
+               rdmsrl(MSR_AMD64_IBSOPCTL, val);
+               val |= IBS_OP_ENABLE;
+               wrmsrl(MSR_AMD64_IBSOPCTL, val);
+       }
+}

Aren't you picking up stale state by using read-modify-write here?

Quoted 7 lines
arch/x86/kernel/cpu/perf_event_amd.c +7 -0
+
+static int amd_pmu_ibs_config(struct perf_event *event)
+{
+       int type;
+
+       if (!x86_pmu.ibs)
+               return -ENODEV;

arch/x86/kernel/cpu/perf_event_amd.c static void release_ibs_hardware(void) · line 249

Quoted 10 lines
arch/x86/kernel/cpu/perf_event_amd.c +10 -0
+
+       if (event->hw.sample_period)
+               /*
+                * The usage of the sample period attribute to
+                * calculate the IBS max count value is not yet
+                * supported, the max count must be in the raw config
+                * value.
+                */
+               return -ENOSYS;
+

What is the problem with directly using the period here, rejecting any value that is off range or with bottom 4 bits set?

Quoted 11 lines
arch/x86/kernel/cpu/perf_event_amd.c +11 -0
+       if (event->attr.type != PERF_TYPE_RAW)
+               /* only raw sample types are supported */
+               return -EINVAL;
+
+       type = get_model_spec_type(event->attr.config);
+       switch (type) {
+       case MODEL_SPEC_TYPE_IBS_FETCH:
+               event->hw.config = IBS_FETCH_CONFIG_MASK & event->attr.config;
+               event->hw.idx = X86_PMC_IDX_SPECIAL_IBS_FETCH;
+               /*
+                * dirty hack, needed for __x86_pmu_enable_event(), we

arch/x86/kernel/cpu/perf_event_amd.c static void release_ibs_hardware(void) · line 270

Quoted 10 lines
arch/x86/kernel/cpu/perf_event_amd.c +10 -0
+                * should better change event->hw.config_base into
+                * event->hw.config_msr that already includes the index
+                */
+               event->hw.config_base = MSR_AMD64_IBSFETCHCTL - event->hw.idx;
+               break;
+       case MODEL_SPEC_TYPE_IBS_OP:
+               event->hw.config = IBS_OP_CONFIG_MASK & event->attr.config;
+               event->hw.idx = X86_PMC_IDX_SPECIAL_IBS_OP;
+               event->hw.config_base = MSR_AMD64_IBSOPCTL - event->hw.idx;
+               break;

IBSOP.cnt_ctl only available from RevC, need to check and reject if older.

Quoted 68 lines
arch/x86/kernel/cpu/perf_event_amd.c +53 -1
+       default:
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static inline void __amd_pmu_enable_ibs_event(struct hw_perf_event *hwc)
+{
+       if (hwc->idx == X86_PMC_IDX_SPECIAL_IBS_FETCH)
+               __x86_pmu_enable_event(hwc, IBS_FETCH_ENABLE);
+       else if (hwc->idx == X86_PMC_IDX_SPECIAL_IBS_OP)
+               __x86_pmu_enable_event(hwc, IBS_OP_ENABLE);
+}
+
+static void amd_pmu_disable_all(void)
+{
+       x86_pmu_disable_all();
+       amd_pmu_disable_ibs();
+}
+
+static void amd_pmu_enable_all(int added)
+{
+       x86_pmu_enable_all(added);
+       amd_pmu_enable_ibs();
+}
+
+static void amd_pmu_enable_event(struct perf_event *event)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!cpuc->enabled)
+               return;
+
+       if (hwc->idx < X86_PMC_IDX_SPECIAL)
+               __x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE);
+       else
+               __amd_pmu_enable_ibs_event(hwc);
+}
+
  static u64 amd_pmu_event_map(int hw_event)
  {
        return amd_perfmon_event_map[hw_event];
@@ -200,7 +316,12 @@ static u64 amd_pmu_event_map(int hw_event)
 
  static int amd_pmu_hw_config(struct perf_event *event)
  {
-       int ret = x86_pmu_hw_config(event);
+       int ret;
+
+       if (event->attr.model_spec)
+               return amd_pmu_ibs_config(event);
+
+       ret = x86_pmu_hw_config(event);
 
        if (ret)
                return ret;
@@ -214,6 +335,23 @@ static int amd_pmu_hw_config(struct perf_event *event)
  }
 
  /*
+ * AMD64 events - list of special events (IBS)
+ */
+static struct event_constraint amd_event_constraints[] =
+{
+       /*
+        * The value for the weight of these constraints is higher

arch/x86/kernel/cpu/perf_event_amd.c static int amd_pmu_hw_config(struct perf_event *event) · line 353

Quoted 10 lines
arch/x86/kernel/cpu/perf_event_amd.c +10 -0
+        * than in the unconstrainted case to process ibs after the
+        * generic counters in x86_schedule_events().
+        */
+       __EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_SPECIAL_IBS_FETCH, 0,
+                          AMD64_NUM_COUNTERS + 1),
+       __EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_SPECIAL_IBS_OP, 0,
+                          AMD64_NUM_COUNTERS + 1),
+       EVENT_CONSTRAINT_END
+};
+

I think you could define EVENT_IBS_CONSTRAINT() and shorten
the definitions here. You could pass FETCH or OP and the macro would do the bit shifting. This is how it's done for fixed counters on Intel.

#21 lore raw

Re: [PATCH 11/12] perf, x86: implement AMD IBS event configuration

Quoted 27 lines · Stephane Eranian
Quoted 27 lines
arch/x86/kernel/cpu/perf_event_amd.c +27 -0
+static inline void amd_pmu_disable_ibs(void)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       u64 val;
+
+       if (test_bit(X86_PMC_IDX_SPECIAL_IBS_FETCH, cpuc->active_mask)) {
+               rdmsrl(MSR_AMD64_IBSFETCHCTL, val);
+               val &= ~IBS_FETCH_ENABLE;
+               wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
+       }
+       if (test_bit(X86_PMC_IDX_SPECIAL_IBS_OP, cpuc->active_mask)) {
+               rdmsrl(MSR_AMD64_IBSOPCTL, val);
+               val &= ~IBS_OP_ENABLE;
+               wrmsrl(MSR_AMD64_IBSOPCTL, val);
+       }
+}
+
+static inline void amd_pmu_enable_ibs(void)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       u64 val;
+
+       if (test_bit(X86_PMC_IDX_SPECIAL_IBS_FETCH, cpuc->active_mask)) {
+               rdmsrl(MSR_AMD64_IBSFETCHCTL, val);
+               val |= IBS_FETCH_ENABLE;
+               wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
+       }
Quoted 8 lines
Quoted 6 lines

+       if (test_bit(X86_PMC_IDX_SPECIAL_IBS_OP, cpuc->active_mask)) {
+               rdmsrl(MSR_AMD64_IBSOPCTL, val);
+               val |= IBS_OP_ENABLE;
+               wrmsrl(MSR_AMD64_IBSOPCTL, val);
+       }
+}

Aren't you picking up stale state by using read-modify-write here?

Hmm, there is a reason for this implementation. Both functions are only used in .enable_all() and .disable_all() which was originally used in atomic sections to disable NMIs during event scheduling and setup. For this short switch off of the pmu the register state is not saved. On Intel this is implemented by only writing to MSR_CORE_PERF_GLOBAL_CTRL. The proper way to enable events is to use amd_pmu_enable_event() which is x86_pmu.enable(event).

Locking at the latest sources this might have changed a little in between and we have to check that this functions above are not used to enable events. So I am not really sure if the register may be setup wrong. But if this happens, then only for the first sample after enabling or reenabling of the whole pmu since the interrupt handler is using __x86_pmu_enable_event() to reenable ibs. Thus I would prever the implementation above and instead reimplement the nmi handling (see below).

Also, We should avoid a global pmu disable generally since it is expensive and also the pmu state may not be restored properly for some events on some hw revisions. But the code must then be atomic.

An alternative solution to disable NMIs on AMD could be to mask the nmi by writing to the lapic instead of the counter msrs. This could be more efficient and the pmu will go on with sampling without the need to restore the state. Or this way: the interrupt handler does not handle events and only clears the reason if some 'atomic' flag is set?

IMHO I think, also the implementation for x86_pmu_enable_all() and x86_pmu_disable_all() is not accurate, since the state is not stored when disabling all counters and then reenabling it with the init value. On Intel counters this is without impact since the global ctrl msr is used. In all other cases x86_pmu_enable_all() does not restore the previous counter state.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#22 lore raw

Re: [PATCH 11/12] perf, x86: implement AMD IBS event configuration

In reply to Stephane Eranian
Quoted 11 lines · Stephane Eranian
Quoted 9 lines

+       if (event->hw.sample_period)
+               /*
+                * The usage of the sample period attribute to
+                * calculate the IBS max count value is not yet
+                * supported, the max count must be in the raw config
+                * value.
+                */
+               return -ENOSYS;
+

What is the problem with directly using the period here, rejecting any value that is off range or with bottom 4 bits set?

Yes, I will create an updated version of this patch.

Quoted 22 lines
Quoted 13 lines

+       if (event->attr.type != PERF_TYPE_RAW)
+               /* only raw sample types are supported */
+               return -EINVAL;
+
+       type = get_model_spec_type(event->attr.config);
+       switch (type) {
+       case MODEL_SPEC_TYPE_IBS_FETCH:
+               event->hw.config = IBS_FETCH_CONFIG_MASK & event->attr.config;
+               event->hw.idx = X86_PMC_IDX_SPECIAL_IBS_FETCH;
+               /*
+                * dirty hack, needed for __x86_pmu_enable_event(), we
+                * should better change event->hw.config_base into
+                * event->hw.config_msr that already includes the index

Quoted 8 lines

+                */
+               event->hw.config_base = MSR_AMD64_IBSFETCHCTL - event->hw.idx;
+               break;
+       case MODEL_SPEC_TYPE_IBS_OP:
+               event->hw.config = IBS_OP_CONFIG_MASK & event->attr.config;
+               event->hw.idx = X86_PMC_IDX_SPECIAL_IBS_OP;
+               event->hw.config_base = MSR_AMD64_IBSOPCTL - event->hw.idx;
+               break;

Quoted 1 line

IBSOP.cnt_ctl only available from RevC, need to check and reject if older.

Right, for this patch I will modify IBS_OP_CONFIG_MASK to RevB only bits, later I will add cpuid detection and pmu revision checks in a separate patch.

Quoted 9 lines
Quoted 9 lines
arch/x86/kernel/cpu/perf_event_amd.c +9 -0
+static struct event_constraint amd_event_constraints[] =
+{
+       /*
+        * The value for the weight of these constraints is higher
+        * than in the unconstrainted case to process ibs after the
+        * generic counters in x86_schedule_events().
+        */
+       __EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_SPECIAL_IBS_FETCH, 0,
+                          AMD64_NUM_COUNTERS + 1),
Quoted 8 lines

arch/x86/kernel/cpu/perf_event_amd.c static int amd_pmu_hw_config(struct perf_event *event) · line 353

Quoted 5 lines

+       __EVENT_CONSTRAINT(0, 1ULL << X86_PMC_IDX_SPECIAL_IBS_OP, 0,
+                          AMD64_NUM_COUNTERS + 1),
+       EVENT_CONSTRAINT_END

arch/x86/kernel/cpu/perf_event_amd.c +2 -0
+};
+

I think you could define EVENT_IBS_CONSTRAINT() and shorten
the definitions here. You could pass FETCH or OP and the macro would do the bit shifting. This is how it's done for fixed counters on Intel.

Ok, I will update this.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#23 lore raw

Re: [PATCH 11/12] perf, x86: implement AMD IBS event configuration

Quoted 4 lines · Robert Richter
Quoted 2 lines

What is the problem with directly using the period here, rejecting any value that is off range or with bottom 4 bits set?

Yes, I will create an updated version of this patch.

Stephane, do you think having the lower 4 bits set is worth an EINVAL? I would rather ignore them since the accuracy is not really necessary compared to a range lets say from 100000 cycles? Otherwise this will make the setup of ibs much more complicated. The check could be moved to userland and generate a waring or so.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#24 lore raw

Re: [PATCH 11/12] perf, x86: implement AMD IBS event configuration

Quoted 11 lines · Robert Richter
Quoted 4 lines · Robert Richter
Quoted 2 lines

What is the problem with directly using the period here, rejecting any value that is off range or with bottom 4 bits set?

Yes, I will create an updated version of this patch.

Stephane, do you think having the lower 4 bits set is worth an EINVAL? I would rather ignore them since the accuracy is not really necessary compared to a range lets say from 100000 cycles? Otherwise this will make the setup of ibs much more complicated. The check could be moved to userland and generate a waring or so.

Explain why you think it would be more complicated? If I recall there is already a function to validate the attrs:
amd_pmu_hw_config().
But may be you are talking about userland setup.

Here is one argument why this might be important. Some people like to know exactly
the sampling period because they use a particular value, like a prime number. You
chopping off the bottom 4 bits could break this logic silently.

#25 lore raw

Re: [PATCH 11/12] perf, x86: implement AMD IBS event configuration

Quoted 18 lines · Stephane Eranian
Quoted 11 lines · Robert Richter
Quoted 4 lines · Robert Richter
Quoted 2 lines

What is the problem with directly using the period here, rejecting any value that is off range or with bottom 4 bits set?

Yes, I will create an updated version of this patch.

Stephane, do you think having the lower 4 bits set is worth an EINVAL? I would rather ignore them since the accuracy is not really necessary compared to a range lets say from 100000 cycles? Otherwise this will make the setup of ibs much more complicated. The check could be moved to userland and generate a waring or so.

Explain why you think it would be more complicated? If I recall there is already a function to validate the attrs:
amd_pmu_hw_config().
But may be you are talking about userland setup.

Quoted 5 lines

Here is one argument why this might be important. Some people like to know exactly
the sampling period because they use a particular value, like a prime number. You
chopping off the bottom 4 bits could break this logic silently.

Ok, I see your point. I was thinking of some decimal value used to set the sample period. You will then have to check if the lower 4 bits are set or not by doing a dec to hex conversion and so on. But I realized that multiples of 10000 can be devided by 16 and thus all lower 4 bits are always cleared.

So, I will check the lower 4 bits and return an error if they are set.

Thanks,

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#26 lore raw

Re: [PATCH 11/12] perf, x86: implement AMD IBS event configuration

Quoted 7 lines · Robert Richter
Quoted 6 lines · Stephane Eranian
Quoted 5 lines · Robert Richter
Quoted 4 lines · Robert Richter
Quoted 2 lines

What is the problem with directly using the period here, rejecting any value that is off range or with bottom 4 bits set?

Yes, I will create an updated version of this patch.

Stephane,

please see my updated version below.

-Robert

--

Quoted 1 line

From 79738167383838eb93f0388f8b7983fe822b36c4 Mon Sep 17 00:00:00 2001

From: Robert Richter <[email protected]>
Date: Wed, 21 Apr 2010 12:43:20 +0200
Subject: [PATCH] perf, x86: implement AMD IBS event configuration

This patch implements IBS for perf_event. It extends the AMD pmu to handle model specific IBS events.

With the attr.model_spec bit set we can setup hardware events others than generic performance counters. A special PMU 64 bit config value can be passed through the perf_event interface. The concept of PMU model-specific arguments was practiced already in Perfmon2. The type of event (8 bits) is determinded from the config value too, bit 32-39 are reserved for this.

There are two types of IBS events for instruction fetch (IBS_FETCH) and instruction execution (IBS_OP). Both events are implemented as special x86 events. The event allocation is implemented by using special event constraints for ibs. This way, the generic event scheduler can be used to allocate ibs events.

Except for the sample period IBS can only be set up with raw (model specific) config values and raw data samples. The event attributes for the syscall should be programmed like this (IBS_FETCH):

        memset(&attr, 0, sizeof(attr));
        attr.type        = PERF_TYPE_RAW;
        attr.sample_type = PERF_SAMPLE_CPU | PERF_SAMPLE_RAW;
        attr.config      = IBS_FETCH_CONFIG_DEFAULT
        attr.config     |=
                ((unsigned long long)MODEL_SPEC_TYPE_IBS_FETCH << 32)
                & MODEL_SPEC_TYPE_MASK;
        attr.model_spec  = 1;

The whole ibs example will be part of libpfm4.

The ibs interrupt handle is implemented in the next patch.

Cc Stephane Eranian <[email protected]>
---
 arch/x86/include/asm/perf_event.h    |   11 ++-
 arch/x86/kernel/cpu/perf_event.c     |   23 ++++
 arch/x86/kernel/cpu/perf_event_amd.c |  189 +++++++++++++++++++++++++++++++++-
 3 files changed, 214 insertions(+), 9 deletions(-)
arch/x86/include/asm/perf_event.h +7 -4
index 7e51c75..dace4e2 100644
@@ -44,14 +44,15 @@
 #define AMD64_RAW_EVENT_MASK		\
 	(X86_RAW_EVENT_MASK          |  \
 	 AMD64_EVENTSEL_EVENT)
+#define AMD64_NUM_COUNTERS				4
 
-#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL		      0x3c
+#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL		0x3c
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK		(0x00 << 8)
-#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX			 0
+#define ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX		0
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT \
 		(1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX))
 
-#define ARCH_PERFMON_BRANCH_MISSES_RETIRED			 6
+#define ARCH_PERFMON_BRANCH_MISSES_RETIRED		6
 
 /*
  * Intel "Architectural Performance Monitoring" CPUID
@@ -102,13 +103,15 @@ union cpuid10_edx {
 #define X86_PMC_IDX_FIXED_BUS_CYCLES			(X86_PMC_IDX_FIXED + 2)
 
 /*
- * We model BTS tracing as another fixed-mode PMC.
+ * Masks for special PMU features
  *
  * We choose a value in the middle of the fixed event range, since lower
  * values are used by actual fixed events and higher values are used
  * to indicate other overflow conditions in the PERF_GLOBAL_STATUS msr.
  */
 #define X86_PMC_IDX_SPECIAL_BTS				(X86_PMC_IDX_SPECIAL + 0)
+#define X86_PMC_IDX_SPECIAL_IBS_FETCH			(X86_PMC_IDX_SPECIAL + 1)
+#define X86_PMC_IDX_SPECIAL_IBS_OP			(X86_PMC_IDX_SPECIAL + 2)
 
 /* IbsFetchCtl bits/masks */
 #define IBS_FETCH_RAND_EN		(1ULL<<57)
arch/x86/kernel/cpu/perf_event.c +23 -0
index 0ad8c45..cc0fd61 100644
@@ -146,6 +146,9 @@ struct cpu_hw_events {
 #define INTEL_EVENT_CONSTRAINT(c, n)	\
 	EVENT_CONSTRAINT(c, n, ARCH_PERFMON_EVENTSEL_EVENT)
 
+#define AMD_IBS_EVENT_CONSTRAINT(idx)	\
+	__EVENT_CONSTRAINT(0, 1ULL << (idx), 0, AMD64_NUM_COUNTERS + 1)
+
 /*
  * Constraint on the Event code + UMask + fixed-mask
  *
@@ -184,6 +187,26 @@ union perf_capabilities {
 };
 
 /*
+ * Model specific hardware events
+ *
+ * With the attr.model_spec bit set we can setup hardware events
+ * others than generic performance counters. A special PMU 64 bit
+ * config value can be passed through the perf_event interface. The
+ * concept of PMU model-specific arguments was practiced already in
+ * Perfmon2. The type of event (8 bits) is determinded from the config
+ * value too, bit 32-39 are reserved for this.
+ */
+#define MODEL_SPEC_TYPE_IBS_FETCH	0
+#define MODEL_SPEC_TYPE_IBS_OP		1
+
+#define MODEL_SPEC_TYPE_MASK		(0xFFULL << 32)
+
+static inline u8 get_model_spec_type(u64 config)
+{
+	return (config & MODEL_SPEC_TYPE_MASK) >> 32;
+}
+
+/*
  * struct x86_pmu - generic x86 pmu
  */
 struct x86_pmu {
arch/x86/kernel/cpu/perf_event_amd.c +184 -5

235 lines not on this page · raw message

Signature · 8 lines
1.7.0.3



-- 
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#27 lore raw

Re: [PATCH 11/12] perf, x86: implement AMD IBS event configuration

Robert,

Some more comments about model_spec.

Quoted 4 lines

Except for the sample period IBS can only be set up with raw (model specific) config values and raw data samples. The event attributes for the syscall should be programmed like this (IBS_FETCH):

Quoted 9 lines

       memset(&attr, 0, sizeof(attr));
       attr.type        = PERF_TYPE_RAW;
       attr.sample_type = PERF_SAMPLE_CPU | PERF_SAMPLE_RAW; attr.config      = IBS_FETCH_CONFIG_DEFAULT attr.config     |=
               ((unsigned long long)MODEL_SPEC_TYPE_IBS_FETCH << 32) & MODEL_SPEC_TYPE_MASK;
       attr.model_spec  = 1;

Why do you need model_spec, in addition to your special encoding?

Quoted 10 lines

 /*
+ * Model specific hardware events
+ *
+ * With the attr.model_spec bit set we can setup hardware events
+ * others than generic performance counters. A special PMU 64 bit
+ * config value can be passed through the perf_event interface. The
+ * concept of PMU model-specific arguments was practiced already in
+ * Perfmon2. The type of event (8 bits) is determinded from the config
+ * value too, bit 32-39 are reserved for this.
+ */

Isn't the config field big enough to encode all the information you need? In the kernel, you could check bit 32-39 and based on host CPU determine whether it refers to IBS or is a bogus value. I am trying to figure out what model_spec buys you. I believe RAW does not mean the final value as accepted by HW but a value that must be interpreted by the model-specific code to eventually come up with a raw HW value. In the current code, the RAW value is never passed as is, it is assembled from various bits and pieces incl. attr.config of course.

#28 lore raw

Re: [PATCH 11/12] perf, x86: implement AMD IBS event configuration

Quoted 12 lines · Stephane Eranian

Why do you need model_spec, in addition to your special encoding?

Quoted 10 lines

 /*
+ * Model specific hardware events
+ *
+ * With the attr.model_spec bit set we can setup hardware events
+ * others than generic performance counters. A special PMU 64 bit
+ * config value can be passed through the perf_event interface. The
+ * concept of PMU model-specific arguments was practiced already in
+ * Perfmon2. The type of event (8 bits) is determinded from the config
+ * value too, bit 32-39 are reserved for this.
+ */

Quoted 8 lines

Isn't the config field big enough to encode all the information you need? In the kernel, you could check bit 32-39 and based on host CPU determine whether it refers to IBS or is a bogus value. I am trying to figure out what model_spec buys you. I believe RAW does not mean the final value as accepted by HW but a value that must be interpreted by the model-specific code to eventually come up with a raw HW value. In the current code, the RAW value is never passed as is, it is assembled from various bits and pieces incl. attr.config of course.

The raw config value without the model_spec bit set would asume a config value for a generic x86 counter. We could reuse also an unused bit in this config value, but what if this bit will be somewhen used? Or, it is available on one hw bot not another? So I found it much cleaner to introduce this attribute flag that can be reused on other architectures. Also, you will then have the freedom to implement model specific generic events without using raw_config. As most pmu features are setup with a 64 bit config value, I would prefer to have also the encoding of the model specific event type outside of the config value. A want to be close to the hw register layout without shifting bits back and forth. This may also introduce trouble in the future if we need all 64 bits.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#29 lore raw

Re: [PATCH 11/12] perf, x86: implement AMD IBS event configuration

Quoted 22 lines · Robert Richter
Quoted 12 lines · Stephane Eranian

Why do you need model_spec, in addition to your special encoding?

Quoted 10 lines

 /*
+ * Model specific hardware events
+ *
+ * With the attr.model_spec bit set we can setup hardware events
+ * others than generic performance counters. A special PMU 64 bit
+ * config value can be passed through the perf_event interface. The
+ * concept of PMU model-specific arguments was practiced already in
+ * Perfmon2. The type of event (8 bits) is determinded from the config
+ * value too, bit 32-39 are reserved for this.
+ */

Quoted 8 lines

Isn't the config field big enough to encode all the information you need? In the kernel, you could check bit 32-39 and based on host CPU determine whether it refers to IBS or is a bogus value. I am trying to figure out what model_spec buys you. I believe RAW does not mean the final value as accepted by HW but a value that must be interpreted by the model-specific code to eventually come up with a raw HW value. In the current code, the RAW value is never passed as is, it is assembled from various bits and pieces incl. attr.config of course.

Quoted 3 lines

The raw config value without the model_spec bit set would asume a config value for a generic x86 counter. We could reuse also an unused bit in this config value, but what if this bit will be somewhen used?

I have not yet seen a definition for what PERF_TYPE_RAW actually means, unfortunately. But I would not necessarily the same conclusion you did for raw without model_spec. I think the interpretation of raw config is up to the machine/model specific layer, it could be a counting event and something else.

To use IBS regardless, it seems the app needs to be aware it is available on the host and that with or without model_spec.

You know that on a Barcelona-class system, you will never need more than 42 bits. So you could reuse bits 63-42 to encode anything you want.

When you go to another class of system which may use more than 42 bits, then the app will have to know the type of host to use any model-specific feature,
thus it is also safe to assume it will now how to encode those feature for that host.
I don't see how model_spec would solve that particular problem.

To avoid the problem with full 64-bit raw config, you'd have to have another u64 model_spec field and not just a bit to encode the feature type, i.e., what you
are load in bits 32-63 today.

Quoted 18 lines

Or, it is available on one hw bot not another? So I found it much cleaner to introduce this attribute flag that can be reused on other architectures. Also, you will then have the freedom to implement model specific generic events without using raw_config. As most pmu features are setup with a 64 bit config value, I would prefer to have also the encoding of the model specific event type outside of the config value. A want to be close to the hw register layout without shifting bits back and forth. This may also introduce trouble in the future if we need all 64 bits.

-Robert

--
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]

#30 lore raw

Re: [PATCH 11/12] perf, x86: implement AMD IBS event configuration

In reply to Stephane Eranian
Quoted 29 lines · Stephane Eranian

Robert,

Some more comments about model_spec.

Quoted 4 lines

Except for the sample period IBS can only be set up with raw (model specific) config values and raw data samples. The event attributes for the syscall should be programmed like this (IBS_FETCH):

Quoted 9 lines

       memset(&attr, 0, sizeof(attr));
       attr.type        = PERF_TYPE_RAW;
       attr.sample_type = PERF_SAMPLE_CPU | PERF_SAMPLE_RAW; attr.config      = IBS_FETCH_CONFIG_DEFAULT attr.config     |=
               ((unsigned long long)MODEL_SPEC_TYPE_IBS_FETCH << 32) & MODEL_SPEC_TYPE_MASK;
       attr.model_spec  = 1;

Why do you need model_spec, in addition to your special encoding?

Quoted 10 lines

 /*
+ * Model specific hardware events
+ *
+ * With the attr.model_spec bit set we can setup hardware events
+ * others than generic performance counters. A special PMU 64 bit
+ * config value can be passed through the perf_event interface. The
+ * concept of PMU model-specific arguments was practiced already in
+ * Perfmon2. The type of event (8 bits) is determinded from the config
+ * value too, bit 32-39 are reserved for this.
+ */

Quoted 8 lines

Isn't the config field big enough to encode all the information you need? In the kernel, you could check bit 32-39 and based on host CPU determine whether it refers to IBS or is a bogus value. I am trying to figure out what model_spec buys you. I believe RAW does not mean the final value as accepted by HW but a value that must be interpreted by the model-specific code to eventually come up with a raw HW value. In the current code, the RAW value is never passed as is, it is assembled from various bits and pieces incl. attr.config of course.

What about introducing a raw_type? We could reuse the unused bp_type space for this. There is no longer the model_spec flag necessary and we could pass the raw 64 bit config value without shifting bits to encode the type there.

include/linux/perf_event.h +4 -1
index 4924c96..c9b51b3 100644
@@ -222,7 +222,10 @@ struct perf_event_attr {
                __u32           wakeup_watermark; /* bytes before wakeup   */
        };
 
-       __u32                   bp_type;
+       union {
+               __u32           bp_type;
+               __u32           raw_type;
+       }
        __u64                   bp_addr;
        __u64                   bp_len;
 };

Raw type would be architecure specific, e.g. for x86:

enum perf_raw_type {

        PERF_RAW_PERFCTR                        = 0,
        PERF_RAW_IBS_FETCH                      = 1,
        PERF_RAW_IBS_OP                         = 2,

PERF_RAW_MAX,
};

Null is the architecture's default.

The raw event syntax could be suffixed by the type (as for breakpoints):

-e rNNN[:TYPE]

Example:

perf record -e r186A:1 # ... meaning IBD fetch, cycle count 100000
perf record -e r0:1 -c 100000 # ... the same

Or with named types:

perf record -e r186A:IBS_FETCH ...
perf record -e r0:IBS_FETCH -c 100000 ...

I would prefer this solution as it has a number of advantages: A raw event type may be specified without to encode the type in the config value. The attr flags are not 'polluted'. We can follow the already existing breakpoint concept in syntax and encoding.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#31 lore raw

PATCH 12/12 perf, x86: implement the ibs interrupt handler

In reply to Robert Richter

This patch implements code to handle ibs interrupts. If ibs data is available a raw perf_event data sample is created and sent back to the userland. Currently only the data is stored only in the raw data, but this could be extended in a later patch by generating generic event data such as the rip from the ibs sampling data.

---
 arch/x86/include/asm/msr-index.h     |    3 ++
 arch/x86/kernel/cpu/perf_event_amd.c |   65 +++++++++++++++++++++++++++++++++-
 2 files changed, 67 insertions(+), 1 deletions(-)
arch/x86/include/asm/msr-index.h +3 -0
index bc473ac..a7e4aa5 100644
@@ -113,6 +113,7 @@
 #define MSR_AMD64_IBSFETCHCTL		0xc0011030
 #define MSR_AMD64_IBSFETCHLINAD		0xc0011031
 #define MSR_AMD64_IBSFETCHPHYSAD	0xc0011032
+#define MSR_AMD64_IBSFETCH_SIZE		3
 #define MSR_AMD64_IBSOPCTL		0xc0011033
 #define MSR_AMD64_IBSOPRIP		0xc0011034
 #define MSR_AMD64_IBSOPDATA		0xc0011035
@@ -120,7 +121,9 @@
 #define MSR_AMD64_IBSOPDATA3		0xc0011037
 #define MSR_AMD64_IBSDCLINAD		0xc0011038
 #define MSR_AMD64_IBSDCPHYSAD		0xc0011039
+#define MSR_AMD64_IBSOP_SIZE		7
 #define MSR_AMD64_IBSCTL		0xc001103a
+#define MSR_AMD64_IBS_SIZE_MAX		MSR_AMD64_IBSOP_SIZE
 
 /* Fam 10h MSRs */
 #define MSR_FAM10H_MMIO_CONF_BASE	0xc0010058
arch/x86/kernel/cpu/perf_event_amd.c +64 -1

77 lines not on this page · raw message

Signature · 1 line
1.7.0.3
#32 lore raw

Re: [PATCH 12/12] perf, x86: implement the ibs interrupt handler

Robert,

Some comments below.

Quoted 17 lines · Robert Richter

This patch implements code to handle ibs interrupts. If ibs data is available a raw perf_event data sample is created and sent back to the userland. Currently only the data is stored only in the raw data, but this could be extended in a later patch by generating generic event data such as the rip from the ibs sampling data.

---
 arch/x86/include/asm/msr-index.h     |    3 ++ arch/x86/kernel/cpu/perf_event_amd.c |   65 +++++++++++++++++++++++++++++++++-

 2 files changed, 67 insertions(+), 1 deletions(-)
arch/x86/include/asm/msr-index.h +0 -0
index bc473ac..a7e4aa5 100644

arch/x86/include/asm/msr-index.h line 116

Quoted 4 lines
arch/x86/include/asm/msr-index.h +1 -0
@@ -113,6 +113,7 @@
  #define MSR_AMD64_IBSFETCHCTL          0xc0011030
  #define MSR_AMD64_IBSFETCHLINAD                0xc0011031
  #define MSR_AMD64_IBSFETCHPHYSAD       0xc0011032
+#define MSR_AMD64_IBSFETCH_SIZE                3

I would use COUNT instead of size given the unit is registers not bytes.

arch/x86/include/asm/msr-index.h line 124

Quoted 8 lines
arch/x86/include/asm/msr-index.h +1 -0
  #define MSR_AMD64_IBSOPCTL             0xc0011033
  #define MSR_AMD64_IBSOPRIP             0xc0011034
  #define MSR_AMD64_IBSOPDATA            0xc0011035
@@ -120,7 +121,9 @@
  #define MSR_AMD64_IBSOPDATA3           0xc0011037
  #define MSR_AMD64_IBSDCLINAD           0xc0011038
  #define MSR_AMD64_IBSDCPHYSAD          0xc0011039
+#define MSR_AMD64_IBSOP_SIZE           7

Idem here for IBSOP.

arch/x86/include/asm/msr-index.h line 127

Quoted 3 lines
arch/x86/include/asm/msr-index.h +1 -0
  #define MSR_AMD64_IBSCTL               0xc001103a
+#define MSR_AMD64_IBS_SIZE_MAX         MSR_AMD64_IBSOP_SIZE
 

Idem.

Quoted 28 lines
arch/x86/include/asm/msr-index.h +0 -0
  /* Fam 10h MSRs */
  #define MSR_FAM10H_MMIO_CONF_BASE      0xc0010058
arch/x86/kernel/cpu/perf_event_amd.c +18 -0
index 3dc327c..78b0b34 100644
@@ -283,6 +283,69 @@ static inline void __amd_pmu_enable_ibs_event(struct hw_perf_event *hwc)
                __x86_pmu_enable_event(hwc, IBS_OP_ENABLE);
  }
 
+static int amd_pmu_check_ibs(int idx, unsigned int msr, u64 valid,
+                            u64 reenable, int size, struct pt_regs *iregs)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct perf_event *event = cpuc->events[idx];
+       struct perf_sample_data data;
+       struct perf_raw_record raw;
+       struct pt_regs regs;
+       u64 buffer[MSR_AMD64_IBS_SIZE_MAX];
+       u64 *buf = buffer;
+       int i;
+
+       if (!test_bit(idx, cpuc->active_mask))
+               return 0;
+
+       rdmsrl(msr++, *buf);
+       if (!(*buf++ & valid))
+               return 0;

arch/x86/kernel/cpu/perf_event_amd.c static inline void __amd_pmu_enable_ibs_event(struct hw_perf_event *hwc) · line 313

Quoted 10 lines
arch/x86/kernel/cpu/perf_event_amd.c +10 -0
+
+       perf_sample_data_init(&data, 0);
+       if (event->attr.sample_type & PERF_SAMPLE_RAW) {
+               for (i = 1; i < size; i++)
+                       rdmsrl(msr++, *buf++);
+               raw.size = sizeof(u64) * size;
+               raw.data = buffer;
+               data.raw = &raw;
+       }
+

Need to add the padding: raw.size = sizeof(u64) * size + sizeof(u32);

Quoted 22 lines
arch/x86/kernel/cpu/perf_event_amd.c +22 -0
+       regs = *iregs; /* later: update ip from ibs sample */
+
+       if (perf_event_overflow(event, 1, &data, &regs))
+               x86_pmu_stop(event);
+       else
+               __x86_pmu_enable_event(&event->hw, reenable);
+
+       return 1;
+}
+
+static int amd_pmu_handle_irq(struct pt_regs *regs)
+{
+       int handled, handled2;
+
+       handled = x86_pmu_handle_irq(regs);
+
+       if (!x86_pmu.ibs)
+               return handled;
+
+       handled2 = 0;
+       handled2 += amd_pmu_check_ibs(X86_PMC_IDX_SPECIAL_IBS_FETCH,
+                                     MSR_AMD64_IBSFETCHCTL, IBS_FETCH_VAL,

arch/x86/kernel/cpu/perf_event_amd.c static inline void __amd_pmu_enable_ibs_event(struct hw_perf_event *hwc) · line 345

Quoted 10 lines
arch/x86/kernel/cpu/perf_event_amd.c +10 -0
+                                     IBS_FETCH_ENABLE, MSR_AMD64_IBSFETCH_SIZE,
+                                     regs);
+       handled2 += amd_pmu_check_ibs(X86_PMC_IDX_SPECIAL_IBS_OP,
+                                     MSR_AMD64_IBSOPCTL, IBS_OP_VAL,
+                                     IBS_OP_ENABLE, MSR_AMD64_IBSOP_SIZE,
+                                     regs);
+
+       if (handled2)
+               inc_irq_stat(apic_perf_irqs);
+

If you have both regular counter intr + IBS you will double-count apic_perf_irqs.
I would do: if (handled2 && !handled) inc_irq_stat().

#33 lore raw

Re: [PATCH 12/12] perf, x86: implement the ibs interrupt handler

Quoted 11 lines · Stephane Eranian

arch/x86/include/asm/msr-index.h line 116

Quoted 9 lines
arch/x86/include/asm/msr-index.h +1 -0
index bc473ac..a7e4aa5 100644
@@ -113,6 +113,7 @@
  #define MSR_AMD64_IBSFETCHCTL          0xc0011030
  #define MSR_AMD64_IBSFETCHLINAD                0xc0011031
  #define MSR_AMD64_IBSFETCHPHYSAD       0xc0011032
+#define MSR_AMD64_IBSFETCH_SIZE                3

I would use COUNT instead of size given the unit is registers not bytes.

I will change the naming for all macros.

Quoted 22 lines
Quoted 22 lines
arch/x86/include/asm/msr-index.h +22 -0
+static int amd_pmu_check_ibs(int idx, unsigned int msr, u64 valid,
+                            u64 reenable, int size, struct pt_regs *iregs)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct perf_event *event = cpuc->events[idx];
+       struct perf_sample_data data;
+       struct perf_raw_record raw;
+       struct pt_regs regs;
+       u64 buffer[MSR_AMD64_IBS_SIZE_MAX];
+       u64 *buf = buffer;
+       int i;
+
+       if (!test_bit(idx, cpuc->active_mask))
+               return 0;
+
+       rdmsrl(msr++, *buf);
+       if (!(*buf++ & valid))
+               return 0;
+
+       perf_sample_data_init(&data, 0);
+       if (event->attr.sample_type & PERF_SAMPLE_RAW) {
+               for (i = 1; i < size; i++)
Quoted 8 lines
Quoted 6 lines

+                       rdmsrl(msr++, *buf++);
+               raw.size = sizeof(u64) * size;
+               raw.data = buffer;
+               data.raw = &raw;
+       }
+

Need to add the padding: raw.size = sizeof(u64) * size + sizeof(u32);

Yes, this triggers a warning. Will change it and add 4 padding bytes at the buffer start (to be also 8 byte aligned).

Quoted 18 lines
Quoted 18 lines
arch/x86/include/asm/msr-index.h +18 -0
+static int amd_pmu_handle_irq(struct pt_regs *regs)
+{
+       int handled, handled2;
+
+       handled = x86_pmu_handle_irq(regs);
+
+       if (!x86_pmu.ibs)
+               return handled;
+
+       handled2 = 0;
+       handled2 += amd_pmu_check_ibs(X86_PMC_IDX_SPECIAL_IBS_FETCH,
+                                     MSR_AMD64_IBSFETCHCTL, IBS_FETCH_VAL,
+                                     IBS_FETCH_ENABLE, MSR_AMD64_IBSFETCH_SIZE,
+                                     regs);
+       handled2 += amd_pmu_check_ibs(X86_PMC_IDX_SPECIAL_IBS_OP,
+                                     MSR_AMD64_IBSOPCTL, IBS_OP_VAL,
+                                     IBS_OP_ENABLE, MSR_AMD64_IBSOP_SIZE,
+                                     regs);
Quoted 9 lines

arch/x86/include/asm/msr-index.h

Quoted 4 lines
arch/x86/include/asm/msr-index.h +4 -0
+
+       if (handled2)
+               inc_irq_stat(apic_perf_irqs);
+

If you have both regular counter intr + IBS you will double-count apic_perf_irqs.
I would do: if (handled2 && !handled) inc_irq_stat().

True, will change this.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#34 lore raw

Re: [PATCH 12/12] perf, x86: implement the ibs interrupt handler

In reply to Stephane Eranian
Quoted 11 lines · Stephane Eranian
Quoted 9 lines

+       perf_sample_data_init(&data, 0);
+       if (event->attr.sample_type & PERF_SAMPLE_RAW) {
+               for (i = 1; i < size; i++)
+                       rdmsrl(msr++, *buf++);
+               raw.size = sizeof(u64) * size;
+               raw.data = buffer;
+               data.raw = &raw;
+       }
+

Need to add the padding: raw.size = sizeof(u64) * size + sizeof(u32);

The u32 size header in the raw sampling data layout leads to unaligned memory access for 64 bit values. No matter if the padding is inserted at the beginning or end of the raw sample, it introduces either on the sending or receiving side an 32 bit offset.

Wouldn't it be better to simply make size an u64 or to add another reserved u32 value to the header. This could introduce some overhead on smaller architectures, but currently this is only used on x86. The event size encoding of the ring_buffer implementation could be another alternative.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#35 lore raw

PATCH 1/1 perf: fix raw sample size if no sampling data is attached

In reply to Stephane Eranian
Quoted 10 lines · Stephane Eranian
Quoted 9 lines

+       perf_sample_data_init(&data, 0);
+       if (event->attr.sample_type & PERF_SAMPLE_RAW) {
+               for (i = 1; i < size; i++)
+                       rdmsrl(msr++, *buf++);
+               raw.size = sizeof(u64) * size;
+               raw.data = buffer;
+               data.raw = &raw;
+       }
+

Quoted 5 lines

Need to add the padding: raw.size = sizeof(u64) * size + sizeof(u32);

Quoted 3 lines

+       regs = *iregs; /* later: update ip from ibs sample */ +
+       if (perf_event_overflow(event, 1, &data, &regs))

During code review I found a bug in perf_output_sample(). A fix is below.

Quoted 6 lines

Review

Quoted 6 lines

+               x86_pmu_stop(event);
+       else
+               __x86_pmu_enable_event(&event->hw, reenable);

(quoted diff) +3 -0
+
+       return 1;
+}

--

Quoted 1 line

From 6373951f1c660400650066b73c3bb2f6d232be67 Mon Sep 17 00:00:00 2001

From: Robert Richter <[email protected]>
Date: Fri, 7 May 2010 15:49:56 +0200
Subject: [PATCH] perf: fix raw sample size if no sampling data is attached

The header size of a raw sample is not included in the total size of a raw data sample. Thus, if no data is attached the size must be null. In this case a buffer overflow may occur when copying the sampling data.

---
 kernel/perf_event.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
kernel/perf_event.c +1 -1
index 9dbe8cd..f6ddae9 100644
@@ -3229,7 +3229,7 @@ void perf_output_sample(struct perf_output_handle *handle,
 				u32	size;
 				u32	data;
 			} raw = {
-				.size = sizeof(u32),
+				.size = 0,
 				.data = 0,
 			};
 			perf_output_put(handle, raw);
Signature · 6 lines
1.7.0.3

-- 
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
maintainer
#36 lore raw

Re: [PATCH] perf: fix raw sample size if no sampling data is attached

Quoted 11 lines · Robert Richter

From 6373951f1c660400650066b73c3bb2f6d232be67 Mon Sep 17 00:00:00 2001
From: Robert Richter <[email protected]>
Date: Fri, 7 May 2010 15:49:56 +0200
Subject: [PATCH] perf: fix raw sample size if no sampling data is attached

The header size of a raw sample is not included in the total size of a raw data sample. Thus, if no data is attached the size must be null. In this case a buffer overflow may occur when copying the sampling data.

But there is data, a whole u32 of value 0. Your patch breaks things.

Quoted 19 lines
---
 kernel/perf_event.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
kernel/perf_event.c +1 -1
index 9dbe8cd..f6ddae9 100644
@@ -3229,7 +3229,7 @@ void perf_output_sample(struct
 perf_output_handle *handle,
                                u32     size;
                                u32     data;
                        } raw = {
-                               .size = sizeof(u32),
+                               .size = 0,
                                .data = 0,
                        };
                        perf_output_put(handle, raw); 
#37 lore raw

Re: [PATCH] perf: fix raw sample size if no sampling data is attached

In reply to Robert Richter

kernel/perf_event.c void perf_output_sample(struct perf_output_handle *handle, · line 3233

Quoted 11 lines · Robert Richter
kernel/perf_event.c +1 -1
index 9dbe8cd..f6ddae9 100644
@@ -3229,7 +3229,7 @@ void perf_output_sample(struct perf_output_handle *handle,
 				u32	size;
 				u32	data;
 			} raw = {
-				.size = sizeof(u32),
+				.size = 0,
 				.data = 0,

Uhhh, this padding data was completly hidden to me by a SEP field. It became visible to me with a far distance of at least 4km and only from the corner of my eye. So, *now* I realized that size is the size of padding data, not the size header! Please ignore this, I shouln't send patches at Friday afternoon.

-Robert

Quoted 2 lines
kernel/perf_event.c +0 -0
 			};
 			perf_output_put(handle, raw);
Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#38 lore raw

RFC PATCH 1/1 perf: align raw sample data on 64-bit boundaries

In reply to Stephane Eranian
Quoted 11 lines · Stephane Eranian
Quoted 9 lines

+       perf_sample_data_init(&data, 0);
+       if (event->attr.sample_type & PERF_SAMPLE_RAW) {
+               for (i = 1; i < size; i++)
+                       rdmsrl(msr++, *buf++);
+               raw.size = sizeof(u64) * size;
+               raw.data = buffer;
+               data.raw = &raw;
+       }
+

Need to add the padding: raw.size = sizeof(u64) * size + sizeof(u32);

When thinking about this I was wondering if it wouldn't make sense to better fix the alignment and move the data buffer to a 64 bit boundary. So take a look at the enclosed RFC patch. Though it breaks the ABI it would solve some problems. I think more than it introduces. Hopefully I found all effected code locations using it.

-Robert

--

Quoted 1 line

From 2427dda67b072f27ecff678f8829b9e2fc537988 Mon Sep 17 00:00:00 2001

From: Robert Richter <[email protected]>
Date: Fri, 7 May 2010 15:32:45 +0200
Subject: [PATCH] perf: align raw sample data on 64-bit boundaries

In the current implementation 64 bit raw sample data values are not aligned due to the 32 bit size header. The size header is located before the data buffer on a 64 bit boundary. This leads to unaligned memory access to the data buffer for arrays or structures containing 64 bit values. To avoid this, the patch adds a 32 bit reserved value to the raw sample data header. The data buffer starts then at a 64 bit boundary.

This changes the ABI and requires changes in the userland tools. For tools/perf this is at a single location in event.c only. This could also introduce some overhead on smaller architectures, but currently this is only used on x86 or for transferring raw tracepoint data. Though an ABI change should be avoided, it is worth to align raw sample data on 64-bit boundaries as the change fixes unaligned memory access, eases the implementation for raw sample data and reduces the risk of data corruption due to different pad structures inserted by the compiler.

---
 include/linux/perf_event.h    |    1 +
 kernel/perf_event.c           |   21 ++++++++++-----------
 kernel/trace/trace_kprobe.c   |    6 ++----
 kernel/trace/trace_syscalls.c |    6 ++----
 tools/perf/util/event.c       |    4 ++--
 5 files changed, 17 insertions(+), 21 deletions(-)
include/linux/perf_event.h +1 -0
index 3fd5c82..016969c 100644
@@ -431,6 +431,7 @@ enum perf_event_type {
 	 *	#
 	 *
 	 *	{ u32			size;
+	 *	  u32			reserved;
 	 *	  char                  data[size];}&& PERF_SAMPLE_RAW
 	 * };
 	 */
kernel/perf_event.c +10 -11
index a4fa381..12bb53d 100644
@@ -3252,18 +3252,19 @@ void perf_output_sample(struct perf_output_handle *handle,
 	}
 
 	if (sample_type & PERF_SAMPLE_RAW) {
+		struct {
+			u32	size;
+			u32	reserved;
+		} raw = {
+			.size = 0,
+			.reserved = 0,
+		};
 		if (data->raw) {
-			perf_output_put(handle, data->raw->size);
+			raw.size = data->raw->size;
+			perf_output_put(handle, raw);
 			perf_output_copy(handle, data->raw->data,
 					 data->raw->size);
 		} else {
-			struct {
-				u32	size;
-				u32	data;
-			} raw = {
-				.size = sizeof(u32),
-				.data = 0,
-			};
 			perf_output_put(handle, raw);
 		}
 	}
@@ -3344,12 +3345,10 @@ void perf_prepare_sample(struct perf_event_header *header,
 	}
 
 	if (sample_type & PERF_SAMPLE_RAW) {
-		int size = sizeof(u32);
+		int size = sizeof(u64);
 
 		if (data->raw)
 			size += data->raw->size;
-		else
-			size += sizeof(u32);
 
 		WARN_ON_ONCE(size & (sizeof(u64)-1));
 		header->size += size;
kernel/trace/trace_kprobe.c +2 -4
index a751432..00172b0 100644
@@ -1347,8 +1347,7 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp,
 	int rctx;
 
 	__size = sizeof(*entry) + tp->size;
-	size = ALIGN(__size + sizeof(u32), sizeof(u64));
-	size -= sizeof(u32);
+	size = ALIGN(__size, sizeof(u64));
 	if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
 		     "profile buffer not large enough"))
 		return;
@@ -1378,8 +1377,7 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri,
 	int rctx;
 
 	__size = sizeof(*entry) + tp->size;
-	size = ALIGN(__size + sizeof(u32), sizeof(u64));
-	size -= sizeof(u32);
+	size = ALIGN(__size, sizeof(u64));
 	if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
 		     "profile buffer not large enough"))
 		return;
kernel/trace/trace_syscalls.c +2 -4
index 4d6d711..ad7e713 100644
@@ -453,8 +453,7 @@ static void perf_syscall_enter(struct pt_regs *regs, long id)
 
 	/* get the size after alignment with the u32 buffer size field */
 	size = sizeof(unsigned long) * sys_data->nb_args + sizeof(*rec);
-	size = ALIGN(size + sizeof(u32), sizeof(u64));
-	size -= sizeof(u32);
+	size = ALIGN(size, sizeof(u64));
 
 	if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
 		      "perf buffer not large enough"))
@@ -524,8 +523,7 @@ static void perf_syscall_exit(struct pt_regs *regs, long ret)
 		return;
 
 	/* We can probably do that at build time */
-	size = ALIGN(sizeof(*rec) + sizeof(u32), sizeof(u64));
-	size -= sizeof(u32);
+	size = ALIGN(sizeof(*rec), sizeof(u64));
 
 	/*
 	 * Impossible, but be paranoid with the future
tools/perf/util/event.c +2 -2
index 50771b5..6902b85 100644
@@ -790,8 +790,8 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
 	if (type & PERF_SAMPLE_RAW) {
 		u32 *p = (u32 *)array;
 		data->raw_size = *p;
-		p++;
-		data->raw_data = p;
+		array++;
+		data->raw_data = array;
 	}
 
 	return 0;
Signature · 6 lines
1.7.1

-- 
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#39 lore raw

Re: [RFC PATCH] perf: align raw sample data on 64-bit boundaries

Quoted 36 lines · Robert Richter
Quoted 11 lines · Stephane Eranian
Quoted 9 lines

+       perf_sample_data_init(&data, 0);
+       if (event->attr.sample_type & PERF_SAMPLE_RAW) {
+               for (i = 1; i < size; i++)
+                       rdmsrl(msr++, *buf++);
+               raw.size = sizeof(u64) * size;
+               raw.data = buffer;
+               data.raw = &raw;
+       }
+

Need to add the padding: raw.size = sizeof(u64) * size + sizeof(u32);

When thinking about this I was wondering if it wouldn't make sense to better fix the alignment and move the data buffer to a 64 bit boundary. So take a look at the enclosed RFC patch. Though it breaks the ABI it would solve some problems. I think more than it introduces. Hopefully I found all effected code locations using it.

-Robert

--

From 2427dda67b072f27ecff678f8829b9e2fc537988 Mon Sep 17 00:00:00 2001
From: Robert Richter <[email protected]>
Date: Fri, 7 May 2010 15:32:45 +0200
Subject: [PATCH] perf: align raw sample data on 64-bit boundaries

In the current implementation 64 bit raw sample data values are not aligned due to the 32 bit size header. The size header is located before the data buffer on a 64 bit boundary. This leads to unaligned memory access to the data buffer for arrays or structures containing 64 bit values. To avoid this, the patch adds a 32 bit reserved value to the raw sample data header. The data buffer starts then at a 64 bit boundary.

Quoted 5 lines

This changes the ABI and requires changes in the userland tools. For tools/perf this is at a single location in event.c only. This could also introduce some overhead on smaller architectures, but currently this is only used on x86 or for transferring raw tracepoint data.

No this is used on any architectures that event have a minimal support for perf events.

I use tracepoint raw samples in sparc 64 for example (which has much more than the minimal support).

Quoted 8 lines

Though an ABI change should be avoided, it is worth to align raw sample data on 64-bit boundaries as the change fixes unaligned memory access, eases the implementation for raw sample data and reduces the risk of data corruption due to different pad structures inserted by the compiler.

---

I don't think we should do this. Ok it's true we've screwed up something there but breaking the ABI is going to make the things even worst I think.

I would feel better with a new PERF_SAMPLE_RAW_ALIGNED sample_type and schedule the deprecation of PERF_SAMPLE_RAW for later but keep it for some releases.

What do you think?

#40 lore raw

Re: [RFC PATCH] perf: align raw sample data on 64-bit boundaries

Quoted 7 lines · Frederic Weisbecker
Quoted 5 lines

This changes the ABI and requires changes in the userland tools. For tools/perf this is at a single location in event.c only. This could also introduce some overhead on smaller architectures, but currently this is only used on x86 or for transferring raw tracepoint data.

Quoted 5 lines

No this is used on any architectures that event have a minimal support for perf events.

I use tracepoint raw samples in sparc 64 for example (which has much more than the minimal support).

Isn't here the same alignment problem on archs there unsigned long is 64 bit? Also, most samples I found have a size of multiples of 8 bytes, so even on 32 bit archs there would be a padding of 4 bytes somethere in the sample.

Quoted 3 lines

I don't think we should do this. Ok it's true we've screwed up something there but breaking the ABI is going to make the things even worst I think.

I was not sure how hard an ABI breakage would be. I think the small number of users of raw samples is manageable, but I understand if you feel uncomfortable with it.

Quoted 3 lines

I would feel better with a new PERF_SAMPLE_RAW_ALIGNED sample_type and schedule the deprecation of PERF_SAMPLE_RAW for later but keep it for some releases.

This could be an alternative. Though, it duplicates code paths and introduces ugly sample type checks. Another alternative would be to check the size value, if it is (n * sizeof(u64)) we could asume 64 bit alignment. But maybe this makes things much worse.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#41 lore raw

Re: [RFC PATCH] perf: align raw sample data on 64-bit boundaries

Quoted 12 lines · Robert Richter
Quoted 10 lines · Frederic Weisbecker
Quoted 5 lines

This changes the ABI and requires changes in the userland tools. For tools/perf this is at a single location in event.c only. This could also introduce some overhead on smaller architectures, but currently this is only used on x86 or for transferring raw tracepoint data.

No this is used on any architectures that event have a minimal support for perf events.

Quoted 7 lines
Quoted 2 lines

I use tracepoint raw samples in sparc 64 for example (which has much more than the minimal support).

Isn't here the same alignment problem on archs there unsigned long is 64 bit? Also, most samples I found have a size of multiples of 8 bytes, so even on 32 bit archs there would be a padding of 4 bytes somethere in the sample.

Yeah there was an alignment problem in sparc 64 that I fixed in perf tools lately. The fix is more a hack though, the real solution would be to have this alignment thing fixed.

And yeah, probably most samples need padding.

Quoted 7 lines
Quoted 3 lines

I don't think we should do this. Ok it's true we've screwed up something there but breaking the ABI is going to make the things even worst I think.

I was not sure how hard an ABI breakage would be. I think the small number of users of raw samples is manageable, but I understand if you feel uncomfortable with it.

I don't know how many people use it. But I prefer not to take that risk.

Quoted 11 lines
Quoted 4 lines

I would feel better with a new PERF_SAMPLE_RAW_ALIGNED sample_type and schedule the deprecation of PERF_SAMPLE_RAW for later but keep it for some releases.

This could be an alternative. Though, it duplicates code paths and introduces ugly sample type checks. Another alternative would be to check the size value, if it is (n * sizeof(u64)) we could asume 64 bit alignment. But maybe this makes things much worse.

-Robert

It doesn't duplicate much code paths, we only have a few corner cases to plug in. And more importantly, that would be temporary if we schedule the older PERF_SAMPLE_RAW in, say, three releases from now.

This ensures an easy forward compatibility (older perf tools -> newer kernel). But the backward compatibility is less easy (newer perf tools -> older kernel) as it means we need to test dynamically if we have PERF_SAMPLE_RAW_ALIGNED, otherwise we need to fall back to using the older one.

#42 lore raw

Re: [RFC PATCH] perf: align raw sample data on 64-bit boundaries

Quoted 8 lines · Frederic Weisbecker

It doesn't duplicate much code paths, we only have a few corner cases to plug in. And more importantly, that would be temporary if we schedule the older PERF_SAMPLE_RAW in, say, three releases from now.

This ensures an easy forward compatibility (older perf tools -> newer kernel). But the backward compatibility is less easy (newer perf tools -> older kernel) as it means we need to test dynamically if we have PERF_SAMPLE_RAW_ALIGNED, otherwise we need to fall back to using the older one.

Frederic, I will send an updated version with PERF_SAMPLE_RAW_ALIGNED.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#43 lore raw
In reply to Robert Richter
Quoted 2 lines · Robert Richter

This patch series introduces model specific events and impments AMD IBS (Instruction Based Sampling) for perf_events.

The patch set triggers this warning in perf_prepare_sample():

WARN_ON_ONCE(size & (sizeof(u64)-1))

Should a raw data sample padded to 64 bit?

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#44 lore raw
Quoted 7 lines · Robert Richter
Quoted 2 lines · Robert Richter

This patch series introduces model specific events and impments AMD IBS (Instruction Based Sampling) for perf_events.

The patch set triggers this warning in perf_prepare_sample():

WARN_ON_ONCE(size & (sizeof(u64)-1))

Just found Stephane's patch on the mailing list that removes the warning.

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
maintainer
#45 lore raw
In reply to Robert Richter
Quoted 9 lines · Robert Richter
Quoted 2 lines · Robert Richter

This patch series introduces model specific events and impments AMD IBS (Instruction Based Sampling) for perf_events.

The patch set triggers this warning in perf_prepare_sample():

WARN_ON_ONCE(size & (sizeof(u64)-1))

Should a raw data sample padded to 64 bit?

Yes it should.

maintainer
#46 lore raw
In reply to Robert Richter
Quoted 2 lines · Robert Richter

This patch series introduces model specific events and impments AMD IBS (Instruction Based Sampling) for perf_events.

I would much rather it uses the ->precise thing PEBS also uses, otherwise we keep growing funny arch extensions and end up with a totally fragmented trainwreck of an ABI.

Quoted 11 lines

The general approach is to introduce a flag to mark an event as model specific. With that flag set a model specific ibs (raw) config value can be passed to the pmu for setup. When there are ibs samples available, it is sent back as a raw data sample to the userland. So we have a raw config value and raw sampling data. This requires the userland to setup ibs and further extract and process sampling data.

Patches 1-8 rework and refactor the code to prepare the ibs implementation. This is done in patches 9-12.

I will add ibs example code to libpfm4.

Please add a valid usecase to tools/perf/ instead.

#47 lore raw
Quoted 7 lines · Peter Zijlstra
Quoted 2 lines · Robert Richter

This patch series introduces model specific events and impments AMD IBS (Instruction Based Sampling) for perf_events.

I would much rather it uses the ->precise thing PEBS also uses, otherwise we keep growing funny arch extensions and end up with a totally fragmented trainwreck of an ABI.

I agree that an exiting flag could be reused. But the naming 'precise' could be misleading. Maybe we rename it to 'model_spec' or something else that underlines the idea of having model specific setups.

Quoted 7 lines
Quoted 7 lines

The general approach is to introduce a flag to mark an event as model specific. With that flag set a model specific ibs (raw) config value can be passed to the pmu for setup. When there are ibs samples available, it is sent back as a raw data sample to the userland. So we have a raw config value and raw sampling data. This requires the userland to setup ibs and further extract and process sampling data.

Quoted 6 lines
Quoted 4 lines

Patches 1-8 rework and refactor the code to prepare the ibs implementation. This is done in patches 9-12.

I will add ibs example code to libpfm4.

Please add a valid usecase to tools/perf/ instead.

I will also provide an example for tools/perf but reusing libpfm4 was a first quick solution for me.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
maintainer
#48 lore raw
Quoted 5 lines · Robert Richter
Quoted 4 lines · Peter Zijlstra
Quoted 2 lines · Robert Richter

This patch series introduces model specific events and impments AMD IBS (Instruction Based Sampling) for perf_events.

Quoted 7 lines
Quoted 3 lines

I would much rather it uses the ->precise thing PEBS also uses, otherwise we keep growing funny arch extensions and end up with a totally fragmented trainwreck of an ABI.

I agree that an exiting flag could be reused. But the naming 'precise' could be misleading. Maybe we rename it to 'model_spec' or something else that underlines the idea of having model specific setups.

Right, so I really hate PERF_SAMPLE_RAW, and I'm considering simply removing that for PEBS as well, its just too ugly. If we want the register set we need to work on getting PERF_SAMPLE_REGS in a sensible shape.

As to the meaning for ->precise, its meant to convey the counters are not affected by skid and the like, I thought IBS provided exact IPs as well (/me should re-read the IBS docs).

The thing with something like ->model_spec and PERF_SAMPLE_RAW is that it doesn't provide a clear model, the user doesn't know what to expect of it, it could be anything.

We want the ABI to express clear concepts, and things like lets bypass everything and just dump stuff out to userspace really are to be avoided at all costs.

Sadly IBS seems to be an utter trainwreck in the concept department (I'm still struggling how to make a sensible interpretation of the data it gathers).

The thing I absolutely want to avoid is the ABI becoming a fragmented trainwreck like oprofile is.

Also not using sample_period for the sample period is of course utterly unacceptable.

#49 lore raw
Quoted 10 lines · Peter Zijlstra
Quoted 9 lines · Robert Richter
Quoted 7 lines · Peter Zijlstra
Quoted 2 lines · Robert Richter

This patch series introduces model specific events and impments AMD IBS (Instruction Based Sampling) for perf_events.

I would much rather it uses the ->precise thing PEBS also uses, otherwise we keep growing funny arch extensions and end up with a totally fragmented trainwreck of an ABI.

Quoted 9 lines
Quoted 3 lines

I agree that an exiting flag could be reused. But the naming 'precise' could be misleading. Maybe we rename it to 'model_spec' or something else that underlines the idea of having model specific setups.

Right, so I really hate PERF_SAMPLE_RAW, and I'm considering simply removing that for PEBS as well, its just too ugly. If we want the register set we need to work on getting PERF_SAMPLE_REGS in a sensible shape.

I wonder why SAMPLE_RAW went in in the first place, then. What was the justification for it, traces?

Okay, so you're suggesting everything is exposed via PERF_SAMPLE_REGS. PEBS does capture machine state which is easily mapped onto PERF_SAMPLE_REGS. Well, that's until you look at PEB-LL on Nehalem where is captures latencies and data
addresses.

IBS does not capture machine state in the sense of general purpose registers. IBS captures micro-architectural info about an instruction and stores this into a
handful of IBS registers. Those could be funneled through PERF_SAMPLE_REGS as well, I believe. But that means, PERF_SAMPLE_REGS would need some configuration
bitmask to name the registers of interest, e.g. EAX, EDX, IBSOP_DATA, IBSOP_PHYSAD,
and so on.

As you pointed out a long time ago, IBS returns to much information to be abstracted
easily unless you're willing to drop part of the information it returns, e.g., concentrate
on cache miss info only. But this goes back to a point I made early
on: there are
many usage models, different metrics need different data. You don't want to prevent
any usage model.

Quoted 4 lines

As to the meaning for ->precise, its meant to convey the counters are not affected by skid and the like, I thought IBS provided exact IPs as well (/me should re-read the IBS docs).

By construction it is given that it tracks an instruction. Thus, the IP is always
that of the monitored instruction: no skid. The difference, though, it that is not
associated with an actual counter+event. IBS keeps its own counter. You can easily create a pseudo event (which is what Robert does in his patch).

Quoted 4 lines

The thing with something like ->model_spec and PERF_SAMPLE_RAW is that it doesn't provide a clear model, the user doesn't know what to expect of it, it could be anything.

I think we can avoid model_spec.

Quoted 8 lines

We want the ABI to express clear concepts, and things like lets bypass everything and just dump stuff out to userspace really are to be avoided at all costs.

Sadly IBS seems to be an utter trainwreck in the concept department (I'm still struggling how to make a sensible interpretation of the data it gathers).

Concept is simple: track an instruction (uop) as it traverses the pipeline and gather all sort of micro-architectural info. When the instruction retires, interrupt the CPU and deliver the info via registers. The current implementation is not without problems, but you can already gather useful info such as instrs latencies, data cache misses.

Speaking of data cache misses, I believe there may be a way to abstract sampling on cache misses, i.e, capture where they occur, that would work with both IBS and PEBS-LL. That may be a good way to start exposing some of the IBS features.

Quoted 3 lines

Also not using sample_period for the sample period is of course utterly unacceptable.

That is fixed now.

#50 lore raw
Quoted 6 lines · Stephane Eranian

Okay, so you're suggesting everything is exposed via PERF_SAMPLE_REGS. PEBS does capture machine state which is easily mapped onto PERF_SAMPLE_REGS. Well, that's until you look at PEB-LL on Nehalem where is captures latencies and data
addresses.

Quoted 6 lines

Those could be funneled through PERF_SAMPLE_REGS
as well, I believe. But that means, PERF_SAMPLE_REGS would need some configuration
bitmask to name the registers of interest, e.g. EAX, EDX, IBSOP_DATA, IBSOP_PHYSAD,
and so on.

What is the idea of PERF_SAMPLE_REGS? A git grep PERF_SAMPLE_REGS only returns a single line in -tip. I know nothing about it.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#51 lore raw
Quoted 14 lines · Robert Richter
Quoted 6 lines · Stephane Eranian

Okay, so you're suggesting everything is exposed via PERF_SAMPLE_REGS. PEBS does capture machine state which is easily mapped onto PERF_SAMPLE_REGS. Well, that's until you look at PEB-LL on Nehalem where is captures latencies and data
addresses.

Quoted 6 lines

Those could be funneled through PERF_SAMPLE_REGS
as well, I believe. But that means, PERF_SAMPLE_REGS would need some configuration
bitmask to name the registers of interest, e.g. EAX, EDX, IBSOP_DATA, IBSOP_PHYSAD,
and so on.

Quoted 3 lines

What is the idea of PERF_SAMPLE_REGS? A git grep PERF_SAMPLE_REGS only returns a single line in -tip. I know nothing about it.

You may want to collect some of the general purpose registers (interrupted state) in each
sample. This is what you get today in a signal handler (ucontext) for instance. That may
also be a way to export PEBS samples.

#52 lore raw
In reply to Peter Zijlstra
Quoted 10 lines · Peter Zijlstra
Quoted 9 lines · Robert Richter
Quoted 7 lines · Peter Zijlstra
Quoted 2 lines · Robert Richter

This patch series introduces model specific events and impments AMD IBS (Instruction Based Sampling) for perf_events.

I would much rather it uses the ->precise thing PEBS also uses, otherwise we keep growing funny arch extensions and end up with a totally fragmented trainwreck of an ABI.

Quoted 8 lines
Quoted 3 lines

I agree that an exiting flag could be reused. But the naming 'precise' could be misleading. Maybe we rename it to 'model_spec' or something else that underlines the idea of having model specific setups.

Right, so I really hate PERF_SAMPLE_RAW, and I'm considering simply removing that for PEBS as well, its just too ugly. If we want the register set we need to work on getting PERF_SAMPLE_REGS in a sensible shape.

The ABI should provide hw access to all pmu features. As it is not possible to abstract these features for all models and architectures in the same way and a new feature may work completely different, the only solution I see is to provide a way to write to pmu registers and receive sampling data unfiltered back. For IBS for example the data in a sample does not fit into existing generic events. Making IBS generic also does not help much, since it will not be available on different models or architectures. Introducing event types that will never reused do not need to be generalized, it is better to generalize the way how to handle this kind of events. This is the reason I like the model_spec/raw_config/raw_sample approach.

Quoted 3 lines

As to the meaning for ->precise, its meant to convey the counters are not affected by skid and the like, I thought IBS provided exact IPs as well (/me should re-read the IBS docs).

Yes, the real rip is in the sample, but there is much more data than that. So the rip is only a subset.

Quoted 7 lines

The thing with something like ->model_spec and PERF_SAMPLE_RAW is that it doesn't provide a clear model, the user doesn't know what to expect of it, it could be anything.

We want the ABI to express clear concepts, and things like lets bypass everything and just dump stuff out to userspace really are to be avoided at all costs.

Of course, it could be anything. But this is not the intention. If configs and buffers or close or exactly as the hw i/f, then it is spec'ed and well defined. The user only have to know how to configure a certain hw feature of a special model and how to get data back. This is how IBS is implemented. Maybe this is the same that you have in mind with PERF_SAMPLE_REG? This interface can then be reused for a very different feature and this looks to me like a clear solution. I do not see alternatives. And even if we process the samples in the kernel somehow, in the end we pack it and send it to userspace.

Quoted 3 lines

Sadly IBS seems to be an utter trainwreck in the concept department (I'm still struggling how to make a sensible interpretation of the data it gathers).

That's the point, there is no generalization of this type of data, but still it is useful.

-Robert

Quoted 7 lines

The thing I absolutely want to avoid is the ABI becoming a fragmented trainwreck like oprofile is.

Also not using sample_period for the sample period is of course utterly unacceptable.

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
#53 lore raw
In reply to Robert Richter
Quoted 2 lines · Robert Richter

This patch series introduces model specific events and impments AMD IBS (Instruction Based Sampling) for perf_events.

Peter,

I suggest to apply patches 1, 2, 3, 5, 6 to tip/perf/core if you don't have objections. I will then resubmit a new version of all remaining patches.

-Robert

Signature · 3 lines
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
maintainer
#54 lore raw
Quoted 3 lines · Robert Richter

I suggest to apply patches 1, 2, 3, 5, 6 to tip/perf/core if you don't have objections. I will then resubmit a new version of all remaining patches.

Ok, I'm not a big fan of 5, but I guess there's no way around that without adding lots more code.