git: 90a6e9ef6320 - main - Update hwpmc on armv7 to handle overflow better

Andrew Turner andrew at FreeBSD.org
Fri Jan 8 14:29:50 UTC 2021


The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=90a6e9ef6320d6e48922b32bbefcb07dbb5e1ba7

commit 90a6e9ef6320d6e48922b32bbefcb07dbb5e1ba7
Author:     Andrew Turner <andrew at FreeBSD.org>
AuthorDate: 2021-01-04 13:50:17 +0000
Commit:     Andrew Turner <andrew at FreeBSD.org>
CommitDate: 2021-01-08 14:24:43 +0000

    Update hwpmc on armv7 to handle overflow better
    
    When testing hwpmc on arm64 we found the counter could overflow while
    reading the event count. Handle this case in the armv7 code by also
    checking if the overflow bit is set and incrementing the overflow
    cound as needed.
    
    Sponsored by:   Innovate UK
    Differential Revision:  https://reviews.freebsd.org/D27969
---
 sys/dev/hwpmc/hwpmc_armv7.c | 34 +++++++++++++++++++++++++++-------
 1 file changed, 27 insertions(+), 7 deletions(-)

diff --git a/sys/dev/hwpmc/hwpmc_armv7.c b/sys/dev/hwpmc/hwpmc_armv7.c
index c43f2786655d..bf38b06cfb56 100644
--- a/sys/dev/hwpmc/hwpmc_armv7.c
+++ b/sys/dev/hwpmc/hwpmc_armv7.c
@@ -109,9 +109,13 @@ armv7_counter_disable(unsigned int pmc)
  * Performance Count Register N
  */
 static uint32_t
-armv7_pmcn_read(unsigned int pmc)
+armv7_pmcn_read(unsigned int pmc, uint32_t evsel)
 {
 
+	if (evsel == PMC_EV_CPU_CYCLES) {
+		return ((uint32_t)cp15_pmccntr_get());
+	}
+
 	KASSERT(pmc < armv7_npmcs, ("%s: illegal PMC number %d", __func__, pmc));
 
 	cp15_pmselr_set(pmc);
@@ -165,6 +169,8 @@ armv7_read_pmc(int cpu, int ri, pmc_value_t *v)
 {
 	pmc_value_t tmp;
 	struct pmc *pm;
+	register_t s;
+	u_int reg;
 
 	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
 	    ("[armv7,%d] illegal CPU value %d", __LINE__, cpu));
@@ -173,11 +179,26 @@ armv7_read_pmc(int cpu, int ri, pmc_value_t *v)
 
 	pm  = armv7_pcpu[cpu]->pc_armv7pmcs[ri].phw_pmc;
 
+	s = intr_disable();
+	tmp = armv7_pmcn_read(ri, pm->pm_md.pm_armv7.pm_armv7_evsel);
+
+	/* Check if counter has overflowed */
 	if (pm->pm_md.pm_armv7.pm_armv7_evsel == PMC_EV_CPU_CYCLES)
-		tmp = (uint32_t)cp15_pmccntr_get();
+		reg = (1u << 31);
 	else
-		tmp = armv7_pmcn_read(ri);
+		reg = (1u << ri);
+
+	if ((cp15_pmovsr_get() & reg) != 0) {
+		/* Clear Overflow Flag */
+		cp15_pmovsr_set(reg);
+		if (!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+			pm->pm_overflowcnt += 1;
+
+		/* Reread counter in case we raced. */
+		tmp = armv7_pmcn_read(ri, pm->pm_md.pm_armv7.pm_armv7_evsel);
+	}
 	tmp += 0x100000000llu * pm->pm_overflowcnt;
+	intr_restore(s);
 
 	PMCDBG2(MDP, REA, 2, "armv7-read id=%d -> %jd", ri, tmp);
 	if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
@@ -205,6 +226,7 @@ armv7_write_pmc(int cpu, int ri, pmc_value_t v)
 	
 	PMCDBG3(MDP, WRI, 1, "armv7-write cpu=%d ri=%d v=%jx", cpu, ri, v);
 
+	pm->pm_overflowcnt = v >> 32;
 	if (pm->pm_md.pm_armv7.pm_armv7_evsel == PMC_EV_CPU_CYCLES)
 		cp15_pmccntr_set(v);
 	else
@@ -247,8 +269,6 @@ armv7_start_pmc(int cpu, int ri)
 	pm     = phw->phw_pmc;
 	config = pm->pm_md.pm_armv7.pm_armv7_evsel;
 
-	pm->pm_overflowcnt = 0;
-
 	/*
 	 * Configure the event selection.
 	 */
@@ -329,9 +349,9 @@ armv7_intr(struct trapframe *tf)
 
 		/* Check if counter has overflowed */
 		if (pm->pm_md.pm_armv7.pm_armv7_evsel == PMC_EV_CPU_CYCLES)
-			reg = (1 << 31);
+			reg = (1u << 31);
 		else
-			reg = (1 << ri);
+			reg = (1u << ri);
 
 		if ((cp15_pmovsr_get() & reg) == 0) {
 			continue;


More information about the dev-commits-src-all mailing list