[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1348806696-31170-23-git-send-email-andi@firstfloor.org>
Date: Thu, 27 Sep 2012 21:31:27 -0700
From: Andi Kleen <andi@...stfloor.org>
To: linux-kernel@...r.kernel.org
Cc: x86@...nel.org, a.p.zijlstra@...llo.nl, eranian@...gle.com,
acme@...hat.com, Andi Kleen <ak@...ux.intel.com>
Subject: [PATCH 22/31] perf, core: Define generic hardware transaction events
From: Andi Kleen <ak@...ux.intel.com>
For tuning and debugging hardware transactional memory it is very
important to have hardware counter support.
This patch adds a simple and hopefully generic set of hardware events
for transactional memory and lock elision.
It is based on the TSX PMU support because I don't have any
information on other CPU's HTM support.
There are start, commit and abort events for transactions and
for lock elision.
The abort events are qualified by a generic abort reason that should
be roughly applicable to a wide range of memory transaction systems:
capacity for the buffering capacity
conflict for a dynamic conflict between CPUs
all for all aborts. On TSX this can be precisely sampled.
We need to split the events into general transaction events and lock
elision events. Architecturs with HTM but no lock elision would only
use the first set.
Implementation for Haswell in a followon patch.
Signed-off-by: Andi Kleen <ak@...ux.intel.com>
---
arch/x86/kernel/cpu/perf_event.c | 36 ++++++++++++++++++++++++++++++++++++
arch/x86/kernel/cpu/perf_event.h | 4 ++++
include/linux/perf_event.h | 25 +++++++++++++++++++++++++
3 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 87c2ab0..cee8f80 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -53,6 +53,13 @@ u64 __read_mostly hw_cache_extra_regs
[PERF_COUNT_HW_CACHE_RESULT_MAX];
/*
+ * Generalized transactional memory event table.
+ */
+u64 __read_mostly hw_transaction_event_ids
+ [PERF_COUNT_HW_TRANSACTION_MAX]
+ [PERF_COUNT_HW_ABORT_MAX];
+
+/*
* Propagate event elapsed time into the generic event.
* Can only be executed on the CPU where the event is active.
* Returns the delta events processed.
@@ -285,6 +292,31 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event *event)
return x86_pmu_extra_regs(val, event);
}
+static int
+set_hw_transaction_attr(struct hw_perf_event *hwc, struct perf_event *event)
+{
+ struct perf_event_attr *attr = &event->attr;
+ u64 config, val;
+ unsigned int op, reason;
+
+ config = attr->config;
+ op = config & 0xff;
+ if (op >= PERF_COUNT_HW_TRANSACTION_MAX)
+ return -EINVAL;
+ reason = (config >> 8) & 0xff;
+ if (reason >= PERF_COUNT_HW_ABORT_MAX)
+ return -EINVAL;
+ if (config >> 16)
+ return -EINVAL;
+ val = hw_transaction_event_ids[config][reason];
+ if (val == 0)
+ return -ENOENT;
+ if (val == -1)
+ return -EINVAL;
+ hwc->config |= val;
+ return 0;
+}
+
int x86_setup_perfctr(struct perf_event *event)
{
struct perf_event_attr *attr = &event->attr;
@@ -312,6 +344,9 @@ int x86_setup_perfctr(struct perf_event *event)
if (attr->type == PERF_TYPE_HW_CACHE)
return set_ext_hw_attr(hwc, event);
+ if (attr->type == PERF_TYPE_HW_TRANSACTION)
+ return set_hw_transaction_attr(hwc, event);
+
if (attr->config >= x86_pmu.max_events)
return -EINVAL;
@@ -1547,6 +1582,7 @@ static int x86_pmu_event_init(struct perf_event *event)
case PERF_TYPE_RAW:
case PERF_TYPE_HARDWARE:
case PERF_TYPE_HW_CACHE:
+ case PERF_TYPE_HW_TRANSACTION:
break;
default:
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 724a141..6a8730e 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -452,6 +452,10 @@ extern u64 __read_mostly hw_cache_extra_regs
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX];
+extern u64 __read_mostly hw_transaction_event_ids
+ [PERF_COUNT_HW_TRANSACTION_MAX]
+ [PERF_COUNT_HW_ABORT_MAX];
+
u64 x86_perf_event_update(struct perf_event *event);
static inline int x86_pmu_addr_offset(int index)
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index c488ae2..1867bed 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -32,6 +32,7 @@ enum perf_type_id {
PERF_TYPE_HW_CACHE = 3,
PERF_TYPE_RAW = 4,
PERF_TYPE_BREAKPOINT = 5,
+ PERF_TYPE_HW_TRANSACTION = 6,
PERF_TYPE_MAX, /* non-ABI */
};
@@ -94,6 +95,30 @@ enum perf_hw_cache_op_result_id {
};
/*
+ * Transactional memory related events:
+ * { op, reason } (8 bits each)
+ * Only aborts have a reason.
+ */
+enum perf_hw_transaction_op_id {
+ PERF_COUNT_HW_TRANSACTION_START = 0,
+ PERF_COUNT_HW_TRANSACTION_COMMIT = 1,
+ PERF_COUNT_HW_TRANSACTION_ABORT = 2, /* qualified by reason */
+ PERF_COUNT_HW_ELISION_START = 3,
+ PERF_COUNT_HW_ELISION_COMMIT = 4,
+ PERF_COUNT_HW_ELISION_ABORT = 5, /* qualified by reason */
+
+ PERF_COUNT_HW_TRANSACTION_MAX, /* non-ABI */
+};
+
+enum perf_transaction_abort_reason_id {
+ PERF_COUNT_HW_ABORT_ALL = 0, /* all aborts */
+ PERF_COUNT_HW_ABORT_CONFLICT = 1, /* conflict with other CPU */
+ PERF_COUNT_HW_ABORT_CAPACITY = 2, /* abort due to capacity */
+
+ PERF_COUNT_HW_ABORT_MAX, /* non-ABI */
+};
+
+/*
* Special "software" events provided by the kernel, even if the hardware
* does not support performance events. These events measure various
* physical and sw events of the kernel (and allow the profiling of them as
--
1.7.7.6
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists