
From: Mikael Pettersson <mikpe@csd.uu.se>

perfctr ppc64 ABI update:
- <asm-ppc64/perfctr.h>: In user-visible state, make start fields
  64 bits (for future-proofing the ABI). Remove map field from
  pmc[] array to avoid underutilised cache lines.
- ppc64.c: retrieve mapping from ->control.pmc_map[].
- ppc64: Add sampling counter to user-visible state, and
  increment it in perfctr_cpu_resume() and perfctr_cpu_sample().

Signed-off-by: Mikael Pettersson <mikpe@csd.uu.se>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/drivers/perfctr/ppc64.c     |   16 ++++++++--------
 25-akpm/include/asm-ppc64/perfctr.h |   13 ++++++++-----
 2 files changed, 16 insertions(+), 13 deletions(-)

diff -puN drivers/perfctr/ppc64.c~perfctr-ppc64-abi-update drivers/perfctr/ppc64.c
--- 25/drivers/perfctr/ppc64.c~perfctr-ppc64-abi-update	2005-04-10 15:11:11.000000000 -0700
+++ 25-akpm/drivers/perfctr/ppc64.c	2005-04-10 15:11:11.000000000 -0700
@@ -244,7 +244,7 @@ static void perfctr_cpu_read_counters(st
 		ctrs->tsc = mftb() & 0xffffffff;
 
 	for (i = 0; i < perfctr_cstatus_nractrs(cstatus); ++i) {
-		pmc = state->user.pmc[i].map;
+		pmc = state->control.pmc_map[i];
 		ctrs->pmc[i] = read_pmc(pmc);
 	}
 }
@@ -260,7 +260,7 @@ static void perfctr_cpu_isuspend(struct 
 	cstatus = state->user.cstatus;
 	nrctrs = perfctr_cstatus_nrctrs(cstatus);
 	for (i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
-		unsigned int pmc = state->user.pmc[i].map;
+		unsigned int pmc = state->control.pmc_map[i];
 		unsigned int now = read_pmc(pmc);
 
 		state->user.pmc[i].sum += now - state->user.pmc[i].start;
@@ -299,7 +299,7 @@ static void perfctr_cpu_iresume(const st
 	cstatus = state->user.cstatus;
 	nrctrs = perfctr_cstatus_nrctrs(cstatus);
 	for (i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
-		write_pmc(state->user.pmc[i].map, state->user.pmc[i].start);
+		write_pmc(state->control.pmc_map[i], state->user.pmc[i].start);
 	}
 }
 
@@ -334,7 +334,7 @@ unsigned int perfctr_cpu_identify_overfl
 	 * amd unused PMCs as well as the ones we actually care
 	 * about. */
 	for (i = 0; i < nractrs; ++i) {
-		int pmc = state->user.pmc[i].map;
+		int pmc = state->control.pmc_map[i];
 		unsigned int val = read_pmc(pmc);
 
 		/* For actrs, force a sample if they overflowed */
@@ -347,7 +347,7 @@ unsigned int perfctr_cpu_identify_overfl
 	}
 	for (; i < nrctrs; ++i) {
 		if ((int)state->user.pmc[i].start < 0) { /* PPC64-specific */
-			int pmc = state->user.pmc[i].map;
+			int pmc = state->control.pmc_map[i];
 			/* XXX: "+=" to correct for overshots */
 			state->user.pmc[i].start = state->control.ireset[pmc];
 			pmc_mask |= (1 << i);
@@ -376,7 +376,7 @@ static inline int check_ireset(struct pe
 	i = state->control.header.nractrs;
 	nrctrs = i + state->control.header.nrictrs;
 	for(; i < nrctrs; ++i) {
-		unsigned int pmc = state->user.pmc[i].map;
+		unsigned int pmc = state->control.pmc_map[i];
 		if ((int)state->control.ireset[pmc] < 0) /* PPC64-specific */
 			return -EINVAL;
 		state->user.pmc[i].start = state->control.ireset[pmc];
@@ -406,7 +406,6 @@ static int check_control(struct perfctr_
 	pmc_mask = 0;
 	for (i = 0; i < nrctrs; ++i) {
 		pmc = state->control.pmc_map[i];
-		state->user.pmc[i].map = pmc;
 		if (pmc >= nr_pmcs || (pmc_mask & (1<<pmc)))
 			return -EINVAL;
 		pmc_mask |= (1<<pmc);
@@ -571,7 +570,7 @@ void perfctr_cpu_resume(struct perfctr_c
 	for (i = 0; i < perfctr_cstatus_nractrs(cstatus); ++i)
 		state->user.pmc[i].start = now.pmc[i];
 
-	/* XXX: if (SMP && start.tsc == now.tsc) ++now.tsc; */
+	++state->user.samplecnt;
 }
 
 void perfctr_cpu_sample(struct perfctr_cpu_state *state)
@@ -590,6 +589,7 @@ void perfctr_cpu_sample(struct perfctr_c
 		state->user.pmc[i].sum += now.pmc[i] - state->user.pmc[i].start;
 		state->user.pmc[i].start = now.pmc[i];
 	}
+	++state->user.samplecnt;
 }
 
 static void perfctr_cpu_clear_counters(void)
diff -puN include/asm-ppc64/perfctr.h~perfctr-ppc64-abi-update include/asm-ppc64/perfctr.h
--- 25/include/asm-ppc64/perfctr.h~perfctr-ppc64-abi-update	2005-04-10 15:11:11.000000000 -0700
+++ 25-akpm/include/asm-ppc64/perfctr.h	2005-04-10 15:11:11.000000000 -0700
@@ -22,13 +22,16 @@ struct perfctr_cpu_control_header {
 
 struct perfctr_cpu_state_user {
 	__u32 cstatus;
-	/* The two tsc fields must be inlined. Placing them in a
-	   sub-struct causes unwanted internal padding on x86-64. */
-	__u32 tsc_start;
+	/* 'samplecnt' is incremented every time the 'start'
+	   fields have been updated by a sampling operation.
+	   Unfortunately the PPC timebase (tsc_start) has too
+	   low frequency for it to be a reliable context-switch
+	   indicator for user-space. */
+	__u32 samplecnt;
+	__u64 tsc_start;
 	__u64 tsc_sum;
 	struct {
-		__u32 map;
-		__u32 start;
+		__u64 start;
 		__u64 sum;
 	} pmc[8];	/* the size is not part of the user ABI */
 };
_
