mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/9] metag: perf fixes and OProfile support
@ 2013-03-15 13:43 James Hogan
  2013-03-15 13:43 ` [PATCH 1/9] metag: perf: fix core internal / perf channel mux James Hogan
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: James Hogan @ 2013-03-15 13:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Hogan, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo, Robert Richter, oprofile-list

This patchset fixes some issues in the Meta support for perf events
(particularly perf counter interrupts), and then adds OProfile support
to the Meta architecture based on perf.

This is aimed at v3.10.

Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Robert Richter <rric@kernel.org>
Cc: oprofile-list@lists.sf.net

James Hogan (9):
  metag: perf: fix core internal / perf channel mux
  metag: perf: fix wrap handling in delta calculation
  metag: perf: fixes for interrupting perf counters
  metag: perf: add missing prev_count updates
  metag: perf: fix frequency sampling (dynamic period)
  metag: perf: use hard_processor_id() to get thread
  metag: perf: don't reset TXTACTCYC
  metag: perf: prepare for use by oprofile
  metag: OProfile support

 arch/metag/Kconfig                  |  4 ++
 arch/metag/Makefile                 |  2 +
 arch/metag/kernel/perf/perf_event.c | 74 +++++++++++++++++++++++++------------
 arch/metag/oprofile/Makefile        | 17 +++++++++
 arch/metag/oprofile/backtrace.c     | 63 +++++++++++++++++++++++++++++++
 arch/metag/oprofile/backtrace.h     |  6 +++
 arch/metag/oprofile/common.c        | 66 +++++++++++++++++++++++++++++++++
 7 files changed, 209 insertions(+), 23 deletions(-)
 create mode 100644 arch/metag/oprofile/Makefile
 create mode 100644 arch/metag/oprofile/backtrace.c
 create mode 100644 arch/metag/oprofile/backtrace.h
 create mode 100644 arch/metag/oprofile/common.c

-- 
1.8.1.2



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/9] metag: perf: fix core internal / perf channel mux
  2013-03-15 13:43 [PATCH 0/9] metag: perf fixes and OProfile support James Hogan
@ 2013-03-15 13:43 ` James Hogan
  2013-03-15 13:43 ` [PATCH 2/9] metag: perf: fix wrap handling in delta calculation James Hogan
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: James Hogan @ 2013-03-15 13:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Hogan, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo

The value written to the PERF_ICOREx or PERF_CHANx register to select
the performance events for the core internal and perf channel events was
(tmp & 0x0f), but tmp was set to (config & 0xf0) so it would always be
0. Correct it to use config instead of tmp.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
---
 arch/metag/kernel/perf/perf_event.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/metag/kernel/perf/perf_event.c b/arch/metag/kernel/perf/perf_event.c
index a876d5f..f38bf6d 100644
--- a/arch/metag/kernel/perf/perf_event.c
+++ b/arch/metag/kernel/perf/perf_event.c
@@ -634,7 +634,7 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
 			break;
 		}
 
-		metag_out32((tmp & 0x0f), perf_addr);
+		metag_out32((config & 0x0f), perf_addr);
 
 		/*
 		 * Now we use the high nibble as the performance event to
-- 
1.8.1.2



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 2/9] metag: perf: fix wrap handling in delta calculation
  2013-03-15 13:43 [PATCH 0/9] metag: perf fixes and OProfile support James Hogan
  2013-03-15 13:43 ` [PATCH 1/9] metag: perf: fix core internal / perf channel mux James Hogan
@ 2013-03-15 13:43 ` James Hogan
  2013-03-15 13:43 ` [PATCH 3/9] metag: perf: fixes for interrupting perf counters James Hogan
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: James Hogan @ 2013-03-15 13:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Hogan, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo

When calculating the delta, mask with MAX_PERIOD (24 bits) to handle
wrapping, which particularly happens with periodic sampling since the
value is intentionally set so that it will overflow soon.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
---
 arch/metag/kernel/perf/perf_event.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/metag/kernel/perf/perf_event.c b/arch/metag/kernel/perf/perf_event.c
index f38bf6d..8096db2 100644
--- a/arch/metag/kernel/perf/perf_event.c
+++ b/arch/metag/kernel/perf/perf_event.c
@@ -211,7 +211,7 @@ again:
 	/*
 	 * Calculate the delta and add it to the counter.
 	 */
-	delta = new_raw_count - prev_raw_count;
+	delta = (new_raw_count - prev_raw_count) & MAX_PERIOD;
 
 	local64_add(delta, &event->count);
 }
-- 
1.8.1.2



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 3/9] metag: perf: fixes for interrupting perf counters
  2013-03-15 13:43 [PATCH 0/9] metag: perf fixes and OProfile support James Hogan
  2013-03-15 13:43 ` [PATCH 1/9] metag: perf: fix core internal / perf channel mux James Hogan
  2013-03-15 13:43 ` [PATCH 2/9] metag: perf: fix wrap handling in delta calculation James Hogan
@ 2013-03-15 13:43 ` James Hogan
  2013-03-15 13:43 ` [PATCH 4/9] metag: perf: add missing prev_count updates James Hogan
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: James Hogan @ 2013-03-15 13:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Hogan, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo

The overflow handler needs to read modify write when re-enabling the
counter so as not to change the counter value as it may have been
changed to ready the next interrupt on overflow. Similarly for
interrupting counters metag_pmu_enable_counter needs to leave the
counter value unchanged rather than resetting it to zero.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
---
 arch/metag/kernel/perf/perf_event.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/arch/metag/kernel/perf/perf_event.c b/arch/metag/kernel/perf/perf_event.c
index 8096db2..a00f527 100644
--- a/arch/metag/kernel/perf/perf_event.c
+++ b/arch/metag/kernel/perf/perf_event.c
@@ -643,13 +643,15 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
 		config = tmp >> 4;
 	}
 
-	/*
-	 * Enabled counters start from 0. Early cores clear the count on
-	 * write but newer cores don't, so we make sure that the count is
-	 * set to 0.
-	 */
 	tmp = ((config & 0xf) << 28) |
 			((1 << 24) << cpu_2_hwthread_id[get_cpu()]);
+	if (metag_pmu->max_period)
+		/*
+		 * Cores supporting overflow interrupts may have had the counter
+		 * set to a specific value that needs preserving.
+		 */
+		tmp |= metag_in32(PERF_COUNT(idx)) & 0x00ffffff;
+
 	metag_out32(tmp, PERF_COUNT(idx));
 unlock:
 	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
@@ -764,10 +766,16 @@ static irqreturn_t metag_pmu_counter_overflow(int irq, void *dev)
 
 	/*
 	 * Enable the counter again once core overflow processing has
-	 * completed.
+	 * completed. Note the counter value may have been modified while it was
+	 * inactive to set it up ready for the next interrupt.
 	 */
-	if (!perf_event_overflow(event, &sampledata, regs))
+	if (!perf_event_overflow(event, &sampledata, regs)) {
+		__global_lock2(flags);
+		counter = (counter & 0xff000000) |
+			  (metag_in32(PERF_COUNT(idx)) & 0x00ffffff);
 		metag_out32(counter, PERF_COUNT(idx));
+		__global_unlock2(flags);
+	}
 
 	return IRQ_HANDLED;
 }
-- 
1.8.1.2



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 4/9] metag: perf: add missing prev_count updates
  2013-03-15 13:43 [PATCH 0/9] metag: perf fixes and OProfile support James Hogan
                   ` (2 preceding siblings ...)
  2013-03-15 13:43 ` [PATCH 3/9] metag: perf: fixes for interrupting perf counters James Hogan
@ 2013-03-15 13:43 ` James Hogan
  2013-03-15 13:43 ` [PATCH 5/9] metag: perf: fix frequency sampling (dynamic period) James Hogan
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: James Hogan @ 2013-03-15 13:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Hogan, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo

The prev_count needs setting when changing the counter value, otherwise
the calculated delta will be wrong, which for frequency sampling
(dynamic period sampling) results in sampling at too high a frequency.

For non-interrupting performance counters it should also be cleared when
enabling the counter since the write to the PERF_COUNT register will
clear the perf counter.

This also includes a minor change to remove the u64 cast from the
metag_pmu->write() call as metag_pmu->write() takes a u32 anyway, and in
any case GCC is smart enough to optimise away the cast.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
---
 arch/metag/kernel/perf/perf_event.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/metag/kernel/perf/perf_event.c b/arch/metag/kernel/perf/perf_event.c
index a00f527..5bf984f 100644
--- a/arch/metag/kernel/perf/perf_event.c
+++ b/arch/metag/kernel/perf/perf_event.c
@@ -240,8 +240,10 @@ int metag_pmu_event_set_period(struct perf_event *event,
 	if (left > (s64)metag_pmu->max_period)
 		left = metag_pmu->max_period;
 
-	if (metag_pmu->write)
-		metag_pmu->write(idx, (u64)(-left) & MAX_PERIOD);
+	if (metag_pmu->write) {
+		local64_set(&hwc->prev_count, -(s32)left);
+		metag_pmu->write(idx, -left & MAX_PERIOD);
+	}
 
 	perf_event_update_userpage(event);
 
@@ -651,6 +653,12 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
 		 * set to a specific value that needs preserving.
 		 */
 		tmp |= metag_in32(PERF_COUNT(idx)) & 0x00ffffff;
+	else
+		/*
+		 * Older cores reset the counter on write, so prev_count needs
+		 * resetting too so we can calculate a correct delta.
+		 */
+		local64_set(&event->prev_count, 0);
 
 	metag_out32(tmp, PERF_COUNT(idx));
 unlock:
-- 
1.8.1.2



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 5/9] metag: perf: fix frequency sampling (dynamic period)
  2013-03-15 13:43 [PATCH 0/9] metag: perf fixes and OProfile support James Hogan
                   ` (3 preceding siblings ...)
  2013-03-15 13:43 ` [PATCH 4/9] metag: perf: add missing prev_count updates James Hogan
@ 2013-03-15 13:43 ` James Hogan
  2013-03-15 13:43 ` [PATCH 6/9] metag: perf: use hard_processor_id() to get thread James Hogan
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: James Hogan @ 2013-03-15 13:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Hogan, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo

Frequency sampling mode dynamically adjusts the sample period so as to
hit a particular frequency of samples. The sample period starts at just
1 and then gets increased if the interrupt rate is too high. This
changed sample period needs handling in metag_pmu_event_set_period to
update period_left (as the ARM equivalent does). The calculated delta
also needs subtracting from period_left in metag_pmu_event_update in
order to hit the conditional blocks in metag_pmu_event_set_period which
update last_period (which is used in the dynamic sampling period
calculation).

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
---
 arch/metag/kernel/perf/perf_event.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/metag/kernel/perf/perf_event.c b/arch/metag/kernel/perf/perf_event.c
index 5bf984f..6210126 100644
--- a/arch/metag/kernel/perf/perf_event.c
+++ b/arch/metag/kernel/perf/perf_event.c
@@ -214,6 +214,7 @@ again:
 	delta = (new_raw_count - prev_raw_count) & MAX_PERIOD;
 
 	local64_add(delta, &event->count);
+	local64_sub(delta, &hwc->period_left);
 }
 
 int metag_pmu_event_set_period(struct perf_event *event,
@@ -223,6 +224,10 @@ int metag_pmu_event_set_period(struct perf_event *event,
 	s64 period = hwc->sample_period;
 	int ret = 0;
 
+	/* The period may have been changed */
+	if (unlikely(period != hwc->last_period))
+		left += period - hwc->last_period;
+
 	if (unlikely(left <= -period)) {
 		left = period;
 		local64_set(&hwc->period_left, left);
-- 
1.8.1.2



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 6/9] metag: perf: use hard_processor_id() to get thread
  2013-03-15 13:43 [PATCH 0/9] metag: perf fixes and OProfile support James Hogan
                   ` (4 preceding siblings ...)
  2013-03-15 13:43 ` [PATCH 5/9] metag: perf: fix frequency sampling (dynamic period) James Hogan
@ 2013-03-15 13:43 ` James Hogan
  2013-03-15 13:43 ` [PATCH 7/9] metag: perf: don't reset TXTACTCYC James Hogan
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: James Hogan @ 2013-03-15 13:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Hogan, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo

Use hard_processor_id() to get the current thread number rather than
get_cpu() and the hardware thread mapping. There was no matching
put_cpu(), and in any case this should be slightly more efficient.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
---
 arch/metag/kernel/perf/perf_event.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/metag/kernel/perf/perf_event.c b/arch/metag/kernel/perf/perf_event.c
index 6210126..54fde35 100644
--- a/arch/metag/kernel/perf/perf_event.c
+++ b/arch/metag/kernel/perf/perf_event.c
@@ -22,9 +22,9 @@
 #include <linux/slab.h>
 
 #include <asm/core_reg.h>
-#include <asm/hwthread.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/processor.h>
 
 #include "perf_event.h"
 
@@ -651,7 +651,7 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
 	}
 
 	tmp = ((config & 0xf) << 28) |
-			((1 << 24) << cpu_2_hwthread_id[get_cpu()]);
+			((1 << 24) << hard_processor_id());
 	if (metag_pmu->max_period)
 		/*
 		 * Cores supporting overflow interrupts may have had the counter
-- 
1.8.1.2



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 7/9] metag: perf: don't reset TXTACTCYC
  2013-03-15 13:43 [PATCH 0/9] metag: perf fixes and OProfile support James Hogan
                   ` (5 preceding siblings ...)
  2013-03-15 13:43 ` [PATCH 6/9] metag: perf: use hard_processor_id() to get thread James Hogan
@ 2013-03-15 13:43 ` James Hogan
  2013-03-15 13:43 ` [PATCH 8/9] metag: perf: prepare for use by oprofile James Hogan
  2013-03-15 13:43 ` [PATCH 9/9] metag: OProfile support James Hogan
  8 siblings, 0 replies; 10+ messages in thread
From: James Hogan @ 2013-03-15 13:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Hogan, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo

The thread active cycle counter TXTACTCYC is used in __delay so it
shouldn't really be reset to zero by perf. Fix perf to just read the
value, and instead of clearing it, record the prev_count value in
enable_counter so that the delta calculations know about the previous
value.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
---
 arch/metag/kernel/perf/perf_event.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/arch/metag/kernel/perf/perf_event.c b/arch/metag/kernel/perf/perf_event.c
index 54fde35..a1eff36 100644
--- a/arch/metag/kernel/perf/perf_event.c
+++ b/arch/metag/kernel/perf/perf_event.c
@@ -617,9 +617,7 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
 		WARN_ONCE((config != 0x100),
 			"invalid configuration (%d) for counter (%d)\n",
 			config, idx);
-
-		/* Reset the cycle count */
-		__core_reg_set(TXTACTCYC, 0);
+		local64_set(&event->prev_count, __core_reg_get(TXTACTCYC));
 		goto unlock;
 	}
 
@@ -708,9 +706,8 @@ static u64 metag_pmu_read_counter(int idx)
 {
 	u32 tmp = 0;
 
-	/* The act of reading the cycle counter also clears it */
 	if (METAG_INST_COUNTER == idx) {
-		__core_reg_swap(TXTACTCYC, tmp);
+		tmp = __core_reg_get(TXTACTCYC);
 		goto out;
 	}
 
-- 
1.8.1.2



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 8/9] metag: perf: prepare for use by oprofile
  2013-03-15 13:43 [PATCH 0/9] metag: perf fixes and OProfile support James Hogan
                   ` (6 preceding siblings ...)
  2013-03-15 13:43 ` [PATCH 7/9] metag: perf: don't reset TXTACTCYC James Hogan
@ 2013-03-15 13:43 ` James Hogan
  2013-03-15 13:43 ` [PATCH 9/9] metag: OProfile support James Hogan
  8 siblings, 0 replies; 10+ messages in thread
From: James Hogan @ 2013-03-15 13:43 UTC (permalink / raw)
  To: linux-kernel
  Cc: James Hogan, Peter Zijlstra, Paul Mackerras, Ingo Molnar,
	Arnaldo Carvalho de Melo, Robert Richter, oprofile-list

To allow our perf_events code to work with oprofile the PERF_TYPE_RAW
event type attribute is implemented, which allows the internal encoding
of events to be used externally (this requires some tweaks so that it
handles invalid event types more gracefully), and perf_pmu_name() is
adjusted to return metag_pmu->name instead of metag_pmu->pmu.name (which
is changed to "meta2").

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Robert Richter <rric@kernel.org>
Cc: oprofile-list@lists.sf.net
---
 arch/metag/kernel/perf/perf_event.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/arch/metag/kernel/perf/perf_event.c b/arch/metag/kernel/perf/perf_event.c
index a1eff36..3665694 100644
--- a/arch/metag/kernel/perf/perf_event.c
+++ b/arch/metag/kernel/perf/perf_event.c
@@ -40,10 +40,10 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
 /* PMU admin */
 const char *perf_pmu_name(void)
 {
-	if (metag_pmu)
-		return metag_pmu->pmu.name;
+	if (!metag_pmu)
+		return NULL;
 
-	return NULL;
+	return metag_pmu->name;
 }
 EXPORT_SYMBOL_GPL(perf_pmu_name);
 
@@ -171,6 +171,7 @@ static int metag_pmu_event_init(struct perf_event *event)
 	switch (event->attr.type) {
 	case PERF_TYPE_HARDWARE:
 	case PERF_TYPE_HW_CACHE:
+	case PERF_TYPE_RAW:
 		err = _hw_perf_event_init(event);
 		break;
 
@@ -556,6 +557,10 @@ static int _hw_perf_event_init(struct perf_event *event)
 		if (err)
 			return err;
 		break;
+
+	case PERF_TYPE_RAW:
+		mapping = attr->config;
+		break;
 	}
 
 	/* Return early if the event is unsupported */
@@ -623,7 +628,7 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
 
 	/* Check for a core internal or performance channel event. */
 	if (tmp) {
-		void *perf_addr = (void *)PERF_COUNT(idx);
+		void *perf_addr;
 
 		/*
 		 * Anything other than a cycle count will write the low-
@@ -637,9 +642,14 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
 		case 0xf0:
 			perf_addr = (void *)PERF_CHAN(idx);
 			break;
+
+		default:
+			perf_addr = NULL;
+			break;
 		}
 
-		metag_out32((config & 0x0f), perf_addr);
+		if (perf_addr)
+			metag_out32((config & 0x0f), perf_addr);
 
 		/*
 		 * Now we use the high nibble as the performance event to
@@ -848,7 +858,7 @@ static int __init init_hw_perf_events(void)
 			metag_pmu->max_period = 0;
 		}
 
-		metag_pmu->name = "Meta 2";
+		metag_pmu->name = "meta2";
 		metag_pmu->version = version;
 		metag_pmu->pmu = pmu;
 	}
-- 
1.8.1.2



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 9/9] metag: OProfile support
  2013-03-15 13:43 [PATCH 0/9] metag: perf fixes and OProfile support James Hogan
                   ` (7 preceding siblings ...)
  2013-03-15 13:43 ` [PATCH 8/9] metag: perf: prepare for use by oprofile James Hogan
@ 2013-03-15 13:43 ` James Hogan
  8 siblings, 0 replies; 10+ messages in thread
From: James Hogan @ 2013-03-15 13:43 UTC (permalink / raw)
  To: linux-kernel; +Cc: James Hogan, Robert Richter, oprofile-list

Add OProfile support for metag, using the perf backend, and falling back
to generic timer based sampling if perf counter interrupt support is
disabled.

The oprofile code prepends "metag/" to the perf pmu name to give
"metag/meta2" which is more consistent with other oprofile arch names.

The backtrace code makes use of <asm/stacktrace.h> for kernel
backtracing, and a simple frame pointer walk for userland backtracing.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Robert Richter <rric@kernel.org>
Cc: oprofile-list@lists.sf.net
---
 arch/metag/Kconfig              |  4 +++
 arch/metag/Makefile             |  2 ++
 arch/metag/oprofile/Makefile    | 17 +++++++++++
 arch/metag/oprofile/backtrace.c | 63 +++++++++++++++++++++++++++++++++++++++
 arch/metag/oprofile/backtrace.h |  6 ++++
 arch/metag/oprofile/common.c    | 66 +++++++++++++++++++++++++++++++++++++++++
 6 files changed, 158 insertions(+)
 create mode 100644 arch/metag/oprofile/Makefile
 create mode 100644 arch/metag/oprofile/backtrace.c
 create mode 100644 arch/metag/oprofile/backtrace.h
 create mode 100644 arch/metag/oprofile/common.c

diff --git a/arch/metag/Kconfig b/arch/metag/Kconfig
index afc8973..b06b418 100644
--- a/arch/metag/Kconfig
+++ b/arch/metag/Kconfig
@@ -25,6 +25,7 @@ config METAG
 	select HAVE_MEMBLOCK
 	select HAVE_MEMBLOCK_NODE_MAP
 	select HAVE_MOD_ARCH_SPECIFIC
+	select HAVE_OPROFILE
 	select HAVE_PERF_EVENTS
 	select HAVE_SYSCALL_TRACEPOINTS
 	select IRQ_DOMAIN
@@ -209,6 +210,9 @@ config METAG_PERFCOUNTER_IRQS
 	  When disabled, Performance Counters information will be collected
 	  based on Timer Interrupt.
 
+config HW_PERF_EVENTS
+	def_bool METAG_PERFCOUNTER_IRQS && PERF_EVENTS
+
 config METAG_DA
 	bool "DA support"
 	help
diff --git a/arch/metag/Makefile b/arch/metag/Makefile
index 81bd6a1..b566116 100644
--- a/arch/metag/Makefile
+++ b/arch/metag/Makefile
@@ -49,6 +49,8 @@ core-y					+= arch/metag/mm/
 libs-y					+= arch/metag/lib/
 libs-y					+= arch/metag/tbx/
 
+drivers-$(CONFIG_OPROFILE)		+= arch/metag/oprofile/
+
 boot					:= arch/metag/boot
 
 boot_targets				+= uImage
diff --git a/arch/metag/oprofile/Makefile b/arch/metag/oprofile/Makefile
new file mode 100644
index 0000000..c9639d4
--- /dev/null
+++ b/arch/metag/oprofile/Makefile
@@ -0,0 +1,17 @@
+obj-$(CONFIG_OPROFILE)	+= oprofile.o
+
+oprofile-core-y	+= buffer_sync.o
+oprofile-core-y	+= cpu_buffer.o
+oprofile-core-y	+= event_buffer.o
+oprofile-core-y	+= oprof.o
+oprofile-core-y	+= oprofile_files.o
+oprofile-core-y	+= oprofile_stats.o
+oprofile-core-y	+= oprofilefs.o
+oprofile-core-y	+= timer_int.o
+oprofile-core-$(CONFIG_HW_PERF_EVENTS)	+= oprofile_perf.o
+
+oprofile-y	+= backtrace.o
+oprofile-y	+= common.o
+oprofile-y	+= $(addprefix ../../../drivers/oprofile/,$(oprofile-core-y))
+
+ccflags-y	+= -Werror
diff --git a/arch/metag/oprofile/backtrace.c b/arch/metag/oprofile/backtrace.c
new file mode 100644
index 0000000..7cc3f37
--- /dev/null
+++ b/arch/metag/oprofile/backtrace.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010-2013 Imagination Technologies Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/oprofile.h>
+#include <linux/uaccess.h>
+#include <asm/processor.h>
+#include <asm/stacktrace.h>
+
+#include "backtrace.h"
+
+static void user_backtrace_fp(unsigned long __user *fp, unsigned int depth)
+{
+	while (depth-- && access_ok(VERIFY_READ, fp, 8)) {
+		unsigned long addr;
+		unsigned long __user *fpnew;
+		if (__copy_from_user_inatomic(&addr, fp + 1, sizeof(addr)))
+			break;
+		addr -= 4;
+
+		oprofile_add_trace(addr);
+
+		/* stack grows up, so frame pointers must decrease */
+		if (__copy_from_user_inatomic(&fpnew, fp + 0, sizeof(fpnew)))
+			break;
+		if (fpnew >= fp)
+			break;
+		fp = fpnew;
+	}
+}
+
+static int kernel_backtrace_frame(struct stackframe *frame, void *data)
+{
+	unsigned int *depth = data;
+
+	oprofile_add_trace(frame->pc);
+
+	/* decrement depth and stop if we reach 0 */
+	if ((*depth)-- == 0)
+		return 1;
+
+	/* otherwise onto the next frame */
+	return 0;
+}
+
+void metag_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+	if (user_mode(regs)) {
+		unsigned long *fp = (unsigned long *)regs->ctx.AX[1].U0;
+		user_backtrace_fp((unsigned long __user __force *)fp, depth);
+	} else {
+		struct stackframe frame;
+		frame.fp = regs->ctx.AX[1].U0;		/* A0FrP */
+		frame.sp = user_stack_pointer(regs);	/* A0StP */
+		frame.lr = 0;				/* from stack */
+		frame.pc = regs->ctx.CurrPC;		/* PC */
+		walk_stackframe(&frame, &kernel_backtrace_frame, &depth);
+	}
+}
diff --git a/arch/metag/oprofile/backtrace.h b/arch/metag/oprofile/backtrace.h
new file mode 100644
index 0000000..c0fcc42
--- /dev/null
+++ b/arch/metag/oprofile/backtrace.h
@@ -0,0 +1,6 @@
+#ifndef _METAG_OPROFILE_BACKTRACE_H
+#define _METAG_OPROFILE_BACKTRACE_H
+
+void metag_backtrace(struct pt_regs * const regs, unsigned int depth);
+
+#endif
diff --git a/arch/metag/oprofile/common.c b/arch/metag/oprofile/common.c
new file mode 100644
index 0000000..ba26152
--- /dev/null
+++ b/arch/metag/oprofile/common.c
@@ -0,0 +1,66 @@
+/*
+ * arch/metag/oprofile/common.c
+ *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ *
+ * Based on arch/sh/oprofile/common.c:
+ *
+ * Copyright (C) 2003 - 2010  Paul Mundt
+ *
+ * Based on arch/mips/oprofile/common.c:
+ *
+ *	Copyright (C) 2004, 2005 Ralf Baechle
+ *	Copyright (C) 2005 MIPS Technologies, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/oprofile.h>
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+
+#include "backtrace.h"
+
+#ifdef CONFIG_HW_PERF_EVENTS
+/*
+ * This will need to be reworked when multiple PMUs are supported.
+ */
+static char *metag_pmu_op_name;
+
+char *op_name_from_perf_id(void)
+{
+	return metag_pmu_op_name;
+}
+
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+	ops->backtrace = metag_backtrace;
+
+	if (perf_num_counters() == 0)
+		return -ENODEV;
+
+	metag_pmu_op_name = kasprintf(GFP_KERNEL, "metag/%s",
+				      perf_pmu_name());
+	if (unlikely(!metag_pmu_op_name))
+		return -ENOMEM;
+
+	return oprofile_perf_init(ops);
+}
+
+void oprofile_arch_exit(void)
+{
+	oprofile_perf_exit();
+	kfree(metag_pmu_op_name);
+}
+#else
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+	ops->backtrace = metag_backtrace;
+	/* fall back to timer interrupt PC sampling */
+	return -ENODEV;
+}
+void oprofile_arch_exit(void) {}
+#endif /* CONFIG_HW_PERF_EVENTS */
-- 
1.8.1.2



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2013-03-15 13:47 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-15 13:43 [PATCH 0/9] metag: perf fixes and OProfile support James Hogan
2013-03-15 13:43 ` [PATCH 1/9] metag: perf: fix core internal / perf channel mux James Hogan
2013-03-15 13:43 ` [PATCH 2/9] metag: perf: fix wrap handling in delta calculation James Hogan
2013-03-15 13:43 ` [PATCH 3/9] metag: perf: fixes for interrupting perf counters James Hogan
2013-03-15 13:43 ` [PATCH 4/9] metag: perf: add missing prev_count updates James Hogan
2013-03-15 13:43 ` [PATCH 5/9] metag: perf: fix frequency sampling (dynamic period) James Hogan
2013-03-15 13:43 ` [PATCH 6/9] metag: perf: use hard_processor_id() to get thread James Hogan
2013-03-15 13:43 ` [PATCH 7/9] metag: perf: don't reset TXTACTCYC James Hogan
2013-03-15 13:43 ` [PATCH 8/9] metag: perf: prepare for use by oprofile James Hogan
2013-03-15 13:43 ` [PATCH 9/9] metag: OProfile support James Hogan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®