All of lore.kernel.org
 help / color / mirror / Atom feed
* [kvm-unit-tests PATCH 0/3] arm: pmu: Add support for PMUv3p5
@ 2022-12-02  4:55 ` Ricardo Koller
  0 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-02  4:55 UTC (permalink / raw)
  To: kvm, kvmarm, andrew.jones
  Cc: maz, alexandru.elisei, eric.auger, oliver.upton, reijiw, Ricardo Koller

The first commit fixes the tests when running on PMUv3p5. The issue is that
PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
for overflowing at 32 or 64-bits. Tests are currently failing [0] on
PMUv3p5 because of this. They wrongly assume that values will be wrapped
around 32-bits, but they overflow into the other half of the 64-bit
counters.

The second and third commits add new tests for 64-bit overflows, a feature
added with PMUv3p5 (PMCR_EL0.LP == 1). This is done by running all
overflow-related tests in two modes: with 32-bit and 64-bit overflows.

This series was tested on PMUv3p5 and PMUv3p4 using the ARM Fast Model and
kvmtool.  All tests pass on both PMUv3p5 and PMUv3p4 when using Marc's
PMUv3p5 series [0], plus the suggestion made at [1]. Didn't test AArch32.

[0] https://lore.kernel.org/kvmarm/20221113163832.3154370-1-maz@kernel.org/
[1] https://lore.kernel.org/kvmarm/Y4jasyxvFRNvvmox@google.com/

Ricardo Koller (3):
  arm: pmu: Fix overflow checks for PMUv3p5 long counters
  arm: pmu: Prepare for testing 64-bit overflows
  arm: pmu: Add tests for 64-bit overflows

 arm/pmu.c | 217 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 133 insertions(+), 84 deletions(-)

-- 
2.39.0.rc0.267.gcb52ba06e7-goog


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

* [kvm-unit-tests PATCH 0/3] arm: pmu: Add support for PMUv3p5
@ 2022-12-02  4:55 ` Ricardo Koller
  0 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-02  4:55 UTC (permalink / raw)
  To: kvm, kvmarm, andrew.jones; +Cc: maz

The first commit fixes the tests when running on PMUv3p5. The issue is that
PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
for overflowing at 32 or 64-bits. Tests are currently failing [0] on
PMUv3p5 because of this. They wrongly assume that values will be wrapped
around 32-bits, but they overflow into the other half of the 64-bit
counters.

The second and third commits add new tests for 64-bit overflows, a feature
added with PMUv3p5 (PMCR_EL0.LP == 1). This is done by running all
overflow-related tests in two modes: with 32-bit and 64-bit overflows.

This series was tested on PMUv3p5 and PMUv3p4 using the ARM Fast Model and
kvmtool.  All tests pass on both PMUv3p5 and PMUv3p4 when using Marc's
PMUv3p5 series [0], plus the suggestion made at [1]. Didn't test AArch32.

[0] https://lore.kernel.org/kvmarm/20221113163832.3154370-1-maz@kernel.org/
[1] https://lore.kernel.org/kvmarm/Y4jasyxvFRNvvmox@google.com/

Ricardo Koller (3):
  arm: pmu: Fix overflow checks for PMUv3p5 long counters
  arm: pmu: Prepare for testing 64-bit overflows
  arm: pmu: Add tests for 64-bit overflows

 arm/pmu.c | 217 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 133 insertions(+), 84 deletions(-)

-- 
2.39.0.rc0.267.gcb52ba06e7-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-02  4:55 ` Ricardo Koller
@ 2022-12-02  4:55   ` Ricardo Koller
  -1 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-02  4:55 UTC (permalink / raw)
  To: kvm, kvmarm, andrew.jones
  Cc: maz, alexandru.elisei, eric.auger, oliver.upton, reijiw, Ricardo Koller

PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
for overflowing at 32 or 64-bits. The consequence is that tests that check
the counter values after overflowing should not assume that values will be
wrapped around 32-bits: they overflow into the other half of the 64-bit
counters on PMUv3p5.

Fix tests by correctly checking overflowing-counters against the expected
64-bit value.

Signed-off-by: Ricardo Koller <ricarkol@google.com>
---
 arm/pmu.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/arm/pmu.c b/arm/pmu.c
index cd47b14..eeac984 100644
--- a/arm/pmu.c
+++ b/arm/pmu.c
@@ -54,10 +54,10 @@
 #define EXT_COMMON_EVENTS_LOW	0x4000
 #define EXT_COMMON_EVENTS_HIGH	0x403F
 
-#define ALL_SET			0xFFFFFFFF
-#define ALL_CLEAR		0x0
-#define PRE_OVERFLOW		0xFFFFFFF0
-#define PRE_OVERFLOW2		0xFFFFFFDC
+#define ALL_SET			0x00000000FFFFFFFFULL
+#define ALL_CLEAR		0x0000000000000000ULL
+#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
+#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
 
 #define PMU_PPI			23
 
@@ -538,6 +538,7 @@ static void test_mem_access(void)
 static void test_sw_incr(void)
 {
 	uint32_t events[] = {SW_INCR, SW_INCR};
+	uint64_t cntr0;
 	int i;
 
 	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
@@ -572,9 +573,9 @@ static void test_sw_incr(void)
 		write_sysreg(0x3, pmswinc_el0);
 
 	isb();
-	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
-	report(read_regn_el0(pmevcntr, 1)  == 100,
-		"counter #0 after + 100 SW_INCR");
+	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
+	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
+	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
 	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
 		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
 	report(read_sysreg(pmovsclr_el0) == 0x1,
@@ -584,6 +585,7 @@ static void test_sw_incr(void)
 static void test_chained_counters(void)
 {
 	uint32_t events[] = {CPU_CYCLES, CHAIN};
+	uint64_t cntr1;
 
 	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
 		return;
@@ -618,13 +620,16 @@ static void test_chained_counters(void)
 
 	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
 	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
-	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
+	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
+	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
+
 	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
 }
 
 static void test_chained_sw_incr(void)
 {
 	uint32_t events[] = {SW_INCR, CHAIN};
+	uint64_t cntr0, cntr1;
 	int i;
 
 	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
@@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
 		write_sysreg(0x1, pmswinc_el0);
 
 	isb();
+	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
+	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
 	report((read_sysreg(pmovsclr_el0) == 0x3) &&
-		(read_regn_el0(pmevcntr, 1) == 0) &&
-		(read_regn_el0(pmevcntr, 0) == 84),
-		"expected overflows and values after 100 SW_INCR/CHAIN");
+	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
+	       (read_regn_el0(pmevcntr, 0) == cntr1),
+	       "expected overflows and values after 100 SW_INCR/CHAIN");
 	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
 		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
 }
-- 
2.39.0.rc0.267.gcb52ba06e7-goog


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

* [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-02  4:55   ` Ricardo Koller
  0 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-02  4:55 UTC (permalink / raw)
  To: kvm, kvmarm, andrew.jones; +Cc: maz

PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
for overflowing at 32 or 64-bits. The consequence is that tests that check
the counter values after overflowing should not assume that values will be
wrapped around 32-bits: they overflow into the other half of the 64-bit
counters on PMUv3p5.

Fix tests by correctly checking overflowing-counters against the expected
64-bit value.

Signed-off-by: Ricardo Koller <ricarkol@google.com>
---
 arm/pmu.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/arm/pmu.c b/arm/pmu.c
index cd47b14..eeac984 100644
--- a/arm/pmu.c
+++ b/arm/pmu.c
@@ -54,10 +54,10 @@
 #define EXT_COMMON_EVENTS_LOW	0x4000
 #define EXT_COMMON_EVENTS_HIGH	0x403F
 
-#define ALL_SET			0xFFFFFFFF
-#define ALL_CLEAR		0x0
-#define PRE_OVERFLOW		0xFFFFFFF0
-#define PRE_OVERFLOW2		0xFFFFFFDC
+#define ALL_SET			0x00000000FFFFFFFFULL
+#define ALL_CLEAR		0x0000000000000000ULL
+#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
+#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
 
 #define PMU_PPI			23
 
@@ -538,6 +538,7 @@ static void test_mem_access(void)
 static void test_sw_incr(void)
 {
 	uint32_t events[] = {SW_INCR, SW_INCR};
+	uint64_t cntr0;
 	int i;
 
 	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
@@ -572,9 +573,9 @@ static void test_sw_incr(void)
 		write_sysreg(0x3, pmswinc_el0);
 
 	isb();
-	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
-	report(read_regn_el0(pmevcntr, 1)  == 100,
-		"counter #0 after + 100 SW_INCR");
+	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
+	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
+	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
 	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
 		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
 	report(read_sysreg(pmovsclr_el0) == 0x1,
@@ -584,6 +585,7 @@ static void test_sw_incr(void)
 static void test_chained_counters(void)
 {
 	uint32_t events[] = {CPU_CYCLES, CHAIN};
+	uint64_t cntr1;
 
 	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
 		return;
@@ -618,13 +620,16 @@ static void test_chained_counters(void)
 
 	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
 	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
-	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
+	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
+	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
+
 	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
 }
 
 static void test_chained_sw_incr(void)
 {
 	uint32_t events[] = {SW_INCR, CHAIN};
+	uint64_t cntr0, cntr1;
 	int i;
 
 	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
@@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
 		write_sysreg(0x1, pmswinc_el0);
 
 	isb();
+	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
+	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
 	report((read_sysreg(pmovsclr_el0) == 0x3) &&
-		(read_regn_el0(pmevcntr, 1) == 0) &&
-		(read_regn_el0(pmevcntr, 0) == 84),
-		"expected overflows and values after 100 SW_INCR/CHAIN");
+	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
+	       (read_regn_el0(pmevcntr, 0) == cntr1),
+	       "expected overflows and values after 100 SW_INCR/CHAIN");
 	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
 		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
 }
-- 
2.39.0.rc0.267.gcb52ba06e7-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [kvm-unit-tests PATCH 2/3] arm: pmu: Prepare for testing 64-bit overflows
  2022-12-02  4:55 ` Ricardo Koller
@ 2022-12-02  4:55   ` Ricardo Koller
  -1 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-02  4:55 UTC (permalink / raw)
  To: kvm, kvmarm, andrew.jones
  Cc: maz, alexandru.elisei, eric.auger, oliver.upton, reijiw, Ricardo Koller

PMUv3p5 adds a knob, PMCR_EL0.LP == 1, that allows overflowing at 64-bits
instead of 32. Prepare by doing these 3 things:

1. Add a "bool overflow_at_64bits" argument to all tests checking
   overflows.
2. Extend satisfy_prerequisites() to check if the machine supports
   "overflow_at_64bits".
3. Refactor the test invocations to use the new "run_test()" which adds a
   report prefix indicating whether the test uses 64 or 32-bit overflows.

A subsequent commit will actually add the 64-bit overflow tests.

Signed-off-by: Ricardo Koller <ricarkol@google.com>
---
 arm/pmu.c | 99 +++++++++++++++++++++++++++++++------------------------
 1 file changed, 56 insertions(+), 43 deletions(-)

diff --git a/arm/pmu.c b/arm/pmu.c
index eeac984..59e5bfe 100644
--- a/arm/pmu.c
+++ b/arm/pmu.c
@@ -164,13 +164,13 @@ static void pmu_reset(void)
 /* event counter tests only implemented for aarch64 */
 static void test_event_introspection(void) {}
 static void test_event_counter_config(void) {}
-static void test_basic_event_count(void) {}
-static void test_mem_access(void) {}
-static void test_sw_incr(void) {}
-static void test_chained_counters(void) {}
-static void test_chained_sw_incr(void) {}
-static void test_chain_promotion(void) {}
-static void test_overflow_interrupt(void) {}
+static void test_basic_event_count(bool overflow_at_64bits) {}
+static void test_mem_access(bool overflow_at_64bits) {}
+static void test_sw_incr(bool overflow_at_64bits) {}
+static void test_chained_counters(bool overflow_at_64bits) {}
+static void test_chained_sw_incr(bool overflow_at_64bits) {}
+static void test_chain_promotion(bool overflow_at_64bits) {}
+static void test_overflow_interrupt(bool overflow_at_64bits) {}
 
 #elif defined(__aarch64__)
 #define ID_AA64DFR0_PERFMON_SHIFT 8
@@ -399,7 +399,8 @@ static void test_event_counter_config(void)
 		"read of a counter programmed with unsupported event");
 }
 
-static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events)
+static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events,
+				  bool overflow_at_64bits)
 {
 	int i;
 
@@ -416,16 +417,23 @@ static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events)
 			return false;
 		}
 	}
+
+	if (overflow_at_64bits && pmu.version < ID_DFR0_PMU_V3_8_5) {
+		report_skip("Skip test as 64 overflows need FEAT_PMUv3p5");
+		return false;
+	}
+
 	return true;
 }
 
-static void test_basic_event_count(void)
+static void test_basic_event_count(bool overflow_at_64bits)
 {
 	uint32_t implemented_counter_mask, non_implemented_counter_mask;
 	uint32_t counter_mask;
 	uint32_t events[] = {CPU_CYCLES, INST_RETIRED};
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	implemented_counter_mask = BIT(pmu.nb_implemented_counters) - 1;
@@ -499,12 +507,13 @@ static void test_basic_event_count(void)
 		"check overflow happened on #0 only");
 }
 
-static void test_mem_access(void)
+static void test_mem_access(bool overflow_at_64bits)
 {
 	void *addr = malloc(PAGE_SIZE);
 	uint32_t events[] = {MEM_ACCESS, MEM_ACCESS};
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	pmu_reset();
@@ -535,13 +544,14 @@ static void test_mem_access(void)
 			read_sysreg(pmovsclr_el0));
 }
 
-static void test_sw_incr(void)
+static void test_sw_incr(bool overflow_at_64bits)
 {
 	uint32_t events[] = {SW_INCR, SW_INCR};
 	uint64_t cntr0;
 	int i;
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	pmu_reset();
@@ -582,12 +592,13 @@ static void test_sw_incr(void)
 		"overflow on counter #0 after 100 SW_INCR");
 }
 
-static void test_chained_counters(void)
+static void test_chained_counters(bool overflow_at_64bits)
 {
 	uint32_t events[] = {CPU_CYCLES, CHAIN};
 	uint64_t cntr1;
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	pmu_reset();
@@ -626,13 +637,14 @@ static void test_chained_counters(void)
 	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
 }
 
-static void test_chained_sw_incr(void)
+static void test_chained_sw_incr(bool overflow_at_64bits)
 {
 	uint32_t events[] = {SW_INCR, CHAIN};
 	uint64_t cntr0, cntr1;
 	int i;
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	pmu_reset();
@@ -680,12 +692,13 @@ static void test_chained_sw_incr(void)
 		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
 }
 
-static void test_chain_promotion(void)
+static void test_chain_promotion(bool overflow_at_64bits)
 {
 	uint32_t events[] = {MEM_ACCESS, CHAIN};
 	void *addr = malloc(PAGE_SIZE);
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	/* Only enable CHAIN counter */
@@ -829,13 +842,14 @@ static bool expect_interrupts(uint32_t bitmap)
 	return true;
 }
 
-static void test_overflow_interrupt(void)
+static void test_overflow_interrupt(bool overflow_at_64bits)
 {
 	uint32_t events[] = {MEM_ACCESS, SW_INCR};
 	void *addr = malloc(PAGE_SIZE);
 	int i;
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	gic_enable_defaults();
@@ -1059,6 +1073,19 @@ static bool pmu_probe(void)
 	return true;
 }
 
+static void run_test(char *name, void (*test)(bool), bool overflow_at_64bits)
+{
+	const char *prefix = overflow_at_64bits ? "64-bit" : "32-bit";
+
+	report_prefix_push(name);
+	report_prefix_push(prefix);
+
+	test(overflow_at_64bits);
+
+	report_prefix_pop();
+	report_prefix_pop();
+}
+
 int main(int argc, char *argv[])
 {
 	int cpi = 0;
@@ -1091,33 +1118,19 @@ int main(int argc, char *argv[])
 		test_event_counter_config();
 		report_prefix_pop();
 	} else if (strcmp(argv[1], "pmu-basic-event-count") == 0) {
-		report_prefix_push(argv[1]);
-		test_basic_event_count();
-		report_prefix_pop();
+		run_test(argv[1], test_basic_event_count, false);
 	} else if (strcmp(argv[1], "pmu-mem-access") == 0) {
-		report_prefix_push(argv[1]);
-		test_mem_access();
-		report_prefix_pop();
+		run_test(argv[1], test_mem_access, false);
 	} else if (strcmp(argv[1], "pmu-sw-incr") == 0) {
-		report_prefix_push(argv[1]);
-		test_sw_incr();
-		report_prefix_pop();
+		run_test(argv[1], test_sw_incr, false);
 	} else if (strcmp(argv[1], "pmu-chained-counters") == 0) {
-		report_prefix_push(argv[1]);
-		test_chained_counters();
-		report_prefix_pop();
+		run_test(argv[1], test_chained_counters, false);
 	} else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) {
-		report_prefix_push(argv[1]);
-		test_chained_sw_incr();
-		report_prefix_pop();
+		run_test(argv[1], test_chained_sw_incr, false);
 	} else if (strcmp(argv[1], "pmu-chain-promotion") == 0) {
-		report_prefix_push(argv[1]);
-		test_chain_promotion();
-		report_prefix_pop();
+		run_test(argv[1], test_chain_promotion, false);
 	} else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) {
-		report_prefix_push(argv[1]);
-		test_overflow_interrupt();
-		report_prefix_pop();
+		run_test(argv[1], test_overflow_interrupt, false);
 	} else {
 		report_abort("Unknown sub-test '%s'", argv[1]);
 	}
-- 
2.39.0.rc0.267.gcb52ba06e7-goog


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

* [kvm-unit-tests PATCH 2/3] arm: pmu: Prepare for testing 64-bit overflows
@ 2022-12-02  4:55   ` Ricardo Koller
  0 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-02  4:55 UTC (permalink / raw)
  To: kvm, kvmarm, andrew.jones; +Cc: maz

PMUv3p5 adds a knob, PMCR_EL0.LP == 1, that allows overflowing at 64-bits
instead of 32. Prepare by doing these 3 things:

1. Add a "bool overflow_at_64bits" argument to all tests checking
   overflows.
2. Extend satisfy_prerequisites() to check if the machine supports
   "overflow_at_64bits".
3. Refactor the test invocations to use the new "run_test()" which adds a
   report prefix indicating whether the test uses 64 or 32-bit overflows.

A subsequent commit will actually add the 64-bit overflow tests.

Signed-off-by: Ricardo Koller <ricarkol@google.com>
---
 arm/pmu.c | 99 +++++++++++++++++++++++++++++++------------------------
 1 file changed, 56 insertions(+), 43 deletions(-)

diff --git a/arm/pmu.c b/arm/pmu.c
index eeac984..59e5bfe 100644
--- a/arm/pmu.c
+++ b/arm/pmu.c
@@ -164,13 +164,13 @@ static void pmu_reset(void)
 /* event counter tests only implemented for aarch64 */
 static void test_event_introspection(void) {}
 static void test_event_counter_config(void) {}
-static void test_basic_event_count(void) {}
-static void test_mem_access(void) {}
-static void test_sw_incr(void) {}
-static void test_chained_counters(void) {}
-static void test_chained_sw_incr(void) {}
-static void test_chain_promotion(void) {}
-static void test_overflow_interrupt(void) {}
+static void test_basic_event_count(bool overflow_at_64bits) {}
+static void test_mem_access(bool overflow_at_64bits) {}
+static void test_sw_incr(bool overflow_at_64bits) {}
+static void test_chained_counters(bool overflow_at_64bits) {}
+static void test_chained_sw_incr(bool overflow_at_64bits) {}
+static void test_chain_promotion(bool overflow_at_64bits) {}
+static void test_overflow_interrupt(bool overflow_at_64bits) {}
 
 #elif defined(__aarch64__)
 #define ID_AA64DFR0_PERFMON_SHIFT 8
@@ -399,7 +399,8 @@ static void test_event_counter_config(void)
 		"read of a counter programmed with unsupported event");
 }
 
-static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events)
+static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events,
+				  bool overflow_at_64bits)
 {
 	int i;
 
@@ -416,16 +417,23 @@ static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events)
 			return false;
 		}
 	}
+
+	if (overflow_at_64bits && pmu.version < ID_DFR0_PMU_V3_8_5) {
+		report_skip("Skip test as 64 overflows need FEAT_PMUv3p5");
+		return false;
+	}
+
 	return true;
 }
 
-static void test_basic_event_count(void)
+static void test_basic_event_count(bool overflow_at_64bits)
 {
 	uint32_t implemented_counter_mask, non_implemented_counter_mask;
 	uint32_t counter_mask;
 	uint32_t events[] = {CPU_CYCLES, INST_RETIRED};
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	implemented_counter_mask = BIT(pmu.nb_implemented_counters) - 1;
@@ -499,12 +507,13 @@ static void test_basic_event_count(void)
 		"check overflow happened on #0 only");
 }
 
-static void test_mem_access(void)
+static void test_mem_access(bool overflow_at_64bits)
 {
 	void *addr = malloc(PAGE_SIZE);
 	uint32_t events[] = {MEM_ACCESS, MEM_ACCESS};
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	pmu_reset();
@@ -535,13 +544,14 @@ static void test_mem_access(void)
 			read_sysreg(pmovsclr_el0));
 }
 
-static void test_sw_incr(void)
+static void test_sw_incr(bool overflow_at_64bits)
 {
 	uint32_t events[] = {SW_INCR, SW_INCR};
 	uint64_t cntr0;
 	int i;
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	pmu_reset();
@@ -582,12 +592,13 @@ static void test_sw_incr(void)
 		"overflow on counter #0 after 100 SW_INCR");
 }
 
-static void test_chained_counters(void)
+static void test_chained_counters(bool overflow_at_64bits)
 {
 	uint32_t events[] = {CPU_CYCLES, CHAIN};
 	uint64_t cntr1;
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	pmu_reset();
@@ -626,13 +637,14 @@ static void test_chained_counters(void)
 	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
 }
 
-static void test_chained_sw_incr(void)
+static void test_chained_sw_incr(bool overflow_at_64bits)
 {
 	uint32_t events[] = {SW_INCR, CHAIN};
 	uint64_t cntr0, cntr1;
 	int i;
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	pmu_reset();
@@ -680,12 +692,13 @@ static void test_chained_sw_incr(void)
 		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
 }
 
-static void test_chain_promotion(void)
+static void test_chain_promotion(bool overflow_at_64bits)
 {
 	uint32_t events[] = {MEM_ACCESS, CHAIN};
 	void *addr = malloc(PAGE_SIZE);
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	/* Only enable CHAIN counter */
@@ -829,13 +842,14 @@ static bool expect_interrupts(uint32_t bitmap)
 	return true;
 }
 
-static void test_overflow_interrupt(void)
+static void test_overflow_interrupt(bool overflow_at_64bits)
 {
 	uint32_t events[] = {MEM_ACCESS, SW_INCR};
 	void *addr = malloc(PAGE_SIZE);
 	int i;
 
-	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
+	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
+				   overflow_at_64bits))
 		return;
 
 	gic_enable_defaults();
@@ -1059,6 +1073,19 @@ static bool pmu_probe(void)
 	return true;
 }
 
+static void run_test(char *name, void (*test)(bool), bool overflow_at_64bits)
+{
+	const char *prefix = overflow_at_64bits ? "64-bit" : "32-bit";
+
+	report_prefix_push(name);
+	report_prefix_push(prefix);
+
+	test(overflow_at_64bits);
+
+	report_prefix_pop();
+	report_prefix_pop();
+}
+
 int main(int argc, char *argv[])
 {
 	int cpi = 0;
@@ -1091,33 +1118,19 @@ int main(int argc, char *argv[])
 		test_event_counter_config();
 		report_prefix_pop();
 	} else if (strcmp(argv[1], "pmu-basic-event-count") == 0) {
-		report_prefix_push(argv[1]);
-		test_basic_event_count();
-		report_prefix_pop();
+		run_test(argv[1], test_basic_event_count, false);
 	} else if (strcmp(argv[1], "pmu-mem-access") == 0) {
-		report_prefix_push(argv[1]);
-		test_mem_access();
-		report_prefix_pop();
+		run_test(argv[1], test_mem_access, false);
 	} else if (strcmp(argv[1], "pmu-sw-incr") == 0) {
-		report_prefix_push(argv[1]);
-		test_sw_incr();
-		report_prefix_pop();
+		run_test(argv[1], test_sw_incr, false);
 	} else if (strcmp(argv[1], "pmu-chained-counters") == 0) {
-		report_prefix_push(argv[1]);
-		test_chained_counters();
-		report_prefix_pop();
+		run_test(argv[1], test_chained_counters, false);
 	} else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) {
-		report_prefix_push(argv[1]);
-		test_chained_sw_incr();
-		report_prefix_pop();
+		run_test(argv[1], test_chained_sw_incr, false);
 	} else if (strcmp(argv[1], "pmu-chain-promotion") == 0) {
-		report_prefix_push(argv[1]);
-		test_chain_promotion();
-		report_prefix_pop();
+		run_test(argv[1], test_chain_promotion, false);
 	} else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) {
-		report_prefix_push(argv[1]);
-		test_overflow_interrupt();
-		report_prefix_pop();
+		run_test(argv[1], test_overflow_interrupt, false);
 	} else {
 		report_abort("Unknown sub-test '%s'", argv[1]);
 	}
-- 
2.39.0.rc0.267.gcb52ba06e7-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* [kvm-unit-tests PATCH 3/3] arm: pmu: Add tests for 64-bit overflows
  2022-12-02  4:55 ` Ricardo Koller
@ 2022-12-02  4:55   ` Ricardo Koller
  -1 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-02  4:55 UTC (permalink / raw)
  To: kvm, kvmarm, andrew.jones
  Cc: maz, alexandru.elisei, eric.auger, oliver.upton, reijiw, Ricardo Koller

Modify all tests checking overflows to support both 32 (PMCR_EL0.LP == 0)
and 64-bit overflows (PMCR_EL0.LP == 1). 64-bit overflows are only
supported on PMUv3p5.

Note that chained tests do not implement "overflow_at_64bits == true".
That's because there are no CHAIN events when "PMCR_EL0.LP == 1" (for more
details see AArch64.IncrementEventCounter() pseudocode in the ARM ARM DDI
0487H.a, J1.1.1 "aarch64/debug").

Signed-off-by: Ricardo Koller <ricarkol@google.com>
---
 arm/pmu.c | 91 ++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 60 insertions(+), 31 deletions(-)

diff --git a/arm/pmu.c b/arm/pmu.c
index 59e5bfe..3cb563b 100644
--- a/arm/pmu.c
+++ b/arm/pmu.c
@@ -28,6 +28,7 @@
 #define PMU_PMCR_X         (1 << 4)
 #define PMU_PMCR_DP        (1 << 5)
 #define PMU_PMCR_LC        (1 << 6)
+#define PMU_PMCR_LP        (1 << 7)
 #define PMU_PMCR_N_SHIFT   11
 #define PMU_PMCR_N_MASK    0x1f
 #define PMU_PMCR_ID_SHIFT  16
@@ -55,10 +56,15 @@
 #define EXT_COMMON_EVENTS_HIGH	0x403F
 
 #define ALL_SET			0x00000000FFFFFFFFULL
+#define ALL_SET_64		0xFFFFFFFFFFFFFFFFULL
 #define ALL_CLEAR		0x0000000000000000ULL
 #define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
+#define PRE_OVERFLOW_64		0xFFFFFFFFFFFFFFF0ULL
 #define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
 
+#define PRE_OVERFLOW_AT(_64b)	(_64b ? PRE_OVERFLOW_64 : PRE_OVERFLOW)
+#define ALL_SET_AT(_64b)	(_64b ? ALL_SET_64 : ALL_SET)
+
 #define PMU_PPI			23
 
 struct pmu {
@@ -429,8 +435,10 @@ static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events,
 static void test_basic_event_count(bool overflow_at_64bits)
 {
 	uint32_t implemented_counter_mask, non_implemented_counter_mask;
-	uint32_t counter_mask;
+	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
+	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
 	uint32_t events[] = {CPU_CYCLES, INST_RETIRED};
+	uint32_t counter_mask;
 
 	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
 				   overflow_at_64bits))
@@ -452,13 +460,13 @@ static void test_basic_event_count(bool overflow_at_64bits)
 	 * clear cycle and all event counters and allow counter enablement
 	 * through PMCNTENSET. LC is RES1.
 	 */
-	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P);
+	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P | pmcr_lp);
 	isb();
-	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC), "pmcr: reset counters");
+	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC | pmcr_lp), "pmcr: reset counters");
 
 	/* Preset counter #0 to pre overflow value to trigger an overflow */
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
-	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
+	write_regn_el0(pmevcntr, 0, pre_overflow);
+	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
 		"counter #0 preset to pre-overflow value");
 	report(!read_regn_el0(pmevcntr, 1), "counter #1 is 0");
 
@@ -511,6 +519,8 @@ static void test_mem_access(bool overflow_at_64bits)
 {
 	void *addr = malloc(PAGE_SIZE);
 	uint32_t events[] = {MEM_ACCESS, MEM_ACCESS};
+	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
+	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
 
 	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
 				   overflow_at_64bits))
@@ -522,7 +532,7 @@ static void test_mem_access(bool overflow_at_64bits)
 	write_regn_el0(pmevtyper, 1, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
 	write_sysreg_s(0x3, PMCNTENSET_EL0);
 	isb();
-	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
+	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
 	report_info("counter #0 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 0));
 	report_info("counter #1 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 1));
 	/* We may measure more than 20 mem access depending on the core */
@@ -532,11 +542,11 @@ static void test_mem_access(bool overflow_at_64bits)
 
 	pmu_reset();
 
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
-	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
+	write_regn_el0(pmevcntr, 1, pre_overflow);
 	write_sysreg_s(0x3, PMCNTENSET_EL0);
 	isb();
-	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
+	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
 	report(read_sysreg(pmovsclr_el0) == 0x3,
 	       "Ran 20 mem accesses with expected overflows on both counters");
 	report_info("cnt#0 = %ld cnt#1=%ld overflow=0x%lx",
@@ -546,6 +556,8 @@ static void test_mem_access(bool overflow_at_64bits)
 
 static void test_sw_incr(bool overflow_at_64bits)
 {
+	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
+	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
 	uint32_t events[] = {SW_INCR, SW_INCR};
 	uint64_t cntr0;
 	int i;
@@ -561,7 +573,7 @@ static void test_sw_incr(bool overflow_at_64bits)
 	/* enable counters #0 and #1 */
 	write_sysreg_s(0x3, PMCNTENSET_EL0);
 
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
 	isb();
 
 	for (i = 0; i < 100; i++)
@@ -569,21 +581,21 @@ static void test_sw_incr(bool overflow_at_64bits)
 
 	isb();
 	report_info("SW_INCR counter #0 has value %ld", read_regn_el0(pmevcntr, 0));
-	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
+	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
 		"PWSYNC does not increment if PMCR.E is unset");
 
 	pmu_reset();
 
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
 	write_sysreg_s(0x3, PMCNTENSET_EL0);
-	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
+	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
 	isb();
 
 	for (i = 0; i < 100; i++)
 		write_sysreg(0x3, pmswinc_el0);
 
 	isb();
-	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
+	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : pre_overflow + 100;
 	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
 	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
 	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
@@ -844,6 +856,9 @@ static bool expect_interrupts(uint32_t bitmap)
 
 static void test_overflow_interrupt(bool overflow_at_64bits)
 {
+	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
+	uint64_t all_set = ALL_SET_AT(overflow_at_64bits);
+	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
 	uint32_t events[] = {MEM_ACCESS, SW_INCR};
 	void *addr = malloc(PAGE_SIZE);
 	int i;
@@ -862,16 +877,16 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
 	write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
 	write_regn_el0(pmevtyper, 1, SW_INCR | PMEVTYPER_EXCLUDE_EL0);
 	write_sysreg_s(0x3, PMCNTENSET_EL0);
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
-	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
+	write_regn_el0(pmevcntr, 1, pre_overflow);
 	isb();
 
 	/* interrupts are disabled (PMINTENSET_EL1 == 0) */
 
-	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
+	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
 	report(expect_interrupts(0), "no overflow interrupt after preset");
 
-	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
+	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
 	isb();
 
 	for (i = 0; i < 100; i++)
@@ -886,12 +901,12 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
 
 	pmu_reset_stats();
 
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
-	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
+	write_regn_el0(pmevcntr, 1, pre_overflow);
 	write_sysreg(ALL_SET, pmintenset_el1);
 	isb();
 
-	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
+	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
 	for (i = 0; i < 100; i++)
 		write_sysreg(0x3, pmswinc_el0);
 
@@ -900,25 +915,35 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
 	report(expect_interrupts(0x3),
 		"overflow interrupts expected on #0 and #1");
 
-	/* promote to 64-b */
+	/*
+	 * promote to 64-b:
+	 *
+	 * This only applies to the !overflow_at_64bits case, as
+	 * overflow_at_64bits doesn't implement CHAIN events. The
+	 * overflow_at_64bits case just checks that chained counters are
+	 * not incremented when PMCR.LP == 1.
+	 */
 
 	pmu_reset_stats();
 
 	write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0);
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
 	isb();
-	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
-	report(expect_interrupts(0x1),
-		"expect overflow interrupt on 32b boundary");
+	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
+	report(expect_interrupts(0x1), "expect overflow interrupt");
 
 	/* overflow on odd counter */
 	pmu_reset_stats();
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
-	write_regn_el0(pmevcntr, 1, ALL_SET);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
+	write_regn_el0(pmevcntr, 1, all_set);
 	isb();
-	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E);
-	report(expect_interrupts(0x3),
-		"expect overflow interrupt on even and odd counter");
+	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
+	if (overflow_at_64bits)
+		report(expect_interrupts(0x1),
+		       "expect overflow interrupt on even counter");
+	else
+		report(expect_interrupts(0x3),
+		       "expect overflow interrupt on even and odd counter");
 }
 #endif
 
@@ -1119,10 +1144,13 @@ int main(int argc, char *argv[])
 		report_prefix_pop();
 	} else if (strcmp(argv[1], "pmu-basic-event-count") == 0) {
 		run_test(argv[1], test_basic_event_count, false);
+		run_test(argv[1], test_basic_event_count, true);
 	} else if (strcmp(argv[1], "pmu-mem-access") == 0) {
 		run_test(argv[1], test_mem_access, false);
+		run_test(argv[1], test_mem_access, true);
 	} else if (strcmp(argv[1], "pmu-sw-incr") == 0) {
 		run_test(argv[1], test_sw_incr, false);
+		run_test(argv[1], test_sw_incr, true);
 	} else if (strcmp(argv[1], "pmu-chained-counters") == 0) {
 		run_test(argv[1], test_chained_counters, false);
 	} else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) {
@@ -1131,6 +1159,7 @@ int main(int argc, char *argv[])
 		run_test(argv[1], test_chain_promotion, false);
 	} else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) {
 		run_test(argv[1], test_overflow_interrupt, false);
+		run_test(argv[1], test_overflow_interrupt, true);
 	} else {
 		report_abort("Unknown sub-test '%s'", argv[1]);
 	}
-- 
2.39.0.rc0.267.gcb52ba06e7-goog


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

* [kvm-unit-tests PATCH 3/3] arm: pmu: Add tests for 64-bit overflows
@ 2022-12-02  4:55   ` Ricardo Koller
  0 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-02  4:55 UTC (permalink / raw)
  To: kvm, kvmarm, andrew.jones; +Cc: maz

Modify all tests checking overflows to support both 32 (PMCR_EL0.LP == 0)
and 64-bit overflows (PMCR_EL0.LP == 1). 64-bit overflows are only
supported on PMUv3p5.

Note that chained tests do not implement "overflow_at_64bits == true".
That's because there are no CHAIN events when "PMCR_EL0.LP == 1" (for more
details see AArch64.IncrementEventCounter() pseudocode in the ARM ARM DDI
0487H.a, J1.1.1 "aarch64/debug").

Signed-off-by: Ricardo Koller <ricarkol@google.com>
---
 arm/pmu.c | 91 ++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 60 insertions(+), 31 deletions(-)

diff --git a/arm/pmu.c b/arm/pmu.c
index 59e5bfe..3cb563b 100644
--- a/arm/pmu.c
+++ b/arm/pmu.c
@@ -28,6 +28,7 @@
 #define PMU_PMCR_X         (1 << 4)
 #define PMU_PMCR_DP        (1 << 5)
 #define PMU_PMCR_LC        (1 << 6)
+#define PMU_PMCR_LP        (1 << 7)
 #define PMU_PMCR_N_SHIFT   11
 #define PMU_PMCR_N_MASK    0x1f
 #define PMU_PMCR_ID_SHIFT  16
@@ -55,10 +56,15 @@
 #define EXT_COMMON_EVENTS_HIGH	0x403F
 
 #define ALL_SET			0x00000000FFFFFFFFULL
+#define ALL_SET_64		0xFFFFFFFFFFFFFFFFULL
 #define ALL_CLEAR		0x0000000000000000ULL
 #define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
+#define PRE_OVERFLOW_64		0xFFFFFFFFFFFFFFF0ULL
 #define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
 
+#define PRE_OVERFLOW_AT(_64b)	(_64b ? PRE_OVERFLOW_64 : PRE_OVERFLOW)
+#define ALL_SET_AT(_64b)	(_64b ? ALL_SET_64 : ALL_SET)
+
 #define PMU_PPI			23
 
 struct pmu {
@@ -429,8 +435,10 @@ static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events,
 static void test_basic_event_count(bool overflow_at_64bits)
 {
 	uint32_t implemented_counter_mask, non_implemented_counter_mask;
-	uint32_t counter_mask;
+	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
+	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
 	uint32_t events[] = {CPU_CYCLES, INST_RETIRED};
+	uint32_t counter_mask;
 
 	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
 				   overflow_at_64bits))
@@ -452,13 +460,13 @@ static void test_basic_event_count(bool overflow_at_64bits)
 	 * clear cycle and all event counters and allow counter enablement
 	 * through PMCNTENSET. LC is RES1.
 	 */
-	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P);
+	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P | pmcr_lp);
 	isb();
-	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC), "pmcr: reset counters");
+	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC | pmcr_lp), "pmcr: reset counters");
 
 	/* Preset counter #0 to pre overflow value to trigger an overflow */
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
-	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
+	write_regn_el0(pmevcntr, 0, pre_overflow);
+	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
 		"counter #0 preset to pre-overflow value");
 	report(!read_regn_el0(pmevcntr, 1), "counter #1 is 0");
 
@@ -511,6 +519,8 @@ static void test_mem_access(bool overflow_at_64bits)
 {
 	void *addr = malloc(PAGE_SIZE);
 	uint32_t events[] = {MEM_ACCESS, MEM_ACCESS};
+	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
+	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
 
 	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
 				   overflow_at_64bits))
@@ -522,7 +532,7 @@ static void test_mem_access(bool overflow_at_64bits)
 	write_regn_el0(pmevtyper, 1, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
 	write_sysreg_s(0x3, PMCNTENSET_EL0);
 	isb();
-	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
+	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
 	report_info("counter #0 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 0));
 	report_info("counter #1 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 1));
 	/* We may measure more than 20 mem access depending on the core */
@@ -532,11 +542,11 @@ static void test_mem_access(bool overflow_at_64bits)
 
 	pmu_reset();
 
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
-	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
+	write_regn_el0(pmevcntr, 1, pre_overflow);
 	write_sysreg_s(0x3, PMCNTENSET_EL0);
 	isb();
-	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
+	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
 	report(read_sysreg(pmovsclr_el0) == 0x3,
 	       "Ran 20 mem accesses with expected overflows on both counters");
 	report_info("cnt#0 = %ld cnt#1=%ld overflow=0x%lx",
@@ -546,6 +556,8 @@ static void test_mem_access(bool overflow_at_64bits)
 
 static void test_sw_incr(bool overflow_at_64bits)
 {
+	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
+	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
 	uint32_t events[] = {SW_INCR, SW_INCR};
 	uint64_t cntr0;
 	int i;
@@ -561,7 +573,7 @@ static void test_sw_incr(bool overflow_at_64bits)
 	/* enable counters #0 and #1 */
 	write_sysreg_s(0x3, PMCNTENSET_EL0);
 
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
 	isb();
 
 	for (i = 0; i < 100; i++)
@@ -569,21 +581,21 @@ static void test_sw_incr(bool overflow_at_64bits)
 
 	isb();
 	report_info("SW_INCR counter #0 has value %ld", read_regn_el0(pmevcntr, 0));
-	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
+	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
 		"PWSYNC does not increment if PMCR.E is unset");
 
 	pmu_reset();
 
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
 	write_sysreg_s(0x3, PMCNTENSET_EL0);
-	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
+	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
 	isb();
 
 	for (i = 0; i < 100; i++)
 		write_sysreg(0x3, pmswinc_el0);
 
 	isb();
-	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
+	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : pre_overflow + 100;
 	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
 	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
 	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
@@ -844,6 +856,9 @@ static bool expect_interrupts(uint32_t bitmap)
 
 static void test_overflow_interrupt(bool overflow_at_64bits)
 {
+	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
+	uint64_t all_set = ALL_SET_AT(overflow_at_64bits);
+	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
 	uint32_t events[] = {MEM_ACCESS, SW_INCR};
 	void *addr = malloc(PAGE_SIZE);
 	int i;
@@ -862,16 +877,16 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
 	write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
 	write_regn_el0(pmevtyper, 1, SW_INCR | PMEVTYPER_EXCLUDE_EL0);
 	write_sysreg_s(0x3, PMCNTENSET_EL0);
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
-	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
+	write_regn_el0(pmevcntr, 1, pre_overflow);
 	isb();
 
 	/* interrupts are disabled (PMINTENSET_EL1 == 0) */
 
-	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
+	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
 	report(expect_interrupts(0), "no overflow interrupt after preset");
 
-	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
+	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
 	isb();
 
 	for (i = 0; i < 100; i++)
@@ -886,12 +901,12 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
 
 	pmu_reset_stats();
 
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
-	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
+	write_regn_el0(pmevcntr, 1, pre_overflow);
 	write_sysreg(ALL_SET, pmintenset_el1);
 	isb();
 
-	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
+	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
 	for (i = 0; i < 100; i++)
 		write_sysreg(0x3, pmswinc_el0);
 
@@ -900,25 +915,35 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
 	report(expect_interrupts(0x3),
 		"overflow interrupts expected on #0 and #1");
 
-	/* promote to 64-b */
+	/*
+	 * promote to 64-b:
+	 *
+	 * This only applies to the !overflow_at_64bits case, as
+	 * overflow_at_64bits doesn't implement CHAIN events. The
+	 * overflow_at_64bits case just checks that chained counters are
+	 * not incremented when PMCR.LP == 1.
+	 */
 
 	pmu_reset_stats();
 
 	write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0);
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
 	isb();
-	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
-	report(expect_interrupts(0x1),
-		"expect overflow interrupt on 32b boundary");
+	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
+	report(expect_interrupts(0x1), "expect overflow interrupt");
 
 	/* overflow on odd counter */
 	pmu_reset_stats();
-	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
-	write_regn_el0(pmevcntr, 1, ALL_SET);
+	write_regn_el0(pmevcntr, 0, pre_overflow);
+	write_regn_el0(pmevcntr, 1, all_set);
 	isb();
-	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E);
-	report(expect_interrupts(0x3),
-		"expect overflow interrupt on even and odd counter");
+	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
+	if (overflow_at_64bits)
+		report(expect_interrupts(0x1),
+		       "expect overflow interrupt on even counter");
+	else
+		report(expect_interrupts(0x3),
+		       "expect overflow interrupt on even and odd counter");
 }
 #endif
 
@@ -1119,10 +1144,13 @@ int main(int argc, char *argv[])
 		report_prefix_pop();
 	} else if (strcmp(argv[1], "pmu-basic-event-count") == 0) {
 		run_test(argv[1], test_basic_event_count, false);
+		run_test(argv[1], test_basic_event_count, true);
 	} else if (strcmp(argv[1], "pmu-mem-access") == 0) {
 		run_test(argv[1], test_mem_access, false);
+		run_test(argv[1], test_mem_access, true);
 	} else if (strcmp(argv[1], "pmu-sw-incr") == 0) {
 		run_test(argv[1], test_sw_incr, false);
+		run_test(argv[1], test_sw_incr, true);
 	} else if (strcmp(argv[1], "pmu-chained-counters") == 0) {
 		run_test(argv[1], test_chained_counters, false);
 	} else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) {
@@ -1131,6 +1159,7 @@ int main(int argc, char *argv[])
 		run_test(argv[1], test_chain_promotion, false);
 	} else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) {
 		run_test(argv[1], test_overflow_interrupt, false);
+		run_test(argv[1], test_overflow_interrupt, true);
 	} else {
 		report_abort("Unknown sub-test '%s'", argv[1]);
 	}
-- 
2.39.0.rc0.267.gcb52ba06e7-goog

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-02  4:55   ` Ricardo Koller
@ 2022-12-09 17:47     ` Alexandru Elisei
  -1 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-09 17:47 UTC (permalink / raw)
  To: Ricardo Koller
  Cc: kvm, kvmarm, andrew.jones, maz, eric.auger, oliver.upton, reijiw

Hi,

On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> for overflowing at 32 or 64-bits. The consequence is that tests that check
> the counter values after overflowing should not assume that values will be
> wrapped around 32-bits: they overflow into the other half of the 64-bit
> counters on PMUv3p5.
> 
> Fix tests by correctly checking overflowing-counters against the expected
> 64-bit value.
> 
> Signed-off-by: Ricardo Koller <ricarkol@google.com>
> ---
>  arm/pmu.c | 29 ++++++++++++++++++-----------
>  1 file changed, 18 insertions(+), 11 deletions(-)
> 
> diff --git a/arm/pmu.c b/arm/pmu.c
> index cd47b14..eeac984 100644
> --- a/arm/pmu.c
> +++ b/arm/pmu.c
> @@ -54,10 +54,10 @@
>  #define EXT_COMMON_EVENTS_LOW	0x4000
>  #define EXT_COMMON_EVENTS_HIGH	0x403F
>  
> -#define ALL_SET			0xFFFFFFFF
> -#define ALL_CLEAR		0x0
> -#define PRE_OVERFLOW		0xFFFFFFF0
> -#define PRE_OVERFLOW2		0xFFFFFFDC
> +#define ALL_SET			0x00000000FFFFFFFFULL
> +#define ALL_CLEAR		0x0000000000000000ULL
> +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
>  
>  #define PMU_PPI			23
>  
> @@ -538,6 +538,7 @@ static void test_mem_access(void)
>  static void test_sw_incr(void)
>  {
>  	uint32_t events[] = {SW_INCR, SW_INCR};
> +	uint64_t cntr0;
>  	int i;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> @@ -572,9 +573,9 @@ static void test_sw_incr(void)
>  		write_sysreg(0x3, pmswinc_el0);
>  
>  	isb();
> -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> -	report(read_regn_el0(pmevcntr, 1)  == 100,
> -		"counter #0 after + 100 SW_INCR");
> +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;

Hm... in the Arm ARM it says that counters are 64-bit if PMUv3p5 is
implemented.  But it doesn't say anywhere that versions newer than p5 are
required to implement PMUv3p5.

For example, for PMUv3p7, it says that the feature is mandatory in Arm8.7
implementations. My interpretation of that is that it is not forbidden for
an implementer to cherry-pick this version on older versions of the
architecture where PMUv3p5 is not implemented.

Maybe the check should be pmu.version == ID_DFR0_PMU_V3_8_5, to match the
counter definitions in the architecture?

Also, I found the meaning of those numbers to be quite cryptic. Perhaps
something like this would be more resilient to changes to the value of
PRE_OVERFLOW and easier to understand:

+       cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ?
+               (uint32_t)PRE_OVERFLOW + 100 :
+               (uint64_t)PRE_OVERFLOW + 100;

I haven't tested the code, would that work?

Thanks,
Alex

> +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
>  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
>  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
>  	report(read_sysreg(pmovsclr_el0) == 0x1,
> @@ -584,6 +585,7 @@ static void test_sw_incr(void)
>  static void test_chained_counters(void)
>  {
>  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> +	uint64_t cntr1;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
>  		return;
> @@ -618,13 +620,16 @@ static void test_chained_counters(void)
>  
>  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
>  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> +
>  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
>  }
>  
>  static void test_chained_sw_incr(void)
>  {
>  	uint32_t events[] = {SW_INCR, CHAIN};
> +	uint64_t cntr0, cntr1;
>  	int i;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
>  		write_sysreg(0x1, pmswinc_el0);
>  
>  	isb();
> +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
>  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> -		(read_regn_el0(pmevcntr, 1) == 0) &&
> -		(read_regn_el0(pmevcntr, 0) == 84),
> -		"expected overflows and values after 100 SW_INCR/CHAIN");
> +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> +	       "expected overflows and values after 100 SW_INCR/CHAIN");
>  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
>  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
>  }
> -- 
> 2.39.0.rc0.267.gcb52ba06e7-goog
> 

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-09 17:47     ` Alexandru Elisei
  0 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-09 17:47 UTC (permalink / raw)
  To: Ricardo Koller; +Cc: kvm, maz, andrew.jones, kvmarm

Hi,

On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> for overflowing at 32 or 64-bits. The consequence is that tests that check
> the counter values after overflowing should not assume that values will be
> wrapped around 32-bits: they overflow into the other half of the 64-bit
> counters on PMUv3p5.
> 
> Fix tests by correctly checking overflowing-counters against the expected
> 64-bit value.
> 
> Signed-off-by: Ricardo Koller <ricarkol@google.com>
> ---
>  arm/pmu.c | 29 ++++++++++++++++++-----------
>  1 file changed, 18 insertions(+), 11 deletions(-)
> 
> diff --git a/arm/pmu.c b/arm/pmu.c
> index cd47b14..eeac984 100644
> --- a/arm/pmu.c
> +++ b/arm/pmu.c
> @@ -54,10 +54,10 @@
>  #define EXT_COMMON_EVENTS_LOW	0x4000
>  #define EXT_COMMON_EVENTS_HIGH	0x403F
>  
> -#define ALL_SET			0xFFFFFFFF
> -#define ALL_CLEAR		0x0
> -#define PRE_OVERFLOW		0xFFFFFFF0
> -#define PRE_OVERFLOW2		0xFFFFFFDC
> +#define ALL_SET			0x00000000FFFFFFFFULL
> +#define ALL_CLEAR		0x0000000000000000ULL
> +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
>  
>  #define PMU_PPI			23
>  
> @@ -538,6 +538,7 @@ static void test_mem_access(void)
>  static void test_sw_incr(void)
>  {
>  	uint32_t events[] = {SW_INCR, SW_INCR};
> +	uint64_t cntr0;
>  	int i;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> @@ -572,9 +573,9 @@ static void test_sw_incr(void)
>  		write_sysreg(0x3, pmswinc_el0);
>  
>  	isb();
> -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> -	report(read_regn_el0(pmevcntr, 1)  == 100,
> -		"counter #0 after + 100 SW_INCR");
> +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;

Hm... in the Arm ARM it says that counters are 64-bit if PMUv3p5 is
implemented.  But it doesn't say anywhere that versions newer than p5 are
required to implement PMUv3p5.

For example, for PMUv3p7, it says that the feature is mandatory in Arm8.7
implementations. My interpretation of that is that it is not forbidden for
an implementer to cherry-pick this version on older versions of the
architecture where PMUv3p5 is not implemented.

Maybe the check should be pmu.version == ID_DFR0_PMU_V3_8_5, to match the
counter definitions in the architecture?

Also, I found the meaning of those numbers to be quite cryptic. Perhaps
something like this would be more resilient to changes to the value of
PRE_OVERFLOW and easier to understand:

+       cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ?
+               (uint32_t)PRE_OVERFLOW + 100 :
+               (uint64_t)PRE_OVERFLOW + 100;

I haven't tested the code, would that work?

Thanks,
Alex

> +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
>  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
>  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
>  	report(read_sysreg(pmovsclr_el0) == 0x1,
> @@ -584,6 +585,7 @@ static void test_sw_incr(void)
>  static void test_chained_counters(void)
>  {
>  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> +	uint64_t cntr1;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
>  		return;
> @@ -618,13 +620,16 @@ static void test_chained_counters(void)
>  
>  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
>  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> +
>  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
>  }
>  
>  static void test_chained_sw_incr(void)
>  {
>  	uint32_t events[] = {SW_INCR, CHAIN};
> +	uint64_t cntr0, cntr1;
>  	int i;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
>  		write_sysreg(0x1, pmswinc_el0);
>  
>  	isb();
> +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
>  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> -		(read_regn_el0(pmevcntr, 1) == 0) &&
> -		(read_regn_el0(pmevcntr, 0) == 84),
> -		"expected overflows and values after 100 SW_INCR/CHAIN");
> +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> +	       "expected overflows and values after 100 SW_INCR/CHAIN");
>  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
>  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
>  }
> -- 
> 2.39.0.rc0.267.gcb52ba06e7-goog
> 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-09 17:47     ` Alexandru Elisei
@ 2022-12-10 11:01       ` Marc Zyngier
  -1 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2022-12-10 11:01 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Ricardo Koller, kvm, kvmarm, andrew.jones, eric.auger,
	oliver.upton, reijiw

On Fri, 09 Dec 2022 17:47:14 +0000,
Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> 
> Hi,
> 
> On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > the counter values after overflowing should not assume that values will be
> > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > counters on PMUv3p5.
> > 
> > Fix tests by correctly checking overflowing-counters against the expected
> > 64-bit value.
> > 
> > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > ---
> >  arm/pmu.c | 29 ++++++++++++++++++-----------
> >  1 file changed, 18 insertions(+), 11 deletions(-)
> > 
> > diff --git a/arm/pmu.c b/arm/pmu.c
> > index cd47b14..eeac984 100644
> > --- a/arm/pmu.c
> > +++ b/arm/pmu.c
> > @@ -54,10 +54,10 @@
> >  #define EXT_COMMON_EVENTS_LOW	0x4000
> >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> >  
> > -#define ALL_SET			0xFFFFFFFF
> > -#define ALL_CLEAR		0x0
> > -#define PRE_OVERFLOW		0xFFFFFFF0
> > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > +#define ALL_SET			0x00000000FFFFFFFFULL
> > +#define ALL_CLEAR		0x0000000000000000ULL
> > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> >  
> >  #define PMU_PPI			23
> >  
> > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> >  static void test_sw_incr(void)
> >  {
> >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > +	uint64_t cntr0;
> >  	int i;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> >  		write_sysreg(0x3, pmswinc_el0);
> >  
> >  	isb();
> > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > -		"counter #0 after + 100 SW_INCR");
> > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> 
> Hm... in the Arm ARM it says that counters are 64-bit if PMUv3p5 is
> implemented.  But it doesn't say anywhere that versions newer than p5 are
> required to implement PMUv3p5.

And I don't think it needs to say it, because there is otherwise no
way for SW to discover whether 64bit counters are implemented or not.

> 
> For example, for PMUv3p7, it says that the feature is mandatory in Arm8.7
> implementations. My interpretation of that is that it is not forbidden for
> an implementer to cherry-pick this version on older versions of the
> architecture where PMUv3p5 is not implemented.

I'm sorry to have to say that, but I find your suggestion that PMUv3p7
could be implemented without supporting the full gamut of PMUv3p5
ludicrous.

Please look back at the ARM ARM, specially at the tiny section titled
"Alternative ID scheme used for the Performance Monitors Extension
version" (DDI0487I.a, D17.1.3, page 5553), and the snipped of C code
that performs exactly this check:

<quote>
  if (value != 0xF and value >= number) {
  	// do something that relies on version 'number' of the feature
  }
</quote>

Replace 'value' with 7 (PMUv3p7), 'number' with 6 (PMUv3p5), and you
get the exact property that you pretend doesn't exist, allowing you to
rely on PMUv3p5 to be implemented when the HW has PMUv3p7.

> Maybe the check should be pmu.version == ID_DFR0_PMU_V3_8_5, to match the
> counter definitions in the architecture?

No, that'd be totally wrong. You need to check your understanding of
how the ID registers work.

	M.

-- 
Without deviation from the norm, progress is not possible.

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-10 11:01       ` Marc Zyngier
  0 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2022-12-10 11:01 UTC (permalink / raw)
  To: Alexandru Elisei; +Cc: kvm, andrew.jones, kvmarm

On Fri, 09 Dec 2022 17:47:14 +0000,
Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> 
> Hi,
> 
> On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > the counter values after overflowing should not assume that values will be
> > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > counters on PMUv3p5.
> > 
> > Fix tests by correctly checking overflowing-counters against the expected
> > 64-bit value.
> > 
> > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > ---
> >  arm/pmu.c | 29 ++++++++++++++++++-----------
> >  1 file changed, 18 insertions(+), 11 deletions(-)
> > 
> > diff --git a/arm/pmu.c b/arm/pmu.c
> > index cd47b14..eeac984 100644
> > --- a/arm/pmu.c
> > +++ b/arm/pmu.c
> > @@ -54,10 +54,10 @@
> >  #define EXT_COMMON_EVENTS_LOW	0x4000
> >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> >  
> > -#define ALL_SET			0xFFFFFFFF
> > -#define ALL_CLEAR		0x0
> > -#define PRE_OVERFLOW		0xFFFFFFF0
> > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > +#define ALL_SET			0x00000000FFFFFFFFULL
> > +#define ALL_CLEAR		0x0000000000000000ULL
> > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> >  
> >  #define PMU_PPI			23
> >  
> > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> >  static void test_sw_incr(void)
> >  {
> >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > +	uint64_t cntr0;
> >  	int i;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> >  		write_sysreg(0x3, pmswinc_el0);
> >  
> >  	isb();
> > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > -		"counter #0 after + 100 SW_INCR");
> > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> 
> Hm... in the Arm ARM it says that counters are 64-bit if PMUv3p5 is
> implemented.  But it doesn't say anywhere that versions newer than p5 are
> required to implement PMUv3p5.

And I don't think it needs to say it, because there is otherwise no
way for SW to discover whether 64bit counters are implemented or not.

> 
> For example, for PMUv3p7, it says that the feature is mandatory in Arm8.7
> implementations. My interpretation of that is that it is not forbidden for
> an implementer to cherry-pick this version on older versions of the
> architecture where PMUv3p5 is not implemented.

I'm sorry to have to say that, but I find your suggestion that PMUv3p7
could be implemented without supporting the full gamut of PMUv3p5
ludicrous.

Please look back at the ARM ARM, specially at the tiny section titled
"Alternative ID scheme used for the Performance Monitors Extension
version" (DDI0487I.a, D17.1.3, page 5553), and the snipped of C code
that performs exactly this check:

<quote>
  if (value != 0xF and value >= number) {
  	// do something that relies on version 'number' of the feature
  }
</quote>

Replace 'value' with 7 (PMUv3p7), 'number' with 6 (PMUv3p5), and you
get the exact property that you pretend doesn't exist, allowing you to
rely on PMUv3p5 to be implemented when the HW has PMUv3p7.

> Maybe the check should be pmu.version == ID_DFR0_PMU_V3_8_5, to match the
> counter definitions in the architecture?

No, that'd be totally wrong. You need to check your understanding of
how the ID registers work.

	M.

-- 
Without deviation from the norm, progress is not possible.
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-10 11:01       ` Marc Zyngier
@ 2022-12-11 11:40         ` Alexandru Elisei
  -1 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-11 11:40 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Ricardo Koller, kvm, kvmarm, andrew.jones, eric.auger,
	oliver.upton, reijiw

Hi Marc,

On Sat, Dec 10, 2022 at 11:01:53AM +0000, Marc Zyngier wrote:
> On Fri, 09 Dec 2022 17:47:14 +0000,
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> > 
> > Hi,
> > 
> > On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > > the counter values after overflowing should not assume that values will be
> > > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > > counters on PMUv3p5.
> > > 
> > > Fix tests by correctly checking overflowing-counters against the expected
> > > 64-bit value.
> > > 
> > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > ---
> > >  arm/pmu.c | 29 ++++++++++++++++++-----------
> > >  1 file changed, 18 insertions(+), 11 deletions(-)
> > > 
> > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > index cd47b14..eeac984 100644
> > > --- a/arm/pmu.c
> > > +++ b/arm/pmu.c
> > > @@ -54,10 +54,10 @@
> > >  #define EXT_COMMON_EVENTS_LOW	0x4000
> > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > >  
> > > -#define ALL_SET			0xFFFFFFFF
> > > -#define ALL_CLEAR		0x0
> > > -#define PRE_OVERFLOW		0xFFFFFFF0
> > > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > > +#define ALL_SET			0x00000000FFFFFFFFULL
> > > +#define ALL_CLEAR		0x0000000000000000ULL
> > > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > >  
> > >  #define PMU_PPI			23
> > >  
> > > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> > >  static void test_sw_incr(void)
> > >  {
> > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > > +	uint64_t cntr0;
> > >  	int i;
> > >  
> > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> > >  		write_sysreg(0x3, pmswinc_el0);
> > >  
> > >  	isb();
> > > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > > -		"counter #0 after + 100 SW_INCR");
> > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > 
> > Hm... in the Arm ARM it says that counters are 64-bit if PMUv3p5 is
> > implemented.  But it doesn't say anywhere that versions newer than p5 are
> > required to implement PMUv3p5.
> 
> And I don't think it needs to say it, because there is otherwise no
> way for SW to discover whether 64bit counters are implemented or not.
> 
> > 
> > For example, for PMUv3p7, it says that the feature is mandatory in Arm8.7
> > implementations. My interpretation of that is that it is not forbidden for
> > an implementer to cherry-pick this version on older versions of the
> > architecture where PMUv3p5 is not implemented.
> 
> I'm sorry to have to say that, but I find your suggestion that PMUv3p7
> could be implemented without supporting the full gamut of PMUv3p5
> ludicrous.
> 
> Please look back at the ARM ARM, specially at the tiny section titled
> "Alternative ID scheme used for the Performance Monitors Extension
> version" (DDI0487I.a, D17.1.3, page 5553), and the snipped of C code
> that performs exactly this check:
> 
> <quote>
>   if (value != 0xF and value >= number) {
>   	// do something that relies on version 'number' of the feature
>   }
> </quote>
> 
> Replace 'value' with 7 (PMUv3p7), 'number' with 6 (PMUv3p5), and you
> get the exact property that you pretend doesn't exist, allowing you to
> rely on PMUv3p5 to be implemented when the HW has PMUv3p7.
> 
> > Maybe the check should be pmu.version == ID_DFR0_PMU_V3_8_5, to match the
> > counter definitions in the architecture?
> 
> No, that'd be totally wrong. You need to check your understanding of
> how the ID registers work.

A simple "hey, you're wrong here, the PMU extensions do not follow the
principles of the ID scheme for fields in ID registers" would have
sufficed. Guess you never made a silly mistake ever, right?

Otherwise, good job encouraging people to help review KVM/arm64 patches ;)

Thanks,
Alex

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-11 11:40         ` Alexandru Elisei
  0 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-11 11:40 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvm, andrew.jones, kvmarm

Hi Marc,

On Sat, Dec 10, 2022 at 11:01:53AM +0000, Marc Zyngier wrote:
> On Fri, 09 Dec 2022 17:47:14 +0000,
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> > 
> > Hi,
> > 
> > On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > > the counter values after overflowing should not assume that values will be
> > > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > > counters on PMUv3p5.
> > > 
> > > Fix tests by correctly checking overflowing-counters against the expected
> > > 64-bit value.
> > > 
> > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > ---
> > >  arm/pmu.c | 29 ++++++++++++++++++-----------
> > >  1 file changed, 18 insertions(+), 11 deletions(-)
> > > 
> > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > index cd47b14..eeac984 100644
> > > --- a/arm/pmu.c
> > > +++ b/arm/pmu.c
> > > @@ -54,10 +54,10 @@
> > >  #define EXT_COMMON_EVENTS_LOW	0x4000
> > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > >  
> > > -#define ALL_SET			0xFFFFFFFF
> > > -#define ALL_CLEAR		0x0
> > > -#define PRE_OVERFLOW		0xFFFFFFF0
> > > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > > +#define ALL_SET			0x00000000FFFFFFFFULL
> > > +#define ALL_CLEAR		0x0000000000000000ULL
> > > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > >  
> > >  #define PMU_PPI			23
> > >  
> > > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> > >  static void test_sw_incr(void)
> > >  {
> > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > > +	uint64_t cntr0;
> > >  	int i;
> > >  
> > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> > >  		write_sysreg(0x3, pmswinc_el0);
> > >  
> > >  	isb();
> > > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > > -		"counter #0 after + 100 SW_INCR");
> > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > 
> > Hm... in the Arm ARM it says that counters are 64-bit if PMUv3p5 is
> > implemented.  But it doesn't say anywhere that versions newer than p5 are
> > required to implement PMUv3p5.
> 
> And I don't think it needs to say it, because there is otherwise no
> way for SW to discover whether 64bit counters are implemented or not.
> 
> > 
> > For example, for PMUv3p7, it says that the feature is mandatory in Arm8.7
> > implementations. My interpretation of that is that it is not forbidden for
> > an implementer to cherry-pick this version on older versions of the
> > architecture where PMUv3p5 is not implemented.
> 
> I'm sorry to have to say that, but I find your suggestion that PMUv3p7
> could be implemented without supporting the full gamut of PMUv3p5
> ludicrous.
> 
> Please look back at the ARM ARM, specially at the tiny section titled
> "Alternative ID scheme used for the Performance Monitors Extension
> version" (DDI0487I.a, D17.1.3, page 5553), and the snipped of C code
> that performs exactly this check:
> 
> <quote>
>   if (value != 0xF and value >= number) {
>   	// do something that relies on version 'number' of the feature
>   }
> </quote>
> 
> Replace 'value' with 7 (PMUv3p7), 'number' with 6 (PMUv3p5), and you
> get the exact property that you pretend doesn't exist, allowing you to
> rely on PMUv3p5 to be implemented when the HW has PMUv3p7.
> 
> > Maybe the check should be pmu.version == ID_DFR0_PMU_V3_8_5, to match the
> > counter definitions in the architecture?
> 
> No, that'd be totally wrong. You need to check your understanding of
> how the ID registers work.

A simple "hey, you're wrong here, the PMU extensions do not follow the
principles of the ID scheme for fields in ID registers" would have
sufficed. Guess you never made a silly mistake ever, right?

Otherwise, good job encouraging people to help review KVM/arm64 patches ;)

Thanks,
Alex
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-11 11:40         ` Alexandru Elisei
@ 2022-12-12  9:05           ` Marc Zyngier
  -1 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2022-12-12  9:05 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Ricardo Koller, kvm, kvmarm, andrew.jones, eric.auger,
	oliver.upton, reijiw

Alex,

On Sun, 11 Dec 2022 11:40:39 +0000,
Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> 
> A simple "hey, you're wrong here, the PMU extensions do not follow the
> principles of the ID scheme for fields in ID registers" would have
> sufficed.

This is what I did, and saved you the hassle of looking it up.

> Guess you never made a silly mistake ever, right?

It's not so much about making a silly mistake. I do that all the time.
But it is about the way you state these things, and the weight that
your reviews carry. You're a trusted reviewer, with a lot of
experience, and posting with an @arm.com address: what you say in a
public forum sticks. When you assert that the author is wrong, they
will take it at face value.

> Otherwise, good job encouraging people to help review KVM/arm64 patches ;)

What is the worse: no review? or a review that spreads confusion?
Think about it. I'm all for being nice, but I will call bullshit when
I see it asserted by people with a certain level of authority.

And I've long made up my mind about the state of the KVM/arm64 review
process -- reviews rarely come from people who have volunteered to do
so, but instead from those who have either a vested interest in it, or
an ulterior motive. Hey ho...

	M.

-- 
Without deviation from the norm, progress is not possible.

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-12  9:05           ` Marc Zyngier
  0 siblings, 0 replies; 40+ messages in thread
From: Marc Zyngier @ 2022-12-12  9:05 UTC (permalink / raw)
  To: Alexandru Elisei; +Cc: kvm, andrew.jones, kvmarm

Alex,

On Sun, 11 Dec 2022 11:40:39 +0000,
Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> 
> A simple "hey, you're wrong here, the PMU extensions do not follow the
> principles of the ID scheme for fields in ID registers" would have
> sufficed.

This is what I did, and saved you the hassle of looking it up.

> Guess you never made a silly mistake ever, right?

It's not so much about making a silly mistake. I do that all the time.
But it is about the way you state these things, and the weight that
your reviews carry. You're a trusted reviewer, with a lot of
experience, and posting with an @arm.com address: what you say in a
public forum sticks. When you assert that the author is wrong, they
will take it at face value.

> Otherwise, good job encouraging people to help review KVM/arm64 patches ;)

What is the worse: no review? or a review that spreads confusion?
Think about it. I'm all for being nice, but I will call bullshit when
I see it asserted by people with a certain level of authority.

And I've long made up my mind about the state of the KVM/arm64 review
process -- reviews rarely come from people who have volunteered to do
so, but instead from those who have either a vested interest in it, or
an ulterior motive. Hey ho...

	M.

-- 
Without deviation from the norm, progress is not possible.
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-12  9:05           ` Marc Zyngier
@ 2022-12-12 13:56             ` Alexandru Elisei
  -1 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-12 13:56 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Ricardo Koller, kvm, kvmarm, andrew.jones, eric.auger,
	oliver.upton, reijiw

Hi,

On Mon, Dec 12, 2022 at 09:05:02AM +0000, Marc Zyngier wrote:
> Alex,
> 
> On Sun, 11 Dec 2022 11:40:39 +0000,
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> > 
> > A simple "hey, you're wrong here, the PMU extensions do not follow the
> > principles of the ID scheme for fields in ID registers" would have
> > sufficed.
> 
> This is what I did, and saved you the hassle of looking it up.

The comment was about how you went about it, not about proving someone
wrong. As expressive as it might be, I don't think that calling someone's
suggestion "ludicrous" from the position of authority associated with being
a maintainer is constructive; and can also be interpreted as a personal
attack (you used **your** suggestion, not **this** suggestion). I didn't
interpret it that way, just saying that it can be.

> 
> > Guess you never made a silly mistake ever, right?
> 
> It's not so much about making a silly mistake. I do that all the time.
> But it is about the way you state these things, and the weight that
> your reviews carry. You're a trusted reviewer, with a lot of
> experience, and posting with an @arm.com address: what you say in a
> public forum sticks. When you assert that the author is wrong, they
> will take it at face value.

This is how I stated things:

"Hm... in the Arm ARM it says that counters are 64-bit if PMUv3p5 is
implemented.  But it doesn't say anywhere that versions newer than p5 are
required to implement PMUv3p5." -> patently false, easily provable with the
Arm ARM and by logic (as you did). My entire argument was based on this, so
once this has been proven false, I would say that the rest of my argument
falls apart.

"For example, for PMUv3p7, it says that the feature is mandatory in Arm8.7
implementations. **My interpretation** of that is that it is not forbidden
for an implementer to cherry-pick this version on older versions of the
architecture where PMUv3p5 is not implemented." -> emphasis on the "my
interpretation"; also easy to prove false because PMUv3p5+ is required to
implement PMUv3p5, as per the architecture.

"**Maybe** the check should be pmu.version == ID_DFR0_PMU_V3_8_5, to match
the counter definitions in the architecture?" -> emphasis on the "maybe",
and the question mark at the end.

My intention wasn't to dictate something, my intention was to have a
conversation about the patch, with the mindset that I might be wrong. What
made you get the idea that I was asserting that the author is wrong? Where
by "asserting the author is wrong" I understand framing my comment in such
a way as to leave no room for further discussions. Or did you mean
something else by that?

Or, to put it another way, what about the way I stated things could have
been done better (other than not being wrong, obviously)?

> 
> > Otherwise, good job encouraging people to help review KVM/arm64 patches ;)
> 
> What is the worse: no review? or a review that spreads confusion?
> Think about it. I'm all for being nice, but I will call bullshit when

That wasn't about calling people out on their mistakes. I was saying that
the way you "call bullshit", as you put it, might be a put off for some
people. Call me naive, but I like to think that not everyone that comments
on a patch does it because they have to.

> I see it asserted by people with a certain level of authority.
> 
> And I've long made up my mind about the state of the KVM/arm64 review
> process -- reviews rarely come from people who have volunteered to do
> so, but instead from those who have either a vested interest in it, or
> an ulterior motive. Hey ho...

I genuinely don't know what to make of this. I can't even tell if it's
directed at me or not.

Thanks,
Alex

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-12 13:56             ` Alexandru Elisei
  0 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-12 13:56 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvm, andrew.jones, kvmarm

Hi,

On Mon, Dec 12, 2022 at 09:05:02AM +0000, Marc Zyngier wrote:
> Alex,
> 
> On Sun, 11 Dec 2022 11:40:39 +0000,
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> > 
> > A simple "hey, you're wrong here, the PMU extensions do not follow the
> > principles of the ID scheme for fields in ID registers" would have
> > sufficed.
> 
> This is what I did, and saved you the hassle of looking it up.

The comment was about how you went about it, not about proving someone
wrong. As expressive as it might be, I don't think that calling someone's
suggestion "ludicrous" from the position of authority associated with being
a maintainer is constructive; and can also be interpreted as a personal
attack (you used **your** suggestion, not **this** suggestion). I didn't
interpret it that way, just saying that it can be.

> 
> > Guess you never made a silly mistake ever, right?
> 
> It's not so much about making a silly mistake. I do that all the time.
> But it is about the way you state these things, and the weight that
> your reviews carry. You're a trusted reviewer, with a lot of
> experience, and posting with an @arm.com address: what you say in a
> public forum sticks. When you assert that the author is wrong, they
> will take it at face value.

This is how I stated things:

"Hm... in the Arm ARM it says that counters are 64-bit if PMUv3p5 is
implemented.  But it doesn't say anywhere that versions newer than p5 are
required to implement PMUv3p5." -> patently false, easily provable with the
Arm ARM and by logic (as you did). My entire argument was based on this, so
once this has been proven false, I would say that the rest of my argument
falls apart.

"For example, for PMUv3p7, it says that the feature is mandatory in Arm8.7
implementations. **My interpretation** of that is that it is not forbidden
for an implementer to cherry-pick this version on older versions of the
architecture where PMUv3p5 is not implemented." -> emphasis on the "my
interpretation"; also easy to prove false because PMUv3p5+ is required to
implement PMUv3p5, as per the architecture.

"**Maybe** the check should be pmu.version == ID_DFR0_PMU_V3_8_5, to match
the counter definitions in the architecture?" -> emphasis on the "maybe",
and the question mark at the end.

My intention wasn't to dictate something, my intention was to have a
conversation about the patch, with the mindset that I might be wrong. What
made you get the idea that I was asserting that the author is wrong? Where
by "asserting the author is wrong" I understand framing my comment in such
a way as to leave no room for further discussions. Or did you mean
something else by that?

Or, to put it another way, what about the way I stated things could have
been done better (other than not being wrong, obviously)?

> 
> > Otherwise, good job encouraging people to help review KVM/arm64 patches ;)
> 
> What is the worse: no review? or a review that spreads confusion?
> Think about it. I'm all for being nice, but I will call bullshit when

That wasn't about calling people out on their mistakes. I was saying that
the way you "call bullshit", as you put it, might be a put off for some
people. Call me naive, but I like to think that not everyone that comments
on a patch does it because they have to.

> I see it asserted by people with a certain level of authority.
> 
> And I've long made up my mind about the state of the KVM/arm64 review
> process -- reviews rarely come from people who have volunteered to do
> so, but instead from those who have either a vested interest in it, or
> an ulterior motive. Hey ho...

I genuinely don't know what to make of this. I can't even tell if it's
directed at me or not.

Thanks,
Alex
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-09 17:47     ` Alexandru Elisei
@ 2022-12-12 21:00       ` Ricardo Koller
  -1 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-12 21:00 UTC (permalink / raw)
  To: Alexandru Elisei; +Cc: kvm, maz, andrew.jones, kvmarm

On Fri, Dec 09, 2022 at 05:47:14PM +0000, Alexandru Elisei wrote:
> Hi,
> 
> On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > the counter values after overflowing should not assume that values will be
> > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > counters on PMUv3p5.
> > 
> > Fix tests by correctly checking overflowing-counters against the expected
> > 64-bit value.
> > 
> > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > ---
> >  arm/pmu.c | 29 ++++++++++++++++++-----------
> >  1 file changed, 18 insertions(+), 11 deletions(-)
> > 
> > diff --git a/arm/pmu.c b/arm/pmu.c
> > index cd47b14..eeac984 100644
> > --- a/arm/pmu.c
> > +++ b/arm/pmu.c
> > @@ -54,10 +54,10 @@
> >  #define EXT_COMMON_EVENTS_LOW	0x4000
> >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> >  
> > -#define ALL_SET			0xFFFFFFFF
> > -#define ALL_CLEAR		0x0
> > -#define PRE_OVERFLOW		0xFFFFFFF0
> > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > +#define ALL_SET			0x00000000FFFFFFFFULL
> > +#define ALL_CLEAR		0x0000000000000000ULL
> > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> >  
> >  #define PMU_PPI			23
> >  
> > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> >  static void test_sw_incr(void)
> >  {
> >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > +	uint64_t cntr0;
> >  	int i;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> >  		write_sysreg(0x3, pmswinc_el0);
> >  
> >  	isb();
> > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > -		"counter #0 after + 100 SW_INCR");
> > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> 
> Hm... in the Arm ARM it says that counters are 64-bit if PMUv3p5 is
> implemented.  But it doesn't say anywhere that versions newer than p5 are
> required to implement PMUv3p5.
> 
> For example, for PMUv3p7, it says that the feature is mandatory in Arm8.7
> implementations. My interpretation of that is that it is not forbidden for
> an implementer to cherry-pick this version on older versions of the
> architecture where PMUv3p5 is not implemented.
> 
> Maybe the check should be pmu.version == ID_DFR0_PMU_V3_8_5, to match the
> counter definitions in the architecture?
> 
> Also, I found the meaning of those numbers to be quite cryptic. Perhaps
> something like this would be more resilient to changes to the value of
> PRE_OVERFLOW and easier to understand:
> 
> +       cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ?
> +               (uint32_t)PRE_OVERFLOW + 100 :
> +               (uint64_t)PRE_OVERFLOW + 100;
> 
> I haven't tested the code, would that work?

Just checked. That works. It's much cleaner, thank you very much.

Will send a v2 a the end of the week, maybe after some more reviews.

> 
> Thanks,
> Alex
> 
> > +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> >  	report(read_sysreg(pmovsclr_el0) == 0x1,
> > @@ -584,6 +585,7 @@ static void test_sw_incr(void)
> >  static void test_chained_counters(void)
> >  {
> >  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> > +	uint64_t cntr1;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> >  		return;
> > @@ -618,13 +620,16 @@ static void test_chained_counters(void)
> >  
> >  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> >  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > +
> >  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> >  }
> >  
> >  static void test_chained_sw_incr(void)
> >  {
> >  	uint32_t events[] = {SW_INCR, CHAIN};
> > +	uint64_t cntr0, cntr1;
> >  	int i;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
> >  		write_sysreg(0x1, pmswinc_el0);
> >  
> >  	isb();
> > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> >  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> > -		(read_regn_el0(pmevcntr, 1) == 0) &&
> > -		(read_regn_el0(pmevcntr, 0) == 84),
> > -		"expected overflows and values after 100 SW_INCR/CHAIN");
> > +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> > +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> > +	       "expected overflows and values after 100 SW_INCR/CHAIN");
> >  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
> >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> >  }
> > -- 
> > 2.39.0.rc0.267.gcb52ba06e7-goog
> > 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-12 21:00       ` Ricardo Koller
  0 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-12 21:00 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: kvm, kvmarm, andrew.jones, maz, eric.auger, oliver.upton, reijiw

On Fri, Dec 09, 2022 at 05:47:14PM +0000, Alexandru Elisei wrote:
> Hi,
> 
> On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > the counter values after overflowing should not assume that values will be
> > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > counters on PMUv3p5.
> > 
> > Fix tests by correctly checking overflowing-counters against the expected
> > 64-bit value.
> > 
> > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > ---
> >  arm/pmu.c | 29 ++++++++++++++++++-----------
> >  1 file changed, 18 insertions(+), 11 deletions(-)
> > 
> > diff --git a/arm/pmu.c b/arm/pmu.c
> > index cd47b14..eeac984 100644
> > --- a/arm/pmu.c
> > +++ b/arm/pmu.c
> > @@ -54,10 +54,10 @@
> >  #define EXT_COMMON_EVENTS_LOW	0x4000
> >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> >  
> > -#define ALL_SET			0xFFFFFFFF
> > -#define ALL_CLEAR		0x0
> > -#define PRE_OVERFLOW		0xFFFFFFF0
> > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > +#define ALL_SET			0x00000000FFFFFFFFULL
> > +#define ALL_CLEAR		0x0000000000000000ULL
> > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> >  
> >  #define PMU_PPI			23
> >  
> > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> >  static void test_sw_incr(void)
> >  {
> >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > +	uint64_t cntr0;
> >  	int i;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> >  		write_sysreg(0x3, pmswinc_el0);
> >  
> >  	isb();
> > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > -		"counter #0 after + 100 SW_INCR");
> > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> 
> Hm... in the Arm ARM it says that counters are 64-bit if PMUv3p5 is
> implemented.  But it doesn't say anywhere that versions newer than p5 are
> required to implement PMUv3p5.
> 
> For example, for PMUv3p7, it says that the feature is mandatory in Arm8.7
> implementations. My interpretation of that is that it is not forbidden for
> an implementer to cherry-pick this version on older versions of the
> architecture where PMUv3p5 is not implemented.
> 
> Maybe the check should be pmu.version == ID_DFR0_PMU_V3_8_5, to match the
> counter definitions in the architecture?
> 
> Also, I found the meaning of those numbers to be quite cryptic. Perhaps
> something like this would be more resilient to changes to the value of
> PRE_OVERFLOW and easier to understand:
> 
> +       cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ?
> +               (uint32_t)PRE_OVERFLOW + 100 :
> +               (uint64_t)PRE_OVERFLOW + 100;
> 
> I haven't tested the code, would that work?

Just checked. That works. It's much cleaner, thank you very much.

Will send a v2 a the end of the week, maybe after some more reviews.

> 
> Thanks,
> Alex
> 
> > +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> >  	report(read_sysreg(pmovsclr_el0) == 0x1,
> > @@ -584,6 +585,7 @@ static void test_sw_incr(void)
> >  static void test_chained_counters(void)
> >  {
> >  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> > +	uint64_t cntr1;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> >  		return;
> > @@ -618,13 +620,16 @@ static void test_chained_counters(void)
> >  
> >  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> >  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > +
> >  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> >  }
> >  
> >  static void test_chained_sw_incr(void)
> >  {
> >  	uint32_t events[] = {SW_INCR, CHAIN};
> > +	uint64_t cntr0, cntr1;
> >  	int i;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
> >  		write_sysreg(0x1, pmswinc_el0);
> >  
> >  	isb();
> > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> >  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> > -		(read_regn_el0(pmevcntr, 1) == 0) &&
> > -		(read_regn_el0(pmevcntr, 0) == 84),
> > -		"expected overflows and values after 100 SW_INCR/CHAIN");
> > +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> > +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> > +	       "expected overflows and values after 100 SW_INCR/CHAIN");
> >  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
> >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> >  }
> > -- 
> > 2.39.0.rc0.267.gcb52ba06e7-goog
> > 

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-02  4:55   ` Ricardo Koller
@ 2022-12-13 12:36     ` Alexandru Elisei
  -1 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-13 12:36 UTC (permalink / raw)
  To: Ricardo Koller
  Cc: kvm, kvmarm, andrew.jones, maz, eric.auger, oliver.upton, reijiw

Hi,

Some more comments below.

On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> for overflowing at 32 or 64-bits. The consequence is that tests that check
> the counter values after overflowing should not assume that values will be
> wrapped around 32-bits: they overflow into the other half of the 64-bit
> counters on PMUv3p5.
> 
> Fix tests by correctly checking overflowing-counters against the expected
> 64-bit value.
> 
> Signed-off-by: Ricardo Koller <ricarkol@google.com>
> ---
>  arm/pmu.c | 29 ++++++++++++++++++-----------
>  1 file changed, 18 insertions(+), 11 deletions(-)
> 
> diff --git a/arm/pmu.c b/arm/pmu.c
> index cd47b14..eeac984 100644
> --- a/arm/pmu.c
> +++ b/arm/pmu.c
> @@ -54,10 +54,10 @@
>  #define EXT_COMMON_EVENTS_LOW	0x4000
>  #define EXT_COMMON_EVENTS_HIGH	0x403F
>  
> -#define ALL_SET			0xFFFFFFFF
> -#define ALL_CLEAR		0x0
> -#define PRE_OVERFLOW		0xFFFFFFF0
> -#define PRE_OVERFLOW2		0xFFFFFFDC
> +#define ALL_SET			0x00000000FFFFFFFFULL
> +#define ALL_CLEAR		0x0000000000000000ULL
> +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
>  
>  #define PMU_PPI			23
>  
> @@ -538,6 +538,7 @@ static void test_mem_access(void)
>  static void test_sw_incr(void)
>  {
>  	uint32_t events[] = {SW_INCR, SW_INCR};
> +	uint64_t cntr0;
>  	int i;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> @@ -572,9 +573,9 @@ static void test_sw_incr(void)
>  		write_sysreg(0x3, pmswinc_el0);
>  
>  	isb();
> -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> -	report(read_regn_el0(pmevcntr, 1)  == 100,
> -		"counter #0 after + 100 SW_INCR");
> +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
>  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
>  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
>  	report(read_sysreg(pmovsclr_el0) == 0x1,
> @@ -584,6 +585,7 @@ static void test_sw_incr(void)
>  static void test_chained_counters(void)
>  {
>  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> +	uint64_t cntr1;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
>  		return;
> @@ -618,13 +620,16 @@ static void test_chained_counters(void)
>  
>  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
>  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");

It looks to me like the intention of the test was to check that the counter
programmed with the CHAIN event wraps, judging from the report message.

I think it would be interesting to keep that by programming counter #1 with
~0ULL when PMUv3p5 (maybe call it ALL_SET64?) and test the counter value
against 0. Alternatively, the report message can be modified, and "wrapped"
replaced with "incremented" (or something like that), to avoid confusion.

> +
>  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
>  }
>  
>  static void test_chained_sw_incr(void)
>  {
>  	uint32_t events[] = {SW_INCR, CHAIN};
> +	uint64_t cntr0, cntr1;
>  	int i;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
>  		write_sysreg(0x1, pmswinc_el0);
>  
>  	isb();
> +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
>  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> -		(read_regn_el0(pmevcntr, 1) == 0) &&
> -		(read_regn_el0(pmevcntr, 0) == 84),
> -		"expected overflows and values after 100 SW_INCR/CHAIN");
> +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> +	       (read_regn_el0(pmevcntr, 0) == cntr1),

This is hard to parse, it would be better if counter 0 is compared against
cntr0 and counter 1 against cntr1.

Also, same suggestion here, looks like the test wants to check that the
odd-numbered counter wraps around when counting the CHAIN event.

Thanks,
Alex

> +	       "expected overflows and values after 100 SW_INCR/CHAIN");
>  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
>  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
>  }
> -- 
> 2.39.0.rc0.267.gcb52ba06e7-goog
> 

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-13 12:36     ` Alexandru Elisei
  0 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-13 12:36 UTC (permalink / raw)
  To: Ricardo Koller; +Cc: kvm, maz, andrew.jones, kvmarm

Hi,

Some more comments below.

On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> for overflowing at 32 or 64-bits. The consequence is that tests that check
> the counter values after overflowing should not assume that values will be
> wrapped around 32-bits: they overflow into the other half of the 64-bit
> counters on PMUv3p5.
> 
> Fix tests by correctly checking overflowing-counters against the expected
> 64-bit value.
> 
> Signed-off-by: Ricardo Koller <ricarkol@google.com>
> ---
>  arm/pmu.c | 29 ++++++++++++++++++-----------
>  1 file changed, 18 insertions(+), 11 deletions(-)
> 
> diff --git a/arm/pmu.c b/arm/pmu.c
> index cd47b14..eeac984 100644
> --- a/arm/pmu.c
> +++ b/arm/pmu.c
> @@ -54,10 +54,10 @@
>  #define EXT_COMMON_EVENTS_LOW	0x4000
>  #define EXT_COMMON_EVENTS_HIGH	0x403F
>  
> -#define ALL_SET			0xFFFFFFFF
> -#define ALL_CLEAR		0x0
> -#define PRE_OVERFLOW		0xFFFFFFF0
> -#define PRE_OVERFLOW2		0xFFFFFFDC
> +#define ALL_SET			0x00000000FFFFFFFFULL
> +#define ALL_CLEAR		0x0000000000000000ULL
> +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
>  
>  #define PMU_PPI			23
>  
> @@ -538,6 +538,7 @@ static void test_mem_access(void)
>  static void test_sw_incr(void)
>  {
>  	uint32_t events[] = {SW_INCR, SW_INCR};
> +	uint64_t cntr0;
>  	int i;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> @@ -572,9 +573,9 @@ static void test_sw_incr(void)
>  		write_sysreg(0x3, pmswinc_el0);
>  
>  	isb();
> -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> -	report(read_regn_el0(pmevcntr, 1)  == 100,
> -		"counter #0 after + 100 SW_INCR");
> +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
>  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
>  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
>  	report(read_sysreg(pmovsclr_el0) == 0x1,
> @@ -584,6 +585,7 @@ static void test_sw_incr(void)
>  static void test_chained_counters(void)
>  {
>  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> +	uint64_t cntr1;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
>  		return;
> @@ -618,13 +620,16 @@ static void test_chained_counters(void)
>  
>  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
>  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");

It looks to me like the intention of the test was to check that the counter
programmed with the CHAIN event wraps, judging from the report message.

I think it would be interesting to keep that by programming counter #1 with
~0ULL when PMUv3p5 (maybe call it ALL_SET64?) and test the counter value
against 0. Alternatively, the report message can be modified, and "wrapped"
replaced with "incremented" (or something like that), to avoid confusion.

> +
>  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
>  }
>  
>  static void test_chained_sw_incr(void)
>  {
>  	uint32_t events[] = {SW_INCR, CHAIN};
> +	uint64_t cntr0, cntr1;
>  	int i;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
>  		write_sysreg(0x1, pmswinc_el0);
>  
>  	isb();
> +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
>  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> -		(read_regn_el0(pmevcntr, 1) == 0) &&
> -		(read_regn_el0(pmevcntr, 0) == 84),
> -		"expected overflows and values after 100 SW_INCR/CHAIN");
> +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> +	       (read_regn_el0(pmevcntr, 0) == cntr1),

This is hard to parse, it would be better if counter 0 is compared against
cntr0 and counter 1 against cntr1.

Also, same suggestion here, looks like the test wants to check that the
odd-numbered counter wraps around when counting the CHAIN event.

Thanks,
Alex

> +	       "expected overflows and values after 100 SW_INCR/CHAIN");
>  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
>  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
>  }
> -- 
> 2.39.0.rc0.267.gcb52ba06e7-goog
> 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-13 12:36     ` Alexandru Elisei
@ 2022-12-13 16:21       ` Ricardo Koller
  -1 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-13 16:21 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: kvm, kvmarm, andrew.jones, maz, eric.auger, oliver.upton, reijiw

On Tue, Dec 13, 2022 at 12:36:14PM +0000, Alexandru Elisei wrote:
> Hi,
> 
> Some more comments below.
> 
> On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > the counter values after overflowing should not assume that values will be
> > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > counters on PMUv3p5.
> > 
> > Fix tests by correctly checking overflowing-counters against the expected
> > 64-bit value.
> > 
> > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > ---
> >  arm/pmu.c | 29 ++++++++++++++++++-----------
> >  1 file changed, 18 insertions(+), 11 deletions(-)
> > 
> > diff --git a/arm/pmu.c b/arm/pmu.c
> > index cd47b14..eeac984 100644
> > --- a/arm/pmu.c
> > +++ b/arm/pmu.c
> > @@ -54,10 +54,10 @@
> >  #define EXT_COMMON_EVENTS_LOW	0x4000
> >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> >  
> > -#define ALL_SET			0xFFFFFFFF
> > -#define ALL_CLEAR		0x0
> > -#define PRE_OVERFLOW		0xFFFFFFF0
> > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > +#define ALL_SET			0x00000000FFFFFFFFULL
> > +#define ALL_CLEAR		0x0000000000000000ULL
> > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> >  
> >  #define PMU_PPI			23
> >  
> > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> >  static void test_sw_incr(void)
> >  {
> >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > +	uint64_t cntr0;
> >  	int i;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> >  		write_sysreg(0x3, pmswinc_el0);
> >  
> >  	isb();
> > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > -		"counter #0 after + 100 SW_INCR");
> > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> >  	report(read_sysreg(pmovsclr_el0) == 0x1,
> > @@ -584,6 +585,7 @@ static void test_sw_incr(void)
> >  static void test_chained_counters(void)
> >  {
> >  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> > +	uint64_t cntr1;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> >  		return;
> > @@ -618,13 +620,16 @@ static void test_chained_counters(void)
> >  
> >  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> >  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> 
> It looks to me like the intention of the test was to check that the counter
> programmed with the CHAIN event wraps, judging from the report message.
> 

Ah, right. Yeah, that message is confusing. It should be the short
version of "Inrementing at 32-bits resulted in the right value".

> I think it would be interesting to keep that by programming counter #1 with
> ~0ULL when PMUv3p5 (maybe call it ALL_SET64?) and test the counter value
> against 0.

The last commit adds tests using ALL_SET64.  Tests can be run in two
modes: overflow_at_64bits and not.  However, this test,
test_chained_counters(), and all other chained tests only use the
!overflow_at_64bits mode (even after the last commit). The reason is
that there are no CHAIN events when overflowing at 64-bits (more details
in the commit message). But, don't worry, there are lots of tests that
check wrapping at 64-bits (overflow_at_64bits=true).

> Alternatively, the report message can be modified, and "wrapped"
> replaced with "incremented" (or something like that), to avoid confusion.
> 
> > +
> >  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> >  }
> >  
> >  static void test_chained_sw_incr(void)
> >  {
> >  	uint32_t events[] = {SW_INCR, CHAIN};
> > +	uint64_t cntr0, cntr1;
> >  	int i;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
> >  		write_sysreg(0x1, pmswinc_el0);
> >  
> >  	isb();
> > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> >  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> > -		(read_regn_el0(pmevcntr, 1) == 0) &&
> > -		(read_regn_el0(pmevcntr, 0) == 84),
> > -		"expected overflows and values after 100 SW_INCR/CHAIN");
> > +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> > +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> 
> This is hard to parse, it would be better if counter 0 is compared against
> cntr0 and counter 1 against cntr1.

Ah, yes, code is correct but that's indeed confusing.

> 
> Also, same suggestion here, looks like the test wants to check that the
> odd-numbered counter wraps around when counting the CHAIN event.

Ack. Will update for v2.

Thanks!
Ricardo

> 
> Thanks,
> Alex
> 
> > +	       "expected overflows and values after 100 SW_INCR/CHAIN");
> >  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
> >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> >  }
> > -- 
> > 2.39.0.rc0.267.gcb52ba06e7-goog
> > 

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-13 16:21       ` Ricardo Koller
  0 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-13 16:21 UTC (permalink / raw)
  To: Alexandru Elisei; +Cc: kvm, maz, andrew.jones, kvmarm

On Tue, Dec 13, 2022 at 12:36:14PM +0000, Alexandru Elisei wrote:
> Hi,
> 
> Some more comments below.
> 
> On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > the counter values after overflowing should not assume that values will be
> > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > counters on PMUv3p5.
> > 
> > Fix tests by correctly checking overflowing-counters against the expected
> > 64-bit value.
> > 
> > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > ---
> >  arm/pmu.c | 29 ++++++++++++++++++-----------
> >  1 file changed, 18 insertions(+), 11 deletions(-)
> > 
> > diff --git a/arm/pmu.c b/arm/pmu.c
> > index cd47b14..eeac984 100644
> > --- a/arm/pmu.c
> > +++ b/arm/pmu.c
> > @@ -54,10 +54,10 @@
> >  #define EXT_COMMON_EVENTS_LOW	0x4000
> >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> >  
> > -#define ALL_SET			0xFFFFFFFF
> > -#define ALL_CLEAR		0x0
> > -#define PRE_OVERFLOW		0xFFFFFFF0
> > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > +#define ALL_SET			0x00000000FFFFFFFFULL
> > +#define ALL_CLEAR		0x0000000000000000ULL
> > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> >  
> >  #define PMU_PPI			23
> >  
> > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> >  static void test_sw_incr(void)
> >  {
> >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > +	uint64_t cntr0;
> >  	int i;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> >  		write_sysreg(0x3, pmswinc_el0);
> >  
> >  	isb();
> > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > -		"counter #0 after + 100 SW_INCR");
> > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> >  	report(read_sysreg(pmovsclr_el0) == 0x1,
> > @@ -584,6 +585,7 @@ static void test_sw_incr(void)
> >  static void test_chained_counters(void)
> >  {
> >  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> > +	uint64_t cntr1;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> >  		return;
> > @@ -618,13 +620,16 @@ static void test_chained_counters(void)
> >  
> >  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> >  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> 
> It looks to me like the intention of the test was to check that the counter
> programmed with the CHAIN event wraps, judging from the report message.
> 

Ah, right. Yeah, that message is confusing. It should be the short
version of "Inrementing at 32-bits resulted in the right value".

> I think it would be interesting to keep that by programming counter #1 with
> ~0ULL when PMUv3p5 (maybe call it ALL_SET64?) and test the counter value
> against 0.

The last commit adds tests using ALL_SET64.  Tests can be run in two
modes: overflow_at_64bits and not.  However, this test,
test_chained_counters(), and all other chained tests only use the
!overflow_at_64bits mode (even after the last commit). The reason is
that there are no CHAIN events when overflowing at 64-bits (more details
in the commit message). But, don't worry, there are lots of tests that
check wrapping at 64-bits (overflow_at_64bits=true).

> Alternatively, the report message can be modified, and "wrapped"
> replaced with "incremented" (or something like that), to avoid confusion.
> 
> > +
> >  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> >  }
> >  
> >  static void test_chained_sw_incr(void)
> >  {
> >  	uint32_t events[] = {SW_INCR, CHAIN};
> > +	uint64_t cntr0, cntr1;
> >  	int i;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
> >  		write_sysreg(0x1, pmswinc_el0);
> >  
> >  	isb();
> > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> >  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> > -		(read_regn_el0(pmevcntr, 1) == 0) &&
> > -		(read_regn_el0(pmevcntr, 0) == 84),
> > -		"expected overflows and values after 100 SW_INCR/CHAIN");
> > +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> > +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> 
> This is hard to parse, it would be better if counter 0 is compared against
> cntr0 and counter 1 against cntr1.

Ah, yes, code is correct but that's indeed confusing.

> 
> Also, same suggestion here, looks like the test wants to check that the
> odd-numbered counter wraps around when counting the CHAIN event.

Ack. Will update for v2.

Thanks!
Ricardo

> 
> Thanks,
> Alex
> 
> > +	       "expected overflows and values after 100 SW_INCR/CHAIN");
> >  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
> >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> >  }
> > -- 
> > 2.39.0.rc0.267.gcb52ba06e7-goog
> > 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-13 16:21       ` Ricardo Koller
@ 2022-12-13 16:43         ` Alexandru Elisei
  -1 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-13 16:43 UTC (permalink / raw)
  To: Ricardo Koller
  Cc: kvm, kvmarm, andrew.jones, maz, eric.auger, oliver.upton, reijiw

Hi,

On Tue, Dec 13, 2022 at 08:21:24AM -0800, Ricardo Koller wrote:
> On Tue, Dec 13, 2022 at 12:36:14PM +0000, Alexandru Elisei wrote:
> > Hi,
> > 
> > Some more comments below.
> > 
> > On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > > the counter values after overflowing should not assume that values will be
> > > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > > counters on PMUv3p5.
> > > 
> > > Fix tests by correctly checking overflowing-counters against the expected
> > > 64-bit value.
> > > 
> > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > ---
> > >  arm/pmu.c | 29 ++++++++++++++++++-----------
> > >  1 file changed, 18 insertions(+), 11 deletions(-)
> > > 
> > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > index cd47b14..eeac984 100644
> > > --- a/arm/pmu.c
> > > +++ b/arm/pmu.c
> > > @@ -54,10 +54,10 @@
> > >  #define EXT_COMMON_EVENTS_LOW	0x4000
> > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > >  
> > > -#define ALL_SET			0xFFFFFFFF
> > > -#define ALL_CLEAR		0x0
> > > -#define PRE_OVERFLOW		0xFFFFFFF0
> > > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > > +#define ALL_SET			0x00000000FFFFFFFFULL
> > > +#define ALL_CLEAR		0x0000000000000000ULL
> > > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > >  
> > >  #define PMU_PPI			23
> > >  
> > > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> > >  static void test_sw_incr(void)
> > >  {
> > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > > +	uint64_t cntr0;
> > >  	int i;
> > >  
> > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> > >  		write_sysreg(0x3, pmswinc_el0);
> > >  
> > >  	isb();
> > > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > > -		"counter #0 after + 100 SW_INCR");
> > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > > +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> > >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > >  	report(read_sysreg(pmovsclr_el0) == 0x1,
> > > @@ -584,6 +585,7 @@ static void test_sw_incr(void)
> > >  static void test_chained_counters(void)
> > >  {
> > >  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> > > +	uint64_t cntr1;
> > >  
> > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > >  		return;
> > > @@ -618,13 +620,16 @@ static void test_chained_counters(void)
> > >  
> > >  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> > >  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > > -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > 
> > It looks to me like the intention of the test was to check that the counter
> > programmed with the CHAIN event wraps, judging from the report message.
> > 
> 
> Ah, right. Yeah, that message is confusing. It should be the short
> version of "Inrementing at 32-bits resulted in the right value".
> 
> > I think it would be interesting to keep that by programming counter #1 with
> > ~0ULL when PMUv3p5 (maybe call it ALL_SET64?) and test the counter value
> > against 0.
> 
> The last commit adds tests using ALL_SET64.  Tests can be run in two
> modes: overflow_at_64bits and not.  However, this test,
> test_chained_counters(), and all other chained tests only use the
> !overflow_at_64bits mode (even after the last commit). The reason is
> that there are no CHAIN events when overflowing at 64-bits (more details
> in the commit message). But, don't worry, there are lots of tests that
> check wrapping at 64-bits (overflow_at_64bits=true).

What I was suggesting is this (change on top of this series, not on top of
this patch, to get access to ALL_SET_AT):

diff --git a/arm/pmu.c b/arm/pmu.c
index 3cb563b1abe4..fd7f20fc6c52 100644
--- a/arm/pmu.c
+++ b/arm/pmu.c
@@ -607,7 +607,6 @@ static void test_sw_incr(bool overflow_at_64bits)
 static void test_chained_counters(bool overflow_at_64bits)
 {
        uint32_t events[] = {CPU_CYCLES, CHAIN};
-       uint64_t cntr1;

        if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
                                   overflow_at_64bits))
@@ -639,12 +638,11 @@ static void test_chained_counters(bool overflow_at_64bits)
        report(read_sysreg(pmovsclr_el0) == 0x1, "overflow recorded for chained incr #2");

        write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
-       write_regn_el0(pmevcntr, 1, ALL_SET);
+       write_regn_el0(pmevcntr, 1, ALL_SET_AT(overflow_at_64bits));

        precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
        report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
-       cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
-       report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
+       report(read_regn_el0(pmevcntr, 1) == 0, "CHAIN counter #1 wrapped");

        report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
 }

The counters are 64bit, but the CHAIN event should still work because
PMCR_EL0.LP is 0, according to the event description in the Arm ARM (ARM
DDI 0487I.a, page D17-6461).

Thanks,
Alex

> 
> > Alternatively, the report message can be modified, and "wrapped"
> > replaced with "incremented" (or something like that), to avoid confusion.
> > 
> > > +
> > >  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> > >  }
> > >  
> > >  static void test_chained_sw_incr(void)
> > >  {
> > >  	uint32_t events[] = {SW_INCR, CHAIN};
> > > +	uint64_t cntr0, cntr1;
> > >  	int i;
> > >  
> > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
> > >  		write_sysreg(0x1, pmswinc_el0);
> > >  
> > >  	isb();
> > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > >  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> > > -		(read_regn_el0(pmevcntr, 1) == 0) &&
> > > -		(read_regn_el0(pmevcntr, 0) == 84),
> > > -		"expected overflows and values after 100 SW_INCR/CHAIN");
> > > +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> > > +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> > 
> > This is hard to parse, it would be better if counter 0 is compared against
> > cntr0 and counter 1 against cntr1.
> 
> Ah, yes, code is correct but that's indeed confusing.
> 
> > 
> > Also, same suggestion here, looks like the test wants to check that the
> > odd-numbered counter wraps around when counting the CHAIN event.
> 
> Ack. Will update for v2.
> 
> Thanks!
> Ricardo
> 
> > 
> > Thanks,
> > Alex
> > 
> > > +	       "expected overflows and values after 100 SW_INCR/CHAIN");
> > >  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
> > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > >  }
> > > -- 
> > > 2.39.0.rc0.267.gcb52ba06e7-goog
> > > 

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-13 16:43         ` Alexandru Elisei
  0 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-13 16:43 UTC (permalink / raw)
  To: Ricardo Koller; +Cc: kvm, maz, andrew.jones, kvmarm

Hi,

On Tue, Dec 13, 2022 at 08:21:24AM -0800, Ricardo Koller wrote:
> On Tue, Dec 13, 2022 at 12:36:14PM +0000, Alexandru Elisei wrote:
> > Hi,
> > 
> > Some more comments below.
> > 
> > On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > > the counter values after overflowing should not assume that values will be
> > > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > > counters on PMUv3p5.
> > > 
> > > Fix tests by correctly checking overflowing-counters against the expected
> > > 64-bit value.
> > > 
> > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > ---
> > >  arm/pmu.c | 29 ++++++++++++++++++-----------
> > >  1 file changed, 18 insertions(+), 11 deletions(-)
> > > 
> > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > index cd47b14..eeac984 100644
> > > --- a/arm/pmu.c
> > > +++ b/arm/pmu.c
> > > @@ -54,10 +54,10 @@
> > >  #define EXT_COMMON_EVENTS_LOW	0x4000
> > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > >  
> > > -#define ALL_SET			0xFFFFFFFF
> > > -#define ALL_CLEAR		0x0
> > > -#define PRE_OVERFLOW		0xFFFFFFF0
> > > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > > +#define ALL_SET			0x00000000FFFFFFFFULL
> > > +#define ALL_CLEAR		0x0000000000000000ULL
> > > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > >  
> > >  #define PMU_PPI			23
> > >  
> > > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> > >  static void test_sw_incr(void)
> > >  {
> > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > > +	uint64_t cntr0;
> > >  	int i;
> > >  
> > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> > >  		write_sysreg(0x3, pmswinc_el0);
> > >  
> > >  	isb();
> > > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > > -		"counter #0 after + 100 SW_INCR");
> > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > > +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> > >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > >  	report(read_sysreg(pmovsclr_el0) == 0x1,
> > > @@ -584,6 +585,7 @@ static void test_sw_incr(void)
> > >  static void test_chained_counters(void)
> > >  {
> > >  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> > > +	uint64_t cntr1;
> > >  
> > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > >  		return;
> > > @@ -618,13 +620,16 @@ static void test_chained_counters(void)
> > >  
> > >  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> > >  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > > -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > 
> > It looks to me like the intention of the test was to check that the counter
> > programmed with the CHAIN event wraps, judging from the report message.
> > 
> 
> Ah, right. Yeah, that message is confusing. It should be the short
> version of "Inrementing at 32-bits resulted in the right value".
> 
> > I think it would be interesting to keep that by programming counter #1 with
> > ~0ULL when PMUv3p5 (maybe call it ALL_SET64?) and test the counter value
> > against 0.
> 
> The last commit adds tests using ALL_SET64.  Tests can be run in two
> modes: overflow_at_64bits and not.  However, this test,
> test_chained_counters(), and all other chained tests only use the
> !overflow_at_64bits mode (even after the last commit). The reason is
> that there are no CHAIN events when overflowing at 64-bits (more details
> in the commit message). But, don't worry, there are lots of tests that
> check wrapping at 64-bits (overflow_at_64bits=true).

What I was suggesting is this (change on top of this series, not on top of
this patch, to get access to ALL_SET_AT):

diff --git a/arm/pmu.c b/arm/pmu.c
index 3cb563b1abe4..fd7f20fc6c52 100644
--- a/arm/pmu.c
+++ b/arm/pmu.c
@@ -607,7 +607,6 @@ static void test_sw_incr(bool overflow_at_64bits)
 static void test_chained_counters(bool overflow_at_64bits)
 {
        uint32_t events[] = {CPU_CYCLES, CHAIN};
-       uint64_t cntr1;

        if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
                                   overflow_at_64bits))
@@ -639,12 +638,11 @@ static void test_chained_counters(bool overflow_at_64bits)
        report(read_sysreg(pmovsclr_el0) == 0x1, "overflow recorded for chained incr #2");

        write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
-       write_regn_el0(pmevcntr, 1, ALL_SET);
+       write_regn_el0(pmevcntr, 1, ALL_SET_AT(overflow_at_64bits));

        precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
        report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
-       cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
-       report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
+       report(read_regn_el0(pmevcntr, 1) == 0, "CHAIN counter #1 wrapped");

        report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
 }

The counters are 64bit, but the CHAIN event should still work because
PMCR_EL0.LP is 0, according to the event description in the Arm ARM (ARM
DDI 0487I.a, page D17-6461).

Thanks,
Alex

> 
> > Alternatively, the report message can be modified, and "wrapped"
> > replaced with "incremented" (or something like that), to avoid confusion.
> > 
> > > +
> > >  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> > >  }
> > >  
> > >  static void test_chained_sw_incr(void)
> > >  {
> > >  	uint32_t events[] = {SW_INCR, CHAIN};
> > > +	uint64_t cntr0, cntr1;
> > >  	int i;
> > >  
> > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
> > >  		write_sysreg(0x1, pmswinc_el0);
> > >  
> > >  	isb();
> > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > >  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> > > -		(read_regn_el0(pmevcntr, 1) == 0) &&
> > > -		(read_regn_el0(pmevcntr, 0) == 84),
> > > -		"expected overflows and values after 100 SW_INCR/CHAIN");
> > > +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> > > +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> > 
> > This is hard to parse, it would be better if counter 0 is compared against
> > cntr0 and counter 1 against cntr1.
> 
> Ah, yes, code is correct but that's indeed confusing.
> 
> > 
> > Also, same suggestion here, looks like the test wants to check that the
> > odd-numbered counter wraps around when counting the CHAIN event.
> 
> Ack. Will update for v2.
> 
> Thanks!
> Ricardo
> 
> > 
> > Thanks,
> > Alex
> > 
> > > +	       "expected overflows and values after 100 SW_INCR/CHAIN");
> > >  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
> > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > >  }
> > > -- 
> > > 2.39.0.rc0.267.gcb52ba06e7-goog
> > > 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 3/3] arm: pmu: Add tests for 64-bit overflows
  2022-12-02  4:55   ` Ricardo Koller
@ 2022-12-13 17:03     ` Alexandru Elisei
  -1 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-13 17:03 UTC (permalink / raw)
  To: Ricardo Koller
  Cc: kvm, kvmarm, andrew.jones, maz, eric.auger, oliver.upton, reijiw

Hi,

Checked that all places where ALL_SET/PRE_OVERFLOW were used are now taking
into account the fact that counters are programmed to be 64bit.

In the case of 64bit counters, the printf format specifier is %ld, which
means that ALL_SET_64 and PRE_OVERFLOW_64 are now displayed as negative
numbers. For example:

INFO: pmu: pmu-sw-incr: 32-bit: SW_INCR counter #0 has value 4294967280
PASS: pmu: pmu-sw-incr: 32-bit: PWSYNC does not increment if PMCR.E is unset
[..]
INFO: pmu: pmu-sw-incr: 64-bit: SW_INCR counter #0 has value -16
PASS: pmu: pmu-sw-incr: 64-bit: PWSYNC does not increment if PMCR.E is unset

I was thinking that the format specifiers could be changed to unsigned
long.  The counters only increment, they don't decrement, and I can't think
how printing them as signed could be useful.

One more comment below.

On Fri, Dec 02, 2022 at 04:55:27AM +0000, Ricardo Koller wrote:
> Modify all tests checking overflows to support both 32 (PMCR_EL0.LP == 0)
> and 64-bit overflows (PMCR_EL0.LP == 1). 64-bit overflows are only
> supported on PMUv3p5.
> 
> Note that chained tests do not implement "overflow_at_64bits == true".
> That's because there are no CHAIN events when "PMCR_EL0.LP == 1" (for more
> details see AArch64.IncrementEventCounter() pseudocode in the ARM ARM DDI
> 0487H.a, J1.1.1 "aarch64/debug").
> 
> Signed-off-by: Ricardo Koller <ricarkol@google.com>
> ---
>  arm/pmu.c | 91 ++++++++++++++++++++++++++++++++++++-------------------
>  1 file changed, 60 insertions(+), 31 deletions(-)
> 
> diff --git a/arm/pmu.c b/arm/pmu.c
> index 59e5bfe..3cb563b 100644
> --- a/arm/pmu.c
> +++ b/arm/pmu.c
> @@ -28,6 +28,7 @@
>  #define PMU_PMCR_X         (1 << 4)
>  #define PMU_PMCR_DP        (1 << 5)
>  #define PMU_PMCR_LC        (1 << 6)
> +#define PMU_PMCR_LP        (1 << 7)
>  #define PMU_PMCR_N_SHIFT   11
>  #define PMU_PMCR_N_MASK    0x1f
>  #define PMU_PMCR_ID_SHIFT  16
> @@ -55,10 +56,15 @@
>  #define EXT_COMMON_EVENTS_HIGH	0x403F
>  
>  #define ALL_SET			0x00000000FFFFFFFFULL
> +#define ALL_SET_64		0xFFFFFFFFFFFFFFFFULL
>  #define ALL_CLEAR		0x0000000000000000ULL
>  #define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> +#define PRE_OVERFLOW_64		0xFFFFFFFFFFFFFFF0ULL
>  #define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
>  
> +#define PRE_OVERFLOW_AT(_64b)	(_64b ? PRE_OVERFLOW_64 : PRE_OVERFLOW)
> +#define ALL_SET_AT(_64b)	(_64b ? ALL_SET_64 : ALL_SET)
> +
>  #define PMU_PPI			23
>  
>  struct pmu {
> @@ -429,8 +435,10 @@ static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events,
>  static void test_basic_event_count(bool overflow_at_64bits)
>  {
>  	uint32_t implemented_counter_mask, non_implemented_counter_mask;
> -	uint32_t counter_mask;
> +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
>  	uint32_t events[] = {CPU_CYCLES, INST_RETIRED};
> +	uint32_t counter_mask;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
>  				   overflow_at_64bits))
> @@ -452,13 +460,13 @@ static void test_basic_event_count(bool overflow_at_64bits)
>  	 * clear cycle and all event counters and allow counter enablement
>  	 * through PMCNTENSET. LC is RES1.
>  	 */
> -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P);
> +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P | pmcr_lp);
>  	isb();
> -	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC), "pmcr: reset counters");
> +	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC | pmcr_lp), "pmcr: reset counters");
>  
>  	/* Preset counter #0 to pre overflow value to trigger an overflow */
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
> +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
>  		"counter #0 preset to pre-overflow value");
>  	report(!read_regn_el0(pmevcntr, 1), "counter #1 is 0");
>  
> @@ -511,6 +519,8 @@ static void test_mem_access(bool overflow_at_64bits)
>  {
>  	void *addr = malloc(PAGE_SIZE);
>  	uint32_t events[] = {MEM_ACCESS, MEM_ACCESS};
> +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
>  				   overflow_at_64bits))
> @@ -522,7 +532,7 @@ static void test_mem_access(bool overflow_at_64bits)
>  	write_regn_el0(pmevtyper, 1, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
>  	write_sysreg_s(0x3, PMCNTENSET_EL0);
>  	isb();
> -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
>  	report_info("counter #0 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 0));
>  	report_info("counter #1 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 1));
>  	/* We may measure more than 20 mem access depending on the core */
> @@ -532,11 +542,11 @@ static void test_mem_access(bool overflow_at_64bits)
>  
>  	pmu_reset();
>  
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
> +	write_regn_el0(pmevcntr, 1, pre_overflow);
>  	write_sysreg_s(0x3, PMCNTENSET_EL0);
>  	isb();
> -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
>  	report(read_sysreg(pmovsclr_el0) == 0x3,
>  	       "Ran 20 mem accesses with expected overflows on both counters");
>  	report_info("cnt#0 = %ld cnt#1=%ld overflow=0x%lx",
> @@ -546,6 +556,8 @@ static void test_mem_access(bool overflow_at_64bits)
>  
>  static void test_sw_incr(bool overflow_at_64bits)
>  {
> +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
>  	uint32_t events[] = {SW_INCR, SW_INCR};
>  	uint64_t cntr0;
>  	int i;
> @@ -561,7 +573,7 @@ static void test_sw_incr(bool overflow_at_64bits)
>  	/* enable counters #0 and #1 */
>  	write_sysreg_s(0x3, PMCNTENSET_EL0);
>  
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
>  	isb();
>  
>  	for (i = 0; i < 100; i++)
> @@ -569,21 +581,21 @@ static void test_sw_incr(bool overflow_at_64bits)
>  
>  	isb();
>  	report_info("SW_INCR counter #0 has value %ld", read_regn_el0(pmevcntr, 0));
> -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
>  		"PWSYNC does not increment if PMCR.E is unset");
>  
>  	pmu_reset();
>  
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
>  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
>  	isb();
>  
>  	for (i = 0; i < 100; i++)
>  		write_sysreg(0x3, pmswinc_el0);
>  
>  	isb();
> -	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : pre_overflow + 100;
>  	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
>  	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
>  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> @@ -844,6 +856,9 @@ static bool expect_interrupts(uint32_t bitmap)
>  
>  static void test_overflow_interrupt(bool overflow_at_64bits)
>  {
> +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> +	uint64_t all_set = ALL_SET_AT(overflow_at_64bits);
> +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
>  	uint32_t events[] = {MEM_ACCESS, SW_INCR};
>  	void *addr = malloc(PAGE_SIZE);
>  	int i;
> @@ -862,16 +877,16 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
>  	write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
>  	write_regn_el0(pmevtyper, 1, SW_INCR | PMEVTYPER_EXCLUDE_EL0);
>  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
> +	write_regn_el0(pmevcntr, 1, pre_overflow);
>  	isb();
>  
>  	/* interrupts are disabled (PMINTENSET_EL1 == 0) */
>  
> -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
>  	report(expect_interrupts(0), "no overflow interrupt after preset");
>  
> -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
>  	isb();
>  
>  	for (i = 0; i < 100; i++)
> @@ -886,12 +901,12 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
>  
>  	pmu_reset_stats();
>  
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
> +	write_regn_el0(pmevcntr, 1, pre_overflow);
>  	write_sysreg(ALL_SET, pmintenset_el1);
>  	isb();
>  
> -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
>  	for (i = 0; i < 100; i++)
>  		write_sysreg(0x3, pmswinc_el0);
>  
> @@ -900,25 +915,35 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
>  	report(expect_interrupts(0x3),
>  		"overflow interrupts expected on #0 and #1");
>  
> -	/* promote to 64-b */
> +	/*
> +	 * promote to 64-b:
> +	 *
> +	 * This only applies to the !overflow_at_64bits case, as
> +	 * overflow_at_64bits doesn't implement CHAIN events. The
> +	 * overflow_at_64bits case just checks that chained counters are
> +	 * not incremented when PMCR.LP == 1.
> +	 */

If this doesn't do anything for when overflow_at_64bits, and since the
interrupt is already tested before this part, why not exit early?

Or the test could check that the CHAIN event indeed does not increment when
LP=1 at the end of this function.

Thanks,
Alex

>  
>  	pmu_reset_stats();
>  
>  	write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0);
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
>  	isb();
> -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> -	report(expect_interrupts(0x1),
> -		"expect overflow interrupt on 32b boundary");
> +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> +	report(expect_interrupts(0x1), "expect overflow interrupt");
>  
>  	/* overflow on odd counter */
>  	pmu_reset_stats();
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> -	write_regn_el0(pmevcntr, 1, ALL_SET);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
> +	write_regn_el0(pmevcntr, 1, all_set);
>  	isb();
> -	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E);
> -	report(expect_interrupts(0x3),
> -		"expect overflow interrupt on even and odd counter");
> +	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> +	if (overflow_at_64bits)
> +		report(expect_interrupts(0x1),
> +		       "expect overflow interrupt on even counter");
> +	else
> +		report(expect_interrupts(0x3),
> +		       "expect overflow interrupt on even and odd counter");
>  }
>  #endif
>  
> @@ -1119,10 +1144,13 @@ int main(int argc, char *argv[])
>  		report_prefix_pop();
>  	} else if (strcmp(argv[1], "pmu-basic-event-count") == 0) {
>  		run_test(argv[1], test_basic_event_count, false);
> +		run_test(argv[1], test_basic_event_count, true);
>  	} else if (strcmp(argv[1], "pmu-mem-access") == 0) {
>  		run_test(argv[1], test_mem_access, false);
> +		run_test(argv[1], test_mem_access, true);
>  	} else if (strcmp(argv[1], "pmu-sw-incr") == 0) {
>  		run_test(argv[1], test_sw_incr, false);
> +		run_test(argv[1], test_sw_incr, true);
>  	} else if (strcmp(argv[1], "pmu-chained-counters") == 0) {
>  		run_test(argv[1], test_chained_counters, false);
>  	} else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) {
> @@ -1131,6 +1159,7 @@ int main(int argc, char *argv[])
>  		run_test(argv[1], test_chain_promotion, false);
>  	} else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) {
>  		run_test(argv[1], test_overflow_interrupt, false);
> +		run_test(argv[1], test_overflow_interrupt, true);
>  	} else {
>  		report_abort("Unknown sub-test '%s'", argv[1]);
>  	}
> -- 
> 2.39.0.rc0.267.gcb52ba06e7-goog
> 

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

* Re: [kvm-unit-tests PATCH 3/3] arm: pmu: Add tests for 64-bit overflows
@ 2022-12-13 17:03     ` Alexandru Elisei
  0 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-13 17:03 UTC (permalink / raw)
  To: Ricardo Koller; +Cc: kvm, maz, andrew.jones, kvmarm

Hi,

Checked that all places where ALL_SET/PRE_OVERFLOW were used are now taking
into account the fact that counters are programmed to be 64bit.

In the case of 64bit counters, the printf format specifier is %ld, which
means that ALL_SET_64 and PRE_OVERFLOW_64 are now displayed as negative
numbers. For example:

INFO: pmu: pmu-sw-incr: 32-bit: SW_INCR counter #0 has value 4294967280
PASS: pmu: pmu-sw-incr: 32-bit: PWSYNC does not increment if PMCR.E is unset
[..]
INFO: pmu: pmu-sw-incr: 64-bit: SW_INCR counter #0 has value -16
PASS: pmu: pmu-sw-incr: 64-bit: PWSYNC does not increment if PMCR.E is unset

I was thinking that the format specifiers could be changed to unsigned
long.  The counters only increment, they don't decrement, and I can't think
how printing them as signed could be useful.

One more comment below.

On Fri, Dec 02, 2022 at 04:55:27AM +0000, Ricardo Koller wrote:
> Modify all tests checking overflows to support both 32 (PMCR_EL0.LP == 0)
> and 64-bit overflows (PMCR_EL0.LP == 1). 64-bit overflows are only
> supported on PMUv3p5.
> 
> Note that chained tests do not implement "overflow_at_64bits == true".
> That's because there are no CHAIN events when "PMCR_EL0.LP == 1" (for more
> details see AArch64.IncrementEventCounter() pseudocode in the ARM ARM DDI
> 0487H.a, J1.1.1 "aarch64/debug").
> 
> Signed-off-by: Ricardo Koller <ricarkol@google.com>
> ---
>  arm/pmu.c | 91 ++++++++++++++++++++++++++++++++++++-------------------
>  1 file changed, 60 insertions(+), 31 deletions(-)
> 
> diff --git a/arm/pmu.c b/arm/pmu.c
> index 59e5bfe..3cb563b 100644
> --- a/arm/pmu.c
> +++ b/arm/pmu.c
> @@ -28,6 +28,7 @@
>  #define PMU_PMCR_X         (1 << 4)
>  #define PMU_PMCR_DP        (1 << 5)
>  #define PMU_PMCR_LC        (1 << 6)
> +#define PMU_PMCR_LP        (1 << 7)
>  #define PMU_PMCR_N_SHIFT   11
>  #define PMU_PMCR_N_MASK    0x1f
>  #define PMU_PMCR_ID_SHIFT  16
> @@ -55,10 +56,15 @@
>  #define EXT_COMMON_EVENTS_HIGH	0x403F
>  
>  #define ALL_SET			0x00000000FFFFFFFFULL
> +#define ALL_SET_64		0xFFFFFFFFFFFFFFFFULL
>  #define ALL_CLEAR		0x0000000000000000ULL
>  #define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> +#define PRE_OVERFLOW_64		0xFFFFFFFFFFFFFFF0ULL
>  #define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
>  
> +#define PRE_OVERFLOW_AT(_64b)	(_64b ? PRE_OVERFLOW_64 : PRE_OVERFLOW)
> +#define ALL_SET_AT(_64b)	(_64b ? ALL_SET_64 : ALL_SET)
> +
>  #define PMU_PPI			23
>  
>  struct pmu {
> @@ -429,8 +435,10 @@ static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events,
>  static void test_basic_event_count(bool overflow_at_64bits)
>  {
>  	uint32_t implemented_counter_mask, non_implemented_counter_mask;
> -	uint32_t counter_mask;
> +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
>  	uint32_t events[] = {CPU_CYCLES, INST_RETIRED};
> +	uint32_t counter_mask;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
>  				   overflow_at_64bits))
> @@ -452,13 +460,13 @@ static void test_basic_event_count(bool overflow_at_64bits)
>  	 * clear cycle and all event counters and allow counter enablement
>  	 * through PMCNTENSET. LC is RES1.
>  	 */
> -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P);
> +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P | pmcr_lp);
>  	isb();
> -	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC), "pmcr: reset counters");
> +	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC | pmcr_lp), "pmcr: reset counters");
>  
>  	/* Preset counter #0 to pre overflow value to trigger an overflow */
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
> +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
>  		"counter #0 preset to pre-overflow value");
>  	report(!read_regn_el0(pmevcntr, 1), "counter #1 is 0");
>  
> @@ -511,6 +519,8 @@ static void test_mem_access(bool overflow_at_64bits)
>  {
>  	void *addr = malloc(PAGE_SIZE);
>  	uint32_t events[] = {MEM_ACCESS, MEM_ACCESS};
> +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
>  
>  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
>  				   overflow_at_64bits))
> @@ -522,7 +532,7 @@ static void test_mem_access(bool overflow_at_64bits)
>  	write_regn_el0(pmevtyper, 1, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
>  	write_sysreg_s(0x3, PMCNTENSET_EL0);
>  	isb();
> -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
>  	report_info("counter #0 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 0));
>  	report_info("counter #1 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 1));
>  	/* We may measure more than 20 mem access depending on the core */
> @@ -532,11 +542,11 @@ static void test_mem_access(bool overflow_at_64bits)
>  
>  	pmu_reset();
>  
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
> +	write_regn_el0(pmevcntr, 1, pre_overflow);
>  	write_sysreg_s(0x3, PMCNTENSET_EL0);
>  	isb();
> -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
>  	report(read_sysreg(pmovsclr_el0) == 0x3,
>  	       "Ran 20 mem accesses with expected overflows on both counters");
>  	report_info("cnt#0 = %ld cnt#1=%ld overflow=0x%lx",
> @@ -546,6 +556,8 @@ static void test_mem_access(bool overflow_at_64bits)
>  
>  static void test_sw_incr(bool overflow_at_64bits)
>  {
> +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
>  	uint32_t events[] = {SW_INCR, SW_INCR};
>  	uint64_t cntr0;
>  	int i;
> @@ -561,7 +573,7 @@ static void test_sw_incr(bool overflow_at_64bits)
>  	/* enable counters #0 and #1 */
>  	write_sysreg_s(0x3, PMCNTENSET_EL0);
>  
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
>  	isb();
>  
>  	for (i = 0; i < 100; i++)
> @@ -569,21 +581,21 @@ static void test_sw_incr(bool overflow_at_64bits)
>  
>  	isb();
>  	report_info("SW_INCR counter #0 has value %ld", read_regn_el0(pmevcntr, 0));
> -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
>  		"PWSYNC does not increment if PMCR.E is unset");
>  
>  	pmu_reset();
>  
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
>  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
>  	isb();
>  
>  	for (i = 0; i < 100; i++)
>  		write_sysreg(0x3, pmswinc_el0);
>  
>  	isb();
> -	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : pre_overflow + 100;
>  	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
>  	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
>  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> @@ -844,6 +856,9 @@ static bool expect_interrupts(uint32_t bitmap)
>  
>  static void test_overflow_interrupt(bool overflow_at_64bits)
>  {
> +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> +	uint64_t all_set = ALL_SET_AT(overflow_at_64bits);
> +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
>  	uint32_t events[] = {MEM_ACCESS, SW_INCR};
>  	void *addr = malloc(PAGE_SIZE);
>  	int i;
> @@ -862,16 +877,16 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
>  	write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
>  	write_regn_el0(pmevtyper, 1, SW_INCR | PMEVTYPER_EXCLUDE_EL0);
>  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
> +	write_regn_el0(pmevcntr, 1, pre_overflow);
>  	isb();
>  
>  	/* interrupts are disabled (PMINTENSET_EL1 == 0) */
>  
> -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
>  	report(expect_interrupts(0), "no overflow interrupt after preset");
>  
> -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
>  	isb();
>  
>  	for (i = 0; i < 100; i++)
> @@ -886,12 +901,12 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
>  
>  	pmu_reset_stats();
>  
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
> +	write_regn_el0(pmevcntr, 1, pre_overflow);
>  	write_sysreg(ALL_SET, pmintenset_el1);
>  	isb();
>  
> -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
>  	for (i = 0; i < 100; i++)
>  		write_sysreg(0x3, pmswinc_el0);
>  
> @@ -900,25 +915,35 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
>  	report(expect_interrupts(0x3),
>  		"overflow interrupts expected on #0 and #1");
>  
> -	/* promote to 64-b */
> +	/*
> +	 * promote to 64-b:
> +	 *
> +	 * This only applies to the !overflow_at_64bits case, as
> +	 * overflow_at_64bits doesn't implement CHAIN events. The
> +	 * overflow_at_64bits case just checks that chained counters are
> +	 * not incremented when PMCR.LP == 1.
> +	 */

If this doesn't do anything for when overflow_at_64bits, and since the
interrupt is already tested before this part, why not exit early?

Or the test could check that the CHAIN event indeed does not increment when
LP=1 at the end of this function.

Thanks,
Alex

>  
>  	pmu_reset_stats();
>  
>  	write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0);
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
>  	isb();
> -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> -	report(expect_interrupts(0x1),
> -		"expect overflow interrupt on 32b boundary");
> +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> +	report(expect_interrupts(0x1), "expect overflow interrupt");
>  
>  	/* overflow on odd counter */
>  	pmu_reset_stats();
> -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> -	write_regn_el0(pmevcntr, 1, ALL_SET);
> +	write_regn_el0(pmevcntr, 0, pre_overflow);
> +	write_regn_el0(pmevcntr, 1, all_set);
>  	isb();
> -	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E);
> -	report(expect_interrupts(0x3),
> -		"expect overflow interrupt on even and odd counter");
> +	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> +	if (overflow_at_64bits)
> +		report(expect_interrupts(0x1),
> +		       "expect overflow interrupt on even counter");
> +	else
> +		report(expect_interrupts(0x3),
> +		       "expect overflow interrupt on even and odd counter");
>  }
>  #endif
>  
> @@ -1119,10 +1144,13 @@ int main(int argc, char *argv[])
>  		report_prefix_pop();
>  	} else if (strcmp(argv[1], "pmu-basic-event-count") == 0) {
>  		run_test(argv[1], test_basic_event_count, false);
> +		run_test(argv[1], test_basic_event_count, true);
>  	} else if (strcmp(argv[1], "pmu-mem-access") == 0) {
>  		run_test(argv[1], test_mem_access, false);
> +		run_test(argv[1], test_mem_access, true);
>  	} else if (strcmp(argv[1], "pmu-sw-incr") == 0) {
>  		run_test(argv[1], test_sw_incr, false);
> +		run_test(argv[1], test_sw_incr, true);
>  	} else if (strcmp(argv[1], "pmu-chained-counters") == 0) {
>  		run_test(argv[1], test_chained_counters, false);
>  	} else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) {
> @@ -1131,6 +1159,7 @@ int main(int argc, char *argv[])
>  		run_test(argv[1], test_chain_promotion, false);
>  	} else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) {
>  		run_test(argv[1], test_overflow_interrupt, false);
> +		run_test(argv[1], test_overflow_interrupt, true);
>  	} else {
>  		report_abort("Unknown sub-test '%s'", argv[1]);
>  	}
> -- 
> 2.39.0.rc0.267.gcb52ba06e7-goog
> 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-13 16:43         ` Alexandru Elisei
@ 2022-12-13 18:01           ` Ricardo Koller
  -1 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-13 18:01 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: kvm, kvmarm, andrew.jones, maz, eric.auger, oliver.upton, reijiw

On Tue, Dec 13, 2022 at 04:43:38PM +0000, Alexandru Elisei wrote:
> Hi,
> 
> On Tue, Dec 13, 2022 at 08:21:24AM -0800, Ricardo Koller wrote:
> > On Tue, Dec 13, 2022 at 12:36:14PM +0000, Alexandru Elisei wrote:
> > > Hi,
> > > 
> > > Some more comments below.
> > > 
> > > On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > > > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > > > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > > > the counter values after overflowing should not assume that values will be
> > > > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > > > counters on PMUv3p5.
> > > > 
> > > > Fix tests by correctly checking overflowing-counters against the expected
> > > > 64-bit value.
> > > > 
> > > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > > ---
> > > >  arm/pmu.c | 29 ++++++++++++++++++-----------
> > > >  1 file changed, 18 insertions(+), 11 deletions(-)
> > > > 
> > > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > > index cd47b14..eeac984 100644
> > > > --- a/arm/pmu.c
> > > > +++ b/arm/pmu.c
> > > > @@ -54,10 +54,10 @@
> > > >  #define EXT_COMMON_EVENTS_LOW	0x4000
> > > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > > >  
> > > > -#define ALL_SET			0xFFFFFFFF
> > > > -#define ALL_CLEAR		0x0
> > > > -#define PRE_OVERFLOW		0xFFFFFFF0
> > > > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > > > +#define ALL_SET			0x00000000FFFFFFFFULL
> > > > +#define ALL_CLEAR		0x0000000000000000ULL
> > > > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > > >  
> > > >  #define PMU_PPI			23
> > > >  
> > > > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> > > >  static void test_sw_incr(void)
> > > >  {
> > > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > > > +	uint64_t cntr0;
> > > >  	int i;
> > > >  
> > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> > > >  		write_sysreg(0x3, pmswinc_el0);
> > > >  
> > > >  	isb();
> > > > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > > > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > > > -		"counter #0 after + 100 SW_INCR");
> > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > > +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > > > +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> > > >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > > >  	report(read_sysreg(pmovsclr_el0) == 0x1,
> > > > @@ -584,6 +585,7 @@ static void test_sw_incr(void)
> > > >  static void test_chained_counters(void)
> > > >  {
> > > >  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> > > > +	uint64_t cntr1;
> > > >  
> > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > >  		return;
> > > > @@ -618,13 +620,16 @@ static void test_chained_counters(void)
> > > >  
> > > >  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> > > >  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > > > -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> > > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > > +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > > 
> > > It looks to me like the intention of the test was to check that the counter
> > > programmed with the CHAIN event wraps, judging from the report message.
> > > 
> > 
> > Ah, right. Yeah, that message is confusing. It should be the short
> > version of "Inrementing at 32-bits resulted in the right value".
> > 
> > > I think it would be interesting to keep that by programming counter #1 with
> > > ~0ULL when PMUv3p5 (maybe call it ALL_SET64?) and test the counter value
> > > against 0.
> > 
> > The last commit adds tests using ALL_SET64.  Tests can be run in two
> > modes: overflow_at_64bits and not.  However, this test,
> > test_chained_counters(), and all other chained tests only use the
> > !overflow_at_64bits mode (even after the last commit). The reason is
> > that there are no CHAIN events when overflowing at 64-bits (more details
> > in the commit message). But, don't worry, there are lots of tests that
> > check wrapping at 64-bits (overflow_at_64bits=true).
> 
> What I was suggesting is this (change on top of this series, not on top of
> this patch, to get access to ALL_SET_AT):

Ooh, I see, I agree: it would be better to check that the odd counter
increments from ~0ULL to 0 when using 64-bit counters.

> 
> diff --git a/arm/pmu.c b/arm/pmu.c
> index 3cb563b1abe4..fd7f20fc6c52 100644
> --- a/arm/pmu.c
> +++ b/arm/pmu.c
> @@ -607,7 +607,6 @@ static void test_sw_incr(bool overflow_at_64bits)
>  static void test_chained_counters(bool overflow_at_64bits)
>  {
>         uint32_t events[] = {CPU_CYCLES, CHAIN};
> -       uint64_t cntr1;
> 
>         if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
>                                    overflow_at_64bits))
> @@ -639,12 +638,11 @@ static void test_chained_counters(bool overflow_at_64bits)
>         report(read_sysreg(pmovsclr_el0) == 0x1, "overflow recorded for chained incr #2");
> 
>         write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> -       write_regn_el0(pmevcntr, 1, ALL_SET);
> +       write_regn_el0(pmevcntr, 1, ALL_SET_AT(overflow_at_64bits));

The only change is that this should be:

	ALL_SET_AT(pmu.version >= ID_DFR0_PMU_V3_8_5)

Because "overflow_at_64bits" implies PMCR_EL0.LP = 1.

> 
>         precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
>         report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> -       cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> -       report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> +       report(read_regn_el0(pmevcntr, 1) == 0, "CHAIN counter #1 wrapped");
> 
>         report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
>  }
> 
> The counters are 64bit, but the CHAIN event should still work because
> PMCR_EL0.LP is 0, according to the event description in the Arm ARM (ARM
> DDI 0487I.a, page D17-6461).
> 
> Thanks,
> Alex
> 
> > 
> > > Alternatively, the report message can be modified, and "wrapped"
> > > replaced with "incremented" (or something like that), to avoid confusion.
> > > 
> > > > +
> > > >  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> > > >  }
> > > >  
> > > >  static void test_chained_sw_incr(void)
> > > >  {
> > > >  	uint32_t events[] = {SW_INCR, CHAIN};
> > > > +	uint64_t cntr0, cntr1;
> > > >  	int i;
> > > >  
> > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
> > > >  		write_sysreg(0x1, pmswinc_el0);
> > > >  
> > > >  	isb();
> > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > >  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> > > > -		(read_regn_el0(pmevcntr, 1) == 0) &&
> > > > -		(read_regn_el0(pmevcntr, 0) == 84),
> > > > -		"expected overflows and values after 100 SW_INCR/CHAIN");
> > > > +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> > > > +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> > > 
> > > This is hard to parse, it would be better if counter 0 is compared against
> > > cntr0 and counter 1 against cntr1.
> > 
> > Ah, yes, code is correct but that's indeed confusing.
> > 
> > > 
> > > Also, same suggestion here, looks like the test wants to check that the
> > > odd-numbered counter wraps around when counting the CHAIN event.
> > 
> > Ack. Will update for v2.
> > 
> > Thanks!
> > Ricardo
> > 
> > > 
> > > Thanks,
> > > Alex
> > > 
> > > > +	       "expected overflows and values after 100 SW_INCR/CHAIN");
> > > >  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
> > > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > > >  }
> > > > -- 
> > > > 2.39.0.rc0.267.gcb52ba06e7-goog
> > > > 

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-13 18:01           ` Ricardo Koller
  0 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-13 18:01 UTC (permalink / raw)
  To: Alexandru Elisei; +Cc: kvm, maz, andrew.jones, kvmarm

On Tue, Dec 13, 2022 at 04:43:38PM +0000, Alexandru Elisei wrote:
> Hi,
> 
> On Tue, Dec 13, 2022 at 08:21:24AM -0800, Ricardo Koller wrote:
> > On Tue, Dec 13, 2022 at 12:36:14PM +0000, Alexandru Elisei wrote:
> > > Hi,
> > > 
> > > Some more comments below.
> > > 
> > > On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > > > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > > > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > > > the counter values after overflowing should not assume that values will be
> > > > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > > > counters on PMUv3p5.
> > > > 
> > > > Fix tests by correctly checking overflowing-counters against the expected
> > > > 64-bit value.
> > > > 
> > > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > > ---
> > > >  arm/pmu.c | 29 ++++++++++++++++++-----------
> > > >  1 file changed, 18 insertions(+), 11 deletions(-)
> > > > 
> > > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > > index cd47b14..eeac984 100644
> > > > --- a/arm/pmu.c
> > > > +++ b/arm/pmu.c
> > > > @@ -54,10 +54,10 @@
> > > >  #define EXT_COMMON_EVENTS_LOW	0x4000
> > > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > > >  
> > > > -#define ALL_SET			0xFFFFFFFF
> > > > -#define ALL_CLEAR		0x0
> > > > -#define PRE_OVERFLOW		0xFFFFFFF0
> > > > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > > > +#define ALL_SET			0x00000000FFFFFFFFULL
> > > > +#define ALL_CLEAR		0x0000000000000000ULL
> > > > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > > >  
> > > >  #define PMU_PPI			23
> > > >  
> > > > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> > > >  static void test_sw_incr(void)
> > > >  {
> > > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > > > +	uint64_t cntr0;
> > > >  	int i;
> > > >  
> > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> > > >  		write_sysreg(0x3, pmswinc_el0);
> > > >  
> > > >  	isb();
> > > > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > > > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > > > -		"counter #0 after + 100 SW_INCR");
> > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > > +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > > > +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> > > >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > > >  	report(read_sysreg(pmovsclr_el0) == 0x1,
> > > > @@ -584,6 +585,7 @@ static void test_sw_incr(void)
> > > >  static void test_chained_counters(void)
> > > >  {
> > > >  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> > > > +	uint64_t cntr1;
> > > >  
> > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > >  		return;
> > > > @@ -618,13 +620,16 @@ static void test_chained_counters(void)
> > > >  
> > > >  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> > > >  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > > > -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> > > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > > +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > > 
> > > It looks to me like the intention of the test was to check that the counter
> > > programmed with the CHAIN event wraps, judging from the report message.
> > > 
> > 
> > Ah, right. Yeah, that message is confusing. It should be the short
> > version of "Inrementing at 32-bits resulted in the right value".
> > 
> > > I think it would be interesting to keep that by programming counter #1 with
> > > ~0ULL when PMUv3p5 (maybe call it ALL_SET64?) and test the counter value
> > > against 0.
> > 
> > The last commit adds tests using ALL_SET64.  Tests can be run in two
> > modes: overflow_at_64bits and not.  However, this test,
> > test_chained_counters(), and all other chained tests only use the
> > !overflow_at_64bits mode (even after the last commit). The reason is
> > that there are no CHAIN events when overflowing at 64-bits (more details
> > in the commit message). But, don't worry, there are lots of tests that
> > check wrapping at 64-bits (overflow_at_64bits=true).
> 
> What I was suggesting is this (change on top of this series, not on top of
> this patch, to get access to ALL_SET_AT):

Ooh, I see, I agree: it would be better to check that the odd counter
increments from ~0ULL to 0 when using 64-bit counters.

> 
> diff --git a/arm/pmu.c b/arm/pmu.c
> index 3cb563b1abe4..fd7f20fc6c52 100644
> --- a/arm/pmu.c
> +++ b/arm/pmu.c
> @@ -607,7 +607,6 @@ static void test_sw_incr(bool overflow_at_64bits)
>  static void test_chained_counters(bool overflow_at_64bits)
>  {
>         uint32_t events[] = {CPU_CYCLES, CHAIN};
> -       uint64_t cntr1;
> 
>         if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
>                                    overflow_at_64bits))
> @@ -639,12 +638,11 @@ static void test_chained_counters(bool overflow_at_64bits)
>         report(read_sysreg(pmovsclr_el0) == 0x1, "overflow recorded for chained incr #2");
> 
>         write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> -       write_regn_el0(pmevcntr, 1, ALL_SET);
> +       write_regn_el0(pmevcntr, 1, ALL_SET_AT(overflow_at_64bits));

The only change is that this should be:

	ALL_SET_AT(pmu.version >= ID_DFR0_PMU_V3_8_5)

Because "overflow_at_64bits" implies PMCR_EL0.LP = 1.

> 
>         precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
>         report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> -       cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> -       report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> +       report(read_regn_el0(pmevcntr, 1) == 0, "CHAIN counter #1 wrapped");
> 
>         report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
>  }
> 
> The counters are 64bit, but the CHAIN event should still work because
> PMCR_EL0.LP is 0, according to the event description in the Arm ARM (ARM
> DDI 0487I.a, page D17-6461).
> 
> Thanks,
> Alex
> 
> > 
> > > Alternatively, the report message can be modified, and "wrapped"
> > > replaced with "incremented" (or something like that), to avoid confusion.
> > > 
> > > > +
> > > >  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> > > >  }
> > > >  
> > > >  static void test_chained_sw_incr(void)
> > > >  {
> > > >  	uint32_t events[] = {SW_INCR, CHAIN};
> > > > +	uint64_t cntr0, cntr1;
> > > >  	int i;
> > > >  
> > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
> > > >  		write_sysreg(0x1, pmswinc_el0);
> > > >  
> > > >  	isb();
> > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > >  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> > > > -		(read_regn_el0(pmevcntr, 1) == 0) &&
> > > > -		(read_regn_el0(pmevcntr, 0) == 84),
> > > > -		"expected overflows and values after 100 SW_INCR/CHAIN");
> > > > +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> > > > +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> > > 
> > > This is hard to parse, it would be better if counter 0 is compared against
> > > cntr0 and counter 1 against cntr1.
> > 
> > Ah, yes, code is correct but that's indeed confusing.
> > 
> > > 
> > > Also, same suggestion here, looks like the test wants to check that the
> > > odd-numbered counter wraps around when counting the CHAIN event.
> > 
> > Ack. Will update for v2.
> > 
> > Thanks!
> > Ricardo
> > 
> > > 
> > > Thanks,
> > > Alex
> > > 
> > > > +	       "expected overflows and values after 100 SW_INCR/CHAIN");
> > > >  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
> > > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > > >  }
> > > > -- 
> > > > 2.39.0.rc0.267.gcb52ba06e7-goog
> > > > 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 3/3] arm: pmu: Add tests for 64-bit overflows
  2022-12-13 17:03     ` Alexandru Elisei
@ 2022-12-13 18:04       ` Ricardo Koller
  -1 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-13 18:04 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: kvm, kvmarm, andrew.jones, maz, eric.auger, oliver.upton, reijiw

On Tue, Dec 13, 2022 at 05:03:40PM +0000, Alexandru Elisei wrote:
> Hi,
> 
> Checked that all places where ALL_SET/PRE_OVERFLOW were used are now taking
> into account the fact that counters are programmed to be 64bit.
> 
> In the case of 64bit counters, the printf format specifier is %ld, which
> means that ALL_SET_64 and PRE_OVERFLOW_64 are now displayed as negative
> numbers. For example:
> 
> INFO: pmu: pmu-sw-incr: 32-bit: SW_INCR counter #0 has value 4294967280
> PASS: pmu: pmu-sw-incr: 32-bit: PWSYNC does not increment if PMCR.E is unset
> [..]
> INFO: pmu: pmu-sw-incr: 64-bit: SW_INCR counter #0 has value -16
> PASS: pmu: pmu-sw-incr: 64-bit: PWSYNC does not increment if PMCR.E is unset
> 

Argh, I didn't notice this. I think this would be more useful if it
printed %llx in all cases.

> I was thinking that the format specifiers could be changed to unsigned
> long.  The counters only increment, they don't decrement, and I can't think
> how printing them as signed could be useful.
> 
> One more comment below.
> 
> On Fri, Dec 02, 2022 at 04:55:27AM +0000, Ricardo Koller wrote:
> > Modify all tests checking overflows to support both 32 (PMCR_EL0.LP == 0)
> > and 64-bit overflows (PMCR_EL0.LP == 1). 64-bit overflows are only
> > supported on PMUv3p5.
> > 
> > Note that chained tests do not implement "overflow_at_64bits == true".
> > That's because there are no CHAIN events when "PMCR_EL0.LP == 1" (for more
> > details see AArch64.IncrementEventCounter() pseudocode in the ARM ARM DDI
> > 0487H.a, J1.1.1 "aarch64/debug").
> > 
> > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > ---
> >  arm/pmu.c | 91 ++++++++++++++++++++++++++++++++++++-------------------
> >  1 file changed, 60 insertions(+), 31 deletions(-)
> > 
> > diff --git a/arm/pmu.c b/arm/pmu.c
> > index 59e5bfe..3cb563b 100644
> > --- a/arm/pmu.c
> > +++ b/arm/pmu.c
> > @@ -28,6 +28,7 @@
> >  #define PMU_PMCR_X         (1 << 4)
> >  #define PMU_PMCR_DP        (1 << 5)
> >  #define PMU_PMCR_LC        (1 << 6)
> > +#define PMU_PMCR_LP        (1 << 7)
> >  #define PMU_PMCR_N_SHIFT   11
> >  #define PMU_PMCR_N_MASK    0x1f
> >  #define PMU_PMCR_ID_SHIFT  16
> > @@ -55,10 +56,15 @@
> >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> >  
> >  #define ALL_SET			0x00000000FFFFFFFFULL
> > +#define ALL_SET_64		0xFFFFFFFFFFFFFFFFULL
> >  #define ALL_CLEAR		0x0000000000000000ULL
> >  #define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > +#define PRE_OVERFLOW_64		0xFFFFFFFFFFFFFFF0ULL
> >  #define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> >  
> > +#define PRE_OVERFLOW_AT(_64b)	(_64b ? PRE_OVERFLOW_64 : PRE_OVERFLOW)
> > +#define ALL_SET_AT(_64b)	(_64b ? ALL_SET_64 : ALL_SET)
> > +
> >  #define PMU_PPI			23
> >  
> >  struct pmu {
> > @@ -429,8 +435,10 @@ static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events,
> >  static void test_basic_event_count(bool overflow_at_64bits)
> >  {
> >  	uint32_t implemented_counter_mask, non_implemented_counter_mask;
> > -	uint32_t counter_mask;
> > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> >  	uint32_t events[] = {CPU_CYCLES, INST_RETIRED};
> > +	uint32_t counter_mask;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> >  				   overflow_at_64bits))
> > @@ -452,13 +460,13 @@ static void test_basic_event_count(bool overflow_at_64bits)
> >  	 * clear cycle and all event counters and allow counter enablement
> >  	 * through PMCNTENSET. LC is RES1.
> >  	 */
> > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P);
> > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P | pmcr_lp);
> >  	isb();
> > -	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC), "pmcr: reset counters");
> > +	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC | pmcr_lp), "pmcr: reset counters");
> >  
> >  	/* Preset counter #0 to pre overflow value to trigger an overflow */
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
> >  		"counter #0 preset to pre-overflow value");
> >  	report(!read_regn_el0(pmevcntr, 1), "counter #1 is 0");
> >  
> > @@ -511,6 +519,8 @@ static void test_mem_access(bool overflow_at_64bits)
> >  {
> >  	void *addr = malloc(PAGE_SIZE);
> >  	uint32_t events[] = {MEM_ACCESS, MEM_ACCESS};
> > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> >  				   overflow_at_64bits))
> > @@ -522,7 +532,7 @@ static void test_mem_access(bool overflow_at_64bits)
> >  	write_regn_el0(pmevtyper, 1, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
> >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> >  	isb();
> > -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> >  	report_info("counter #0 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 0));
> >  	report_info("counter #1 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 1));
> >  	/* We may measure more than 20 mem access depending on the core */
> > @@ -532,11 +542,11 @@ static void test_mem_access(bool overflow_at_64bits)
> >  
> >  	pmu_reset();
> >  
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> >  	isb();
> > -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> >  	report(read_sysreg(pmovsclr_el0) == 0x3,
> >  	       "Ran 20 mem accesses with expected overflows on both counters");
> >  	report_info("cnt#0 = %ld cnt#1=%ld overflow=0x%lx",
> > @@ -546,6 +556,8 @@ static void test_mem_access(bool overflow_at_64bits)
> >  
> >  static void test_sw_incr(bool overflow_at_64bits)
> >  {
> > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> >  	uint32_t events[] = {SW_INCR, SW_INCR};
> >  	uint64_t cntr0;
> >  	int i;
> > @@ -561,7 +573,7 @@ static void test_sw_incr(bool overflow_at_64bits)
> >  	/* enable counters #0 and #1 */
> >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> >  
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> >  	isb();
> >  
> >  	for (i = 0; i < 100; i++)
> > @@ -569,21 +581,21 @@ static void test_sw_incr(bool overflow_at_64bits)
> >  
> >  	isb();
> >  	report_info("SW_INCR counter #0 has value %ld", read_regn_el0(pmevcntr, 0));
> > -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> > +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
> >  		"PWSYNC does not increment if PMCR.E is unset");
> >  
> >  	pmu_reset();
> >  
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> >  	isb();
> >  
> >  	for (i = 0; i < 100; i++)
> >  		write_sysreg(0x3, pmswinc_el0);
> >  
> >  	isb();
> > -	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : pre_overflow + 100;
> >  	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> >  	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > @@ -844,6 +856,9 @@ static bool expect_interrupts(uint32_t bitmap)
> >  
> >  static void test_overflow_interrupt(bool overflow_at_64bits)
> >  {
> > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > +	uint64_t all_set = ALL_SET_AT(overflow_at_64bits);
> > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> >  	uint32_t events[] = {MEM_ACCESS, SW_INCR};
> >  	void *addr = malloc(PAGE_SIZE);
> >  	int i;
> > @@ -862,16 +877,16 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> >  	write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
> >  	write_regn_el0(pmevtyper, 1, SW_INCR | PMEVTYPER_EXCLUDE_EL0);
> >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> >  	isb();
> >  
> >  	/* interrupts are disabled (PMINTENSET_EL1 == 0) */
> >  
> > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> >  	report(expect_interrupts(0), "no overflow interrupt after preset");
> >  
> > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> >  	isb();
> >  
> >  	for (i = 0; i < 100; i++)
> > @@ -886,12 +901,12 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> >  
> >  	pmu_reset_stats();
> >  
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> >  	write_sysreg(ALL_SET, pmintenset_el1);
> >  	isb();
> >  
> > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> >  	for (i = 0; i < 100; i++)
> >  		write_sysreg(0x3, pmswinc_el0);
> >  
> > @@ -900,25 +915,35 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> >  	report(expect_interrupts(0x3),
> >  		"overflow interrupts expected on #0 and #1");
> >  
> > -	/* promote to 64-b */
> > +	/*
> > +	 * promote to 64-b:
> > +	 *
> > +	 * This only applies to the !overflow_at_64bits case, as
> > +	 * overflow_at_64bits doesn't implement CHAIN events. The
> > +	 * overflow_at_64bits case just checks that chained counters are
> > +	 * not incremented when PMCR.LP == 1.
> > +	 */
> 
> If this doesn't do anything for when overflow_at_64bits, and since the
> interrupt is already tested before this part, why not exit early?
> 
> Or the test could check that the CHAIN event indeed does not increment when
> LP=1 at the end of this function.

That's precisely what it's doing.

Thanks!
Ricardo

> 
> Thanks,
> Alex
> 
> >  
> >  	pmu_reset_stats();
> >  
> >  	write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0);
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> >  	isb();
> > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > -	report(expect_interrupts(0x1),
> > -		"expect overflow interrupt on 32b boundary");
> > +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > +	report(expect_interrupts(0x1), "expect overflow interrupt");
> >  
> >  	/* overflow on odd counter */
> >  	pmu_reset_stats();
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > -	write_regn_el0(pmevcntr, 1, ALL_SET);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > +	write_regn_el0(pmevcntr, 1, all_set);
> >  	isb();
> > -	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E);
> > -	report(expect_interrupts(0x3),
> > -		"expect overflow interrupt on even and odd counter");
> > +	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > +	if (overflow_at_64bits)
> > +		report(expect_interrupts(0x1),
> > +		       "expect overflow interrupt on even counter");
> > +	else
> > +		report(expect_interrupts(0x3),
> > +		       "expect overflow interrupt on even and odd counter");
> >  }
> >  #endif
> >  
> > @@ -1119,10 +1144,13 @@ int main(int argc, char *argv[])
> >  		report_prefix_pop();
> >  	} else if (strcmp(argv[1], "pmu-basic-event-count") == 0) {
> >  		run_test(argv[1], test_basic_event_count, false);
> > +		run_test(argv[1], test_basic_event_count, true);
> >  	} else if (strcmp(argv[1], "pmu-mem-access") == 0) {
> >  		run_test(argv[1], test_mem_access, false);
> > +		run_test(argv[1], test_mem_access, true);
> >  	} else if (strcmp(argv[1], "pmu-sw-incr") == 0) {
> >  		run_test(argv[1], test_sw_incr, false);
> > +		run_test(argv[1], test_sw_incr, true);
> >  	} else if (strcmp(argv[1], "pmu-chained-counters") == 0) {
> >  		run_test(argv[1], test_chained_counters, false);
> >  	} else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) {
> > @@ -1131,6 +1159,7 @@ int main(int argc, char *argv[])
> >  		run_test(argv[1], test_chain_promotion, false);
> >  	} else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) {
> >  		run_test(argv[1], test_overflow_interrupt, false);
> > +		run_test(argv[1], test_overflow_interrupt, true);
> >  	} else {
> >  		report_abort("Unknown sub-test '%s'", argv[1]);
> >  	}
> > -- 
> > 2.39.0.rc0.267.gcb52ba06e7-goog
> > 

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

* Re: [kvm-unit-tests PATCH 3/3] arm: pmu: Add tests for 64-bit overflows
@ 2022-12-13 18:04       ` Ricardo Koller
  0 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-13 18:04 UTC (permalink / raw)
  To: Alexandru Elisei; +Cc: kvm, maz, andrew.jones, kvmarm

On Tue, Dec 13, 2022 at 05:03:40PM +0000, Alexandru Elisei wrote:
> Hi,
> 
> Checked that all places where ALL_SET/PRE_OVERFLOW were used are now taking
> into account the fact that counters are programmed to be 64bit.
> 
> In the case of 64bit counters, the printf format specifier is %ld, which
> means that ALL_SET_64 and PRE_OVERFLOW_64 are now displayed as negative
> numbers. For example:
> 
> INFO: pmu: pmu-sw-incr: 32-bit: SW_INCR counter #0 has value 4294967280
> PASS: pmu: pmu-sw-incr: 32-bit: PWSYNC does not increment if PMCR.E is unset
> [..]
> INFO: pmu: pmu-sw-incr: 64-bit: SW_INCR counter #0 has value -16
> PASS: pmu: pmu-sw-incr: 64-bit: PWSYNC does not increment if PMCR.E is unset
> 

Argh, I didn't notice this. I think this would be more useful if it
printed %llx in all cases.

> I was thinking that the format specifiers could be changed to unsigned
> long.  The counters only increment, they don't decrement, and I can't think
> how printing them as signed could be useful.
> 
> One more comment below.
> 
> On Fri, Dec 02, 2022 at 04:55:27AM +0000, Ricardo Koller wrote:
> > Modify all tests checking overflows to support both 32 (PMCR_EL0.LP == 0)
> > and 64-bit overflows (PMCR_EL0.LP == 1). 64-bit overflows are only
> > supported on PMUv3p5.
> > 
> > Note that chained tests do not implement "overflow_at_64bits == true".
> > That's because there are no CHAIN events when "PMCR_EL0.LP == 1" (for more
> > details see AArch64.IncrementEventCounter() pseudocode in the ARM ARM DDI
> > 0487H.a, J1.1.1 "aarch64/debug").
> > 
> > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > ---
> >  arm/pmu.c | 91 ++++++++++++++++++++++++++++++++++++-------------------
> >  1 file changed, 60 insertions(+), 31 deletions(-)
> > 
> > diff --git a/arm/pmu.c b/arm/pmu.c
> > index 59e5bfe..3cb563b 100644
> > --- a/arm/pmu.c
> > +++ b/arm/pmu.c
> > @@ -28,6 +28,7 @@
> >  #define PMU_PMCR_X         (1 << 4)
> >  #define PMU_PMCR_DP        (1 << 5)
> >  #define PMU_PMCR_LC        (1 << 6)
> > +#define PMU_PMCR_LP        (1 << 7)
> >  #define PMU_PMCR_N_SHIFT   11
> >  #define PMU_PMCR_N_MASK    0x1f
> >  #define PMU_PMCR_ID_SHIFT  16
> > @@ -55,10 +56,15 @@
> >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> >  
> >  #define ALL_SET			0x00000000FFFFFFFFULL
> > +#define ALL_SET_64		0xFFFFFFFFFFFFFFFFULL
> >  #define ALL_CLEAR		0x0000000000000000ULL
> >  #define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > +#define PRE_OVERFLOW_64		0xFFFFFFFFFFFFFFF0ULL
> >  #define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> >  
> > +#define PRE_OVERFLOW_AT(_64b)	(_64b ? PRE_OVERFLOW_64 : PRE_OVERFLOW)
> > +#define ALL_SET_AT(_64b)	(_64b ? ALL_SET_64 : ALL_SET)
> > +
> >  #define PMU_PPI			23
> >  
> >  struct pmu {
> > @@ -429,8 +435,10 @@ static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events,
> >  static void test_basic_event_count(bool overflow_at_64bits)
> >  {
> >  	uint32_t implemented_counter_mask, non_implemented_counter_mask;
> > -	uint32_t counter_mask;
> > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> >  	uint32_t events[] = {CPU_CYCLES, INST_RETIRED};
> > +	uint32_t counter_mask;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> >  				   overflow_at_64bits))
> > @@ -452,13 +460,13 @@ static void test_basic_event_count(bool overflow_at_64bits)
> >  	 * clear cycle and all event counters and allow counter enablement
> >  	 * through PMCNTENSET. LC is RES1.
> >  	 */
> > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P);
> > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P | pmcr_lp);
> >  	isb();
> > -	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC), "pmcr: reset counters");
> > +	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC | pmcr_lp), "pmcr: reset counters");
> >  
> >  	/* Preset counter #0 to pre overflow value to trigger an overflow */
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
> >  		"counter #0 preset to pre-overflow value");
> >  	report(!read_regn_el0(pmevcntr, 1), "counter #1 is 0");
> >  
> > @@ -511,6 +519,8 @@ static void test_mem_access(bool overflow_at_64bits)
> >  {
> >  	void *addr = malloc(PAGE_SIZE);
> >  	uint32_t events[] = {MEM_ACCESS, MEM_ACCESS};
> > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> >  
> >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> >  				   overflow_at_64bits))
> > @@ -522,7 +532,7 @@ static void test_mem_access(bool overflow_at_64bits)
> >  	write_regn_el0(pmevtyper, 1, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
> >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> >  	isb();
> > -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> >  	report_info("counter #0 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 0));
> >  	report_info("counter #1 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 1));
> >  	/* We may measure more than 20 mem access depending on the core */
> > @@ -532,11 +542,11 @@ static void test_mem_access(bool overflow_at_64bits)
> >  
> >  	pmu_reset();
> >  
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> >  	isb();
> > -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> >  	report(read_sysreg(pmovsclr_el0) == 0x3,
> >  	       "Ran 20 mem accesses with expected overflows on both counters");
> >  	report_info("cnt#0 = %ld cnt#1=%ld overflow=0x%lx",
> > @@ -546,6 +556,8 @@ static void test_mem_access(bool overflow_at_64bits)
> >  
> >  static void test_sw_incr(bool overflow_at_64bits)
> >  {
> > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> >  	uint32_t events[] = {SW_INCR, SW_INCR};
> >  	uint64_t cntr0;
> >  	int i;
> > @@ -561,7 +573,7 @@ static void test_sw_incr(bool overflow_at_64bits)
> >  	/* enable counters #0 and #1 */
> >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> >  
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> >  	isb();
> >  
> >  	for (i = 0; i < 100; i++)
> > @@ -569,21 +581,21 @@ static void test_sw_incr(bool overflow_at_64bits)
> >  
> >  	isb();
> >  	report_info("SW_INCR counter #0 has value %ld", read_regn_el0(pmevcntr, 0));
> > -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> > +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
> >  		"PWSYNC does not increment if PMCR.E is unset");
> >  
> >  	pmu_reset();
> >  
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> >  	isb();
> >  
> >  	for (i = 0; i < 100; i++)
> >  		write_sysreg(0x3, pmswinc_el0);
> >  
> >  	isb();
> > -	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : pre_overflow + 100;
> >  	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> >  	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > @@ -844,6 +856,9 @@ static bool expect_interrupts(uint32_t bitmap)
> >  
> >  static void test_overflow_interrupt(bool overflow_at_64bits)
> >  {
> > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > +	uint64_t all_set = ALL_SET_AT(overflow_at_64bits);
> > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> >  	uint32_t events[] = {MEM_ACCESS, SW_INCR};
> >  	void *addr = malloc(PAGE_SIZE);
> >  	int i;
> > @@ -862,16 +877,16 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> >  	write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
> >  	write_regn_el0(pmevtyper, 1, SW_INCR | PMEVTYPER_EXCLUDE_EL0);
> >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> >  	isb();
> >  
> >  	/* interrupts are disabled (PMINTENSET_EL1 == 0) */
> >  
> > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> >  	report(expect_interrupts(0), "no overflow interrupt after preset");
> >  
> > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> >  	isb();
> >  
> >  	for (i = 0; i < 100; i++)
> > @@ -886,12 +901,12 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> >  
> >  	pmu_reset_stats();
> >  
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> >  	write_sysreg(ALL_SET, pmintenset_el1);
> >  	isb();
> >  
> > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> >  	for (i = 0; i < 100; i++)
> >  		write_sysreg(0x3, pmswinc_el0);
> >  
> > @@ -900,25 +915,35 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> >  	report(expect_interrupts(0x3),
> >  		"overflow interrupts expected on #0 and #1");
> >  
> > -	/* promote to 64-b */
> > +	/*
> > +	 * promote to 64-b:
> > +	 *
> > +	 * This only applies to the !overflow_at_64bits case, as
> > +	 * overflow_at_64bits doesn't implement CHAIN events. The
> > +	 * overflow_at_64bits case just checks that chained counters are
> > +	 * not incremented when PMCR.LP == 1.
> > +	 */
> 
> If this doesn't do anything for when overflow_at_64bits, and since the
> interrupt is already tested before this part, why not exit early?
> 
> Or the test could check that the CHAIN event indeed does not increment when
> LP=1 at the end of this function.

That's precisely what it's doing.

Thanks!
Ricardo

> 
> Thanks,
> Alex
> 
> >  
> >  	pmu_reset_stats();
> >  
> >  	write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0);
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> >  	isb();
> > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > -	report(expect_interrupts(0x1),
> > -		"expect overflow interrupt on 32b boundary");
> > +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > +	report(expect_interrupts(0x1), "expect overflow interrupt");
> >  
> >  	/* overflow on odd counter */
> >  	pmu_reset_stats();
> > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > -	write_regn_el0(pmevcntr, 1, ALL_SET);
> > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > +	write_regn_el0(pmevcntr, 1, all_set);
> >  	isb();
> > -	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E);
> > -	report(expect_interrupts(0x3),
> > -		"expect overflow interrupt on even and odd counter");
> > +	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > +	if (overflow_at_64bits)
> > +		report(expect_interrupts(0x1),
> > +		       "expect overflow interrupt on even counter");
> > +	else
> > +		report(expect_interrupts(0x3),
> > +		       "expect overflow interrupt on even and odd counter");
> >  }
> >  #endif
> >  
> > @@ -1119,10 +1144,13 @@ int main(int argc, char *argv[])
> >  		report_prefix_pop();
> >  	} else if (strcmp(argv[1], "pmu-basic-event-count") == 0) {
> >  		run_test(argv[1], test_basic_event_count, false);
> > +		run_test(argv[1], test_basic_event_count, true);
> >  	} else if (strcmp(argv[1], "pmu-mem-access") == 0) {
> >  		run_test(argv[1], test_mem_access, false);
> > +		run_test(argv[1], test_mem_access, true);
> >  	} else if (strcmp(argv[1], "pmu-sw-incr") == 0) {
> >  		run_test(argv[1], test_sw_incr, false);
> > +		run_test(argv[1], test_sw_incr, true);
> >  	} else if (strcmp(argv[1], "pmu-chained-counters") == 0) {
> >  		run_test(argv[1], test_chained_counters, false);
> >  	} else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) {
> > @@ -1131,6 +1159,7 @@ int main(int argc, char *argv[])
> >  		run_test(argv[1], test_chain_promotion, false);
> >  	} else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) {
> >  		run_test(argv[1], test_overflow_interrupt, false);
> > +		run_test(argv[1], test_overflow_interrupt, true);
> >  	} else {
> >  		report_abort("Unknown sub-test '%s'", argv[1]);
> >  	}
> > -- 
> > 2.39.0.rc0.267.gcb52ba06e7-goog
> > 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 3/3] arm: pmu: Add tests for 64-bit overflows
  2022-12-13 18:04       ` Ricardo Koller
@ 2022-12-14 10:45         ` Alexandru Elisei
  -1 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-14 10:45 UTC (permalink / raw)
  To: Ricardo Koller
  Cc: kvm, kvmarm, andrew.jones, maz, eric.auger, oliver.upton, reijiw

Hi,

On Tue, Dec 13, 2022 at 10:04:04AM -0800, Ricardo Koller wrote:
> On Tue, Dec 13, 2022 at 05:03:40PM +0000, Alexandru Elisei wrote:
> > Hi,
> > 
> > Checked that all places where ALL_SET/PRE_OVERFLOW were used are now taking
> > into account the fact that counters are programmed to be 64bit.
> > 
> > In the case of 64bit counters, the printf format specifier is %ld, which
> > means that ALL_SET_64 and PRE_OVERFLOW_64 are now displayed as negative
> > numbers. For example:
> > 
> > INFO: pmu: pmu-sw-incr: 32-bit: SW_INCR counter #0 has value 4294967280
> > PASS: pmu: pmu-sw-incr: 32-bit: PWSYNC does not increment if PMCR.E is unset
> > [..]
> > INFO: pmu: pmu-sw-incr: 64-bit: SW_INCR counter #0 has value -16
> > PASS: pmu: pmu-sw-incr: 64-bit: PWSYNC does not increment if PMCR.E is unset
> > 
> 
> Argh, I didn't notice this. I think this would be more useful if it
> printed %llx in all cases.

Indeed, printing the hex value will make it easier to match it against the
defines.

One more comment below.

> 
> > I was thinking that the format specifiers could be changed to unsigned
> > long.  The counters only increment, they don't decrement, and I can't think
> > how printing them as signed could be useful.
> > 
> > One more comment below.
> > 
> > On Fri, Dec 02, 2022 at 04:55:27AM +0000, Ricardo Koller wrote:
> > > Modify all tests checking overflows to support both 32 (PMCR_EL0.LP == 0)
> > > and 64-bit overflows (PMCR_EL0.LP == 1). 64-bit overflows are only
> > > supported on PMUv3p5.
> > > 
> > > Note that chained tests do not implement "overflow_at_64bits == true".
> > > That's because there are no CHAIN events when "PMCR_EL0.LP == 1" (for more
> > > details see AArch64.IncrementEventCounter() pseudocode in the ARM ARM DDI
> > > 0487H.a, J1.1.1 "aarch64/debug").
> > > 
> > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > ---
> > >  arm/pmu.c | 91 ++++++++++++++++++++++++++++++++++++-------------------
> > >  1 file changed, 60 insertions(+), 31 deletions(-)
> > > 
> > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > index 59e5bfe..3cb563b 100644
> > > --- a/arm/pmu.c
> > > +++ b/arm/pmu.c
> > > @@ -28,6 +28,7 @@
> > >  #define PMU_PMCR_X         (1 << 4)
> > >  #define PMU_PMCR_DP        (1 << 5)
> > >  #define PMU_PMCR_LC        (1 << 6)
> > > +#define PMU_PMCR_LP        (1 << 7)
> > >  #define PMU_PMCR_N_SHIFT   11
> > >  #define PMU_PMCR_N_MASK    0x1f
> > >  #define PMU_PMCR_ID_SHIFT  16
> > > @@ -55,10 +56,15 @@
> > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > >  
> > >  #define ALL_SET			0x00000000FFFFFFFFULL
> > > +#define ALL_SET_64		0xFFFFFFFFFFFFFFFFULL
> > >  #define ALL_CLEAR		0x0000000000000000ULL
> > >  #define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > +#define PRE_OVERFLOW_64		0xFFFFFFFFFFFFFFF0ULL
> > >  #define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > >  
> > > +#define PRE_OVERFLOW_AT(_64b)	(_64b ? PRE_OVERFLOW_64 : PRE_OVERFLOW)
> > > +#define ALL_SET_AT(_64b)	(_64b ? ALL_SET_64 : ALL_SET)
> > > +
> > >  #define PMU_PPI			23
> > >  
> > >  struct pmu {
> > > @@ -429,8 +435,10 @@ static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events,
> > >  static void test_basic_event_count(bool overflow_at_64bits)
> > >  {
> > >  	uint32_t implemented_counter_mask, non_implemented_counter_mask;
> > > -	uint32_t counter_mask;
> > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > >  	uint32_t events[] = {CPU_CYCLES, INST_RETIRED};
> > > +	uint32_t counter_mask;
> > >  
> > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> > >  				   overflow_at_64bits))
> > > @@ -452,13 +460,13 @@ static void test_basic_event_count(bool overflow_at_64bits)
> > >  	 * clear cycle and all event counters and allow counter enablement
> > >  	 * through PMCNTENSET. LC is RES1.
> > >  	 */
> > > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P);
> > > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P | pmcr_lp);
> > >  	isb();
> > > -	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC), "pmcr: reset counters");
> > > +	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC | pmcr_lp), "pmcr: reset counters");
> > >  
> > >  	/* Preset counter #0 to pre overflow value to trigger an overflow */
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
> > >  		"counter #0 preset to pre-overflow value");
> > >  	report(!read_regn_el0(pmevcntr, 1), "counter #1 is 0");
> > >  
> > > @@ -511,6 +519,8 @@ static void test_mem_access(bool overflow_at_64bits)
> > >  {
> > >  	void *addr = malloc(PAGE_SIZE);
> > >  	uint32_t events[] = {MEM_ACCESS, MEM_ACCESS};
> > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > >  
> > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> > >  				   overflow_at_64bits))
> > > @@ -522,7 +532,7 @@ static void test_mem_access(bool overflow_at_64bits)
> > >  	write_regn_el0(pmevtyper, 1, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
> > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > >  	isb();
> > > -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> > > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > >  	report_info("counter #0 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 0));
> > >  	report_info("counter #1 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 1));
> > >  	/* We may measure more than 20 mem access depending on the core */
> > > @@ -532,11 +542,11 @@ static void test_mem_access(bool overflow_at_64bits)
> > >  
> > >  	pmu_reset();
> > >  
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > >  	isb();
> > > -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> > > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > >  	report(read_sysreg(pmovsclr_el0) == 0x3,
> > >  	       "Ran 20 mem accesses with expected overflows on both counters");
> > >  	report_info("cnt#0 = %ld cnt#1=%ld overflow=0x%lx",
> > > @@ -546,6 +556,8 @@ static void test_mem_access(bool overflow_at_64bits)
> > >  
> > >  static void test_sw_incr(bool overflow_at_64bits)
> > >  {
> > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > >  	uint64_t cntr0;
> > >  	int i;
> > > @@ -561,7 +573,7 @@ static void test_sw_incr(bool overflow_at_64bits)
> > >  	/* enable counters #0 and #1 */
> > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > >  
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > >  	isb();
> > >  
> > >  	for (i = 0; i < 100; i++)
> > > @@ -569,21 +581,21 @@ static void test_sw_incr(bool overflow_at_64bits)
> > >  
> > >  	isb();
> > >  	report_info("SW_INCR counter #0 has value %ld", read_regn_el0(pmevcntr, 0));
> > > -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> > > +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
> > >  		"PWSYNC does not increment if PMCR.E is unset");
> > >  
> > >  	pmu_reset();
> > >  
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> > > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > >  	isb();
> > >  
> > >  	for (i = 0; i < 100; i++)
> > >  		write_sysreg(0x3, pmswinc_el0);
> > >  
> > >  	isb();
> > > -	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : pre_overflow + 100;
> > >  	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > >  	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> > >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > > @@ -844,6 +856,9 @@ static bool expect_interrupts(uint32_t bitmap)
> > >  
> > >  static void test_overflow_interrupt(bool overflow_at_64bits)
> > >  {
> > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > +	uint64_t all_set = ALL_SET_AT(overflow_at_64bits);
> > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > >  	uint32_t events[] = {MEM_ACCESS, SW_INCR};
> > >  	void *addr = malloc(PAGE_SIZE);
> > >  	int i;
> > > @@ -862,16 +877,16 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> > >  	write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
> > >  	write_regn_el0(pmevtyper, 1, SW_INCR | PMEVTYPER_EXCLUDE_EL0);
> > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> > >  	isb();
> > >  
> > >  	/* interrupts are disabled (PMINTENSET_EL1 == 0) */
> > >  
> > > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > >  	report(expect_interrupts(0), "no overflow interrupt after preset");
> > >  
> > > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> > > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > >  	isb();
> > >  
> > >  	for (i = 0; i < 100; i++)
> > > @@ -886,12 +901,12 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> > >  
> > >  	pmu_reset_stats();
> > >  
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> > >  	write_sysreg(ALL_SET, pmintenset_el1);
> > >  	isb();
> > >  
> > > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > > +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > >  	for (i = 0; i < 100; i++)
> > >  		write_sysreg(0x3, pmswinc_el0);
> > >  
> > > @@ -900,25 +915,35 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> > >  	report(expect_interrupts(0x3),
> > >  		"overflow interrupts expected on #0 and #1");
> > >  
> > > -	/* promote to 64-b */
> > > +	/*
> > > +	 * promote to 64-b:
> > > +	 *
> > > +	 * This only applies to the !overflow_at_64bits case, as
> > > +	 * overflow_at_64bits doesn't implement CHAIN events. The
> > > +	 * overflow_at_64bits case just checks that chained counters are
> > > +	 * not incremented when PMCR.LP == 1.
> > > +	 */
> > 
> > If this doesn't do anything for when overflow_at_64bits, and since the
> > interrupt is already tested before this part, why not exit early?
> > 
> > Or the test could check that the CHAIN event indeed does not increment when
> > LP=1 at the end of this function.
> 
> That's precisely what it's doing.

Where? Are you referring to this part?

	if (overflow_at_64bits)
		report(expect_interrupts(0x1),
		       "expect overflow interrupt on even counter");

My suggestion was to check that the counter that counts the CHAIN event
didn't increment (PMEVCNTR1_EL0 == all_set). I was thinking that since KVM
emulates the CHAIN event in software, it might be useful to check that the
final state of all registers is consistent. I'll leave it up to you to
decide if you want to add this extra check.

Thanks,
Alex

> 
> Thanks!
> Ricardo
> 
> > 
> > Thanks,
> > Alex
> > 
> > >  
> > >  	pmu_reset_stats();
> > >  
> > >  	write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0);
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > >  	isb();
> > > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > > -	report(expect_interrupts(0x1),
> > > -		"expect overflow interrupt on 32b boundary");
> > > +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > +	report(expect_interrupts(0x1), "expect overflow interrupt");
> > >  
> > >  	/* overflow on odd counter */
> > >  	pmu_reset_stats();
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > -	write_regn_el0(pmevcntr, 1, ALL_SET);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > +	write_regn_el0(pmevcntr, 1, all_set);
> > >  	isb();
> > > -	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E);
> > > -	report(expect_interrupts(0x3),
> > > -		"expect overflow interrupt on even and odd counter");
> > > +	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > +	if (overflow_at_64bits)
> > > +		report(expect_interrupts(0x1),
> > > +		       "expect overflow interrupt on even counter");
> > > +	else
> > > +		report(expect_interrupts(0x3),
> > > +		       "expect overflow interrupt on even and odd counter");
> > >  }
> > >  #endif
> > >  
> > > @@ -1119,10 +1144,13 @@ int main(int argc, char *argv[])
> > >  		report_prefix_pop();
> > >  	} else if (strcmp(argv[1], "pmu-basic-event-count") == 0) {
> > >  		run_test(argv[1], test_basic_event_count, false);
> > > +		run_test(argv[1], test_basic_event_count, true);
> > >  	} else if (strcmp(argv[1], "pmu-mem-access") == 0) {
> > >  		run_test(argv[1], test_mem_access, false);
> > > +		run_test(argv[1], test_mem_access, true);
> > >  	} else if (strcmp(argv[1], "pmu-sw-incr") == 0) {
> > >  		run_test(argv[1], test_sw_incr, false);
> > > +		run_test(argv[1], test_sw_incr, true);
> > >  	} else if (strcmp(argv[1], "pmu-chained-counters") == 0) {
> > >  		run_test(argv[1], test_chained_counters, false);
> > >  	} else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) {
> > > @@ -1131,6 +1159,7 @@ int main(int argc, char *argv[])
> > >  		run_test(argv[1], test_chain_promotion, false);
> > >  	} else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) {
> > >  		run_test(argv[1], test_overflow_interrupt, false);
> > > +		run_test(argv[1], test_overflow_interrupt, true);
> > >  	} else {
> > >  		report_abort("Unknown sub-test '%s'", argv[1]);
> > >  	}
> > > -- 
> > > 2.39.0.rc0.267.gcb52ba06e7-goog
> > > 

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

* Re: [kvm-unit-tests PATCH 3/3] arm: pmu: Add tests for 64-bit overflows
@ 2022-12-14 10:45         ` Alexandru Elisei
  0 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-14 10:45 UTC (permalink / raw)
  To: Ricardo Koller; +Cc: kvm, maz, andrew.jones, kvmarm

Hi,

On Tue, Dec 13, 2022 at 10:04:04AM -0800, Ricardo Koller wrote:
> On Tue, Dec 13, 2022 at 05:03:40PM +0000, Alexandru Elisei wrote:
> > Hi,
> > 
> > Checked that all places where ALL_SET/PRE_OVERFLOW were used are now taking
> > into account the fact that counters are programmed to be 64bit.
> > 
> > In the case of 64bit counters, the printf format specifier is %ld, which
> > means that ALL_SET_64 and PRE_OVERFLOW_64 are now displayed as negative
> > numbers. For example:
> > 
> > INFO: pmu: pmu-sw-incr: 32-bit: SW_INCR counter #0 has value 4294967280
> > PASS: pmu: pmu-sw-incr: 32-bit: PWSYNC does not increment if PMCR.E is unset
> > [..]
> > INFO: pmu: pmu-sw-incr: 64-bit: SW_INCR counter #0 has value -16
> > PASS: pmu: pmu-sw-incr: 64-bit: PWSYNC does not increment if PMCR.E is unset
> > 
> 
> Argh, I didn't notice this. I think this would be more useful if it
> printed %llx in all cases.

Indeed, printing the hex value will make it easier to match it against the
defines.

One more comment below.

> 
> > I was thinking that the format specifiers could be changed to unsigned
> > long.  The counters only increment, they don't decrement, and I can't think
> > how printing them as signed could be useful.
> > 
> > One more comment below.
> > 
> > On Fri, Dec 02, 2022 at 04:55:27AM +0000, Ricardo Koller wrote:
> > > Modify all tests checking overflows to support both 32 (PMCR_EL0.LP == 0)
> > > and 64-bit overflows (PMCR_EL0.LP == 1). 64-bit overflows are only
> > > supported on PMUv3p5.
> > > 
> > > Note that chained tests do not implement "overflow_at_64bits == true".
> > > That's because there are no CHAIN events when "PMCR_EL0.LP == 1" (for more
> > > details see AArch64.IncrementEventCounter() pseudocode in the ARM ARM DDI
> > > 0487H.a, J1.1.1 "aarch64/debug").
> > > 
> > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > ---
> > >  arm/pmu.c | 91 ++++++++++++++++++++++++++++++++++++-------------------
> > >  1 file changed, 60 insertions(+), 31 deletions(-)
> > > 
> > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > index 59e5bfe..3cb563b 100644
> > > --- a/arm/pmu.c
> > > +++ b/arm/pmu.c
> > > @@ -28,6 +28,7 @@
> > >  #define PMU_PMCR_X         (1 << 4)
> > >  #define PMU_PMCR_DP        (1 << 5)
> > >  #define PMU_PMCR_LC        (1 << 6)
> > > +#define PMU_PMCR_LP        (1 << 7)
> > >  #define PMU_PMCR_N_SHIFT   11
> > >  #define PMU_PMCR_N_MASK    0x1f
> > >  #define PMU_PMCR_ID_SHIFT  16
> > > @@ -55,10 +56,15 @@
> > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > >  
> > >  #define ALL_SET			0x00000000FFFFFFFFULL
> > > +#define ALL_SET_64		0xFFFFFFFFFFFFFFFFULL
> > >  #define ALL_CLEAR		0x0000000000000000ULL
> > >  #define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > +#define PRE_OVERFLOW_64		0xFFFFFFFFFFFFFFF0ULL
> > >  #define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > >  
> > > +#define PRE_OVERFLOW_AT(_64b)	(_64b ? PRE_OVERFLOW_64 : PRE_OVERFLOW)
> > > +#define ALL_SET_AT(_64b)	(_64b ? ALL_SET_64 : ALL_SET)
> > > +
> > >  #define PMU_PPI			23
> > >  
> > >  struct pmu {
> > > @@ -429,8 +435,10 @@ static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events,
> > >  static void test_basic_event_count(bool overflow_at_64bits)
> > >  {
> > >  	uint32_t implemented_counter_mask, non_implemented_counter_mask;
> > > -	uint32_t counter_mask;
> > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > >  	uint32_t events[] = {CPU_CYCLES, INST_RETIRED};
> > > +	uint32_t counter_mask;
> > >  
> > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> > >  				   overflow_at_64bits))
> > > @@ -452,13 +460,13 @@ static void test_basic_event_count(bool overflow_at_64bits)
> > >  	 * clear cycle and all event counters and allow counter enablement
> > >  	 * through PMCNTENSET. LC is RES1.
> > >  	 */
> > > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P);
> > > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P | pmcr_lp);
> > >  	isb();
> > > -	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC), "pmcr: reset counters");
> > > +	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC | pmcr_lp), "pmcr: reset counters");
> > >  
> > >  	/* Preset counter #0 to pre overflow value to trigger an overflow */
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
> > >  		"counter #0 preset to pre-overflow value");
> > >  	report(!read_regn_el0(pmevcntr, 1), "counter #1 is 0");
> > >  
> > > @@ -511,6 +519,8 @@ static void test_mem_access(bool overflow_at_64bits)
> > >  {
> > >  	void *addr = malloc(PAGE_SIZE);
> > >  	uint32_t events[] = {MEM_ACCESS, MEM_ACCESS};
> > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > >  
> > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> > >  				   overflow_at_64bits))
> > > @@ -522,7 +532,7 @@ static void test_mem_access(bool overflow_at_64bits)
> > >  	write_regn_el0(pmevtyper, 1, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
> > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > >  	isb();
> > > -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> > > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > >  	report_info("counter #0 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 0));
> > >  	report_info("counter #1 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 1));
> > >  	/* We may measure more than 20 mem access depending on the core */
> > > @@ -532,11 +542,11 @@ static void test_mem_access(bool overflow_at_64bits)
> > >  
> > >  	pmu_reset();
> > >  
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > >  	isb();
> > > -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> > > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > >  	report(read_sysreg(pmovsclr_el0) == 0x3,
> > >  	       "Ran 20 mem accesses with expected overflows on both counters");
> > >  	report_info("cnt#0 = %ld cnt#1=%ld overflow=0x%lx",
> > > @@ -546,6 +556,8 @@ static void test_mem_access(bool overflow_at_64bits)
> > >  
> > >  static void test_sw_incr(bool overflow_at_64bits)
> > >  {
> > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > >  	uint64_t cntr0;
> > >  	int i;
> > > @@ -561,7 +573,7 @@ static void test_sw_incr(bool overflow_at_64bits)
> > >  	/* enable counters #0 and #1 */
> > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > >  
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > >  	isb();
> > >  
> > >  	for (i = 0; i < 100; i++)
> > > @@ -569,21 +581,21 @@ static void test_sw_incr(bool overflow_at_64bits)
> > >  
> > >  	isb();
> > >  	report_info("SW_INCR counter #0 has value %ld", read_regn_el0(pmevcntr, 0));
> > > -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> > > +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
> > >  		"PWSYNC does not increment if PMCR.E is unset");
> > >  
> > >  	pmu_reset();
> > >  
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> > > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > >  	isb();
> > >  
> > >  	for (i = 0; i < 100; i++)
> > >  		write_sysreg(0x3, pmswinc_el0);
> > >  
> > >  	isb();
> > > -	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : pre_overflow + 100;
> > >  	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > >  	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> > >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > > @@ -844,6 +856,9 @@ static bool expect_interrupts(uint32_t bitmap)
> > >  
> > >  static void test_overflow_interrupt(bool overflow_at_64bits)
> > >  {
> > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > +	uint64_t all_set = ALL_SET_AT(overflow_at_64bits);
> > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > >  	uint32_t events[] = {MEM_ACCESS, SW_INCR};
> > >  	void *addr = malloc(PAGE_SIZE);
> > >  	int i;
> > > @@ -862,16 +877,16 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> > >  	write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
> > >  	write_regn_el0(pmevtyper, 1, SW_INCR | PMEVTYPER_EXCLUDE_EL0);
> > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> > >  	isb();
> > >  
> > >  	/* interrupts are disabled (PMINTENSET_EL1 == 0) */
> > >  
> > > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > >  	report(expect_interrupts(0), "no overflow interrupt after preset");
> > >  
> > > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> > > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > >  	isb();
> > >  
> > >  	for (i = 0; i < 100; i++)
> > > @@ -886,12 +901,12 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> > >  
> > >  	pmu_reset_stats();
> > >  
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> > >  	write_sysreg(ALL_SET, pmintenset_el1);
> > >  	isb();
> > >  
> > > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > > +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > >  	for (i = 0; i < 100; i++)
> > >  		write_sysreg(0x3, pmswinc_el0);
> > >  
> > > @@ -900,25 +915,35 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> > >  	report(expect_interrupts(0x3),
> > >  		"overflow interrupts expected on #0 and #1");
> > >  
> > > -	/* promote to 64-b */
> > > +	/*
> > > +	 * promote to 64-b:
> > > +	 *
> > > +	 * This only applies to the !overflow_at_64bits case, as
> > > +	 * overflow_at_64bits doesn't implement CHAIN events. The
> > > +	 * overflow_at_64bits case just checks that chained counters are
> > > +	 * not incremented when PMCR.LP == 1.
> > > +	 */
> > 
> > If this doesn't do anything for when overflow_at_64bits, and since the
> > interrupt is already tested before this part, why not exit early?
> > 
> > Or the test could check that the CHAIN event indeed does not increment when
> > LP=1 at the end of this function.
> 
> That's precisely what it's doing.

Where? Are you referring to this part?

	if (overflow_at_64bits)
		report(expect_interrupts(0x1),
		       "expect overflow interrupt on even counter");

My suggestion was to check that the counter that counts the CHAIN event
didn't increment (PMEVCNTR1_EL0 == all_set). I was thinking that since KVM
emulates the CHAIN event in software, it might be useful to check that the
final state of all registers is consistent. I'll leave it up to you to
decide if you want to add this extra check.

Thanks,
Alex

> 
> Thanks!
> Ricardo
> 
> > 
> > Thanks,
> > Alex
> > 
> > >  
> > >  	pmu_reset_stats();
> > >  
> > >  	write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0);
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > >  	isb();
> > > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > > -	report(expect_interrupts(0x1),
> > > -		"expect overflow interrupt on 32b boundary");
> > > +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > +	report(expect_interrupts(0x1), "expect overflow interrupt");
> > >  
> > >  	/* overflow on odd counter */
> > >  	pmu_reset_stats();
> > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > -	write_regn_el0(pmevcntr, 1, ALL_SET);
> > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > +	write_regn_el0(pmevcntr, 1, all_set);
> > >  	isb();
> > > -	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E);
> > > -	report(expect_interrupts(0x3),
> > > -		"expect overflow interrupt on even and odd counter");
> > > +	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > +	if (overflow_at_64bits)
> > > +		report(expect_interrupts(0x1),
> > > +		       "expect overflow interrupt on even counter");
> > > +	else
> > > +		report(expect_interrupts(0x3),
> > > +		       "expect overflow interrupt on even and odd counter");
> > >  }
> > >  #endif
> > >  
> > > @@ -1119,10 +1144,13 @@ int main(int argc, char *argv[])
> > >  		report_prefix_pop();
> > >  	} else if (strcmp(argv[1], "pmu-basic-event-count") == 0) {
> > >  		run_test(argv[1], test_basic_event_count, false);
> > > +		run_test(argv[1], test_basic_event_count, true);
> > >  	} else if (strcmp(argv[1], "pmu-mem-access") == 0) {
> > >  		run_test(argv[1], test_mem_access, false);
> > > +		run_test(argv[1], test_mem_access, true);
> > >  	} else if (strcmp(argv[1], "pmu-sw-incr") == 0) {
> > >  		run_test(argv[1], test_sw_incr, false);
> > > +		run_test(argv[1], test_sw_incr, true);
> > >  	} else if (strcmp(argv[1], "pmu-chained-counters") == 0) {
> > >  		run_test(argv[1], test_chained_counters, false);
> > >  	} else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) {
> > > @@ -1131,6 +1159,7 @@ int main(int argc, char *argv[])
> > >  		run_test(argv[1], test_chain_promotion, false);
> > >  	} else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) {
> > >  		run_test(argv[1], test_overflow_interrupt, false);
> > > +		run_test(argv[1], test_overflow_interrupt, true);
> > >  	} else {
> > >  		report_abort("Unknown sub-test '%s'", argv[1]);
> > >  	}
> > > -- 
> > > 2.39.0.rc0.267.gcb52ba06e7-goog
> > > 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-13 18:01           ` Ricardo Koller
@ 2022-12-14 10:46             ` Alexandru Elisei
  -1 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-14 10:46 UTC (permalink / raw)
  To: Ricardo Koller
  Cc: kvm, kvmarm, andrew.jones, maz, eric.auger, oliver.upton, reijiw

Hi,

On Tue, Dec 13, 2022 at 10:01:06AM -0800, Ricardo Koller wrote:
> On Tue, Dec 13, 2022 at 04:43:38PM +0000, Alexandru Elisei wrote:
> > Hi,
> > 
> > On Tue, Dec 13, 2022 at 08:21:24AM -0800, Ricardo Koller wrote:
> > > On Tue, Dec 13, 2022 at 12:36:14PM +0000, Alexandru Elisei wrote:
> > > > Hi,
> > > > 
> > > > Some more comments below.
> > > > 
> > > > On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > > > > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > > > > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > > > > the counter values after overflowing should not assume that values will be
> > > > > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > > > > counters on PMUv3p5.
> > > > > 
> > > > > Fix tests by correctly checking overflowing-counters against the expected
> > > > > 64-bit value.
> > > > > 
> > > > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > > > ---
> > > > >  arm/pmu.c | 29 ++++++++++++++++++-----------
> > > > >  1 file changed, 18 insertions(+), 11 deletions(-)
> > > > > 
> > > > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > > > index cd47b14..eeac984 100644
> > > > > --- a/arm/pmu.c
> > > > > +++ b/arm/pmu.c
> > > > > @@ -54,10 +54,10 @@
> > > > >  #define EXT_COMMON_EVENTS_LOW	0x4000
> > > > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > > > >  
> > > > > -#define ALL_SET			0xFFFFFFFF
> > > > > -#define ALL_CLEAR		0x0
> > > > > -#define PRE_OVERFLOW		0xFFFFFFF0
> > > > > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > > > > +#define ALL_SET			0x00000000FFFFFFFFULL
> > > > > +#define ALL_CLEAR		0x0000000000000000ULL
> > > > > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > > > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > > > >  
> > > > >  #define PMU_PPI			23
> > > > >  
> > > > > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> > > > >  static void test_sw_incr(void)
> > > > >  {
> > > > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > > > > +	uint64_t cntr0;
> > > > >  	int i;
> > > > >  
> > > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> > > > >  		write_sysreg(0x3, pmswinc_el0);
> > > > >  
> > > > >  	isb();
> > > > > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > > > > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > > > > -		"counter #0 after + 100 SW_INCR");
> > > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > > > +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > > > > +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> > > > >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > > > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > > > >  	report(read_sysreg(pmovsclr_el0) == 0x1,
> > > > > @@ -584,6 +585,7 @@ static void test_sw_incr(void)
> > > > >  static void test_chained_counters(void)
> > > > >  {
> > > > >  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> > > > > +	uint64_t cntr1;
> > > > >  
> > > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > >  		return;
> > > > > @@ -618,13 +620,16 @@ static void test_chained_counters(void)
> > > > >  
> > > > >  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> > > > >  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > > > > -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> > > > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > > > +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > > > 
> > > > It looks to me like the intention of the test was to check that the counter
> > > > programmed with the CHAIN event wraps, judging from the report message.
> > > > 
> > > 
> > > Ah, right. Yeah, that message is confusing. It should be the short
> > > version of "Inrementing at 32-bits resulted in the right value".
> > > 
> > > > I think it would be interesting to keep that by programming counter #1 with
> > > > ~0ULL when PMUv3p5 (maybe call it ALL_SET64?) and test the counter value
> > > > against 0.
> > > 
> > > The last commit adds tests using ALL_SET64.  Tests can be run in two
> > > modes: overflow_at_64bits and not.  However, this test,
> > > test_chained_counters(), and all other chained tests only use the
> > > !overflow_at_64bits mode (even after the last commit). The reason is
> > > that there are no CHAIN events when overflowing at 64-bits (more details
> > > in the commit message). But, don't worry, there are lots of tests that
> > > check wrapping at 64-bits (overflow_at_64bits=true).
> > 
> > What I was suggesting is this (change on top of this series, not on top of
> > this patch, to get access to ALL_SET_AT):
> 
> Ooh, I see, I agree: it would be better to check that the odd counter
> increments from ~0ULL to 0 when using 64-bit counters.
> 
> > 
> > diff --git a/arm/pmu.c b/arm/pmu.c
> > index 3cb563b1abe4..fd7f20fc6c52 100644
> > --- a/arm/pmu.c
> > +++ b/arm/pmu.c
> > @@ -607,7 +607,6 @@ static void test_sw_incr(bool overflow_at_64bits)
> >  static void test_chained_counters(bool overflow_at_64bits)
> >  {
> >         uint32_t events[] = {CPU_CYCLES, CHAIN};
> > -       uint64_t cntr1;
> > 
> >         if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> >                                    overflow_at_64bits))
> > @@ -639,12 +638,11 @@ static void test_chained_counters(bool overflow_at_64bits)
> >         report(read_sysreg(pmovsclr_el0) == 0x1, "overflow recorded for chained incr #2");
> > 
> >         write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > -       write_regn_el0(pmevcntr, 1, ALL_SET);
> > +       write_regn_el0(pmevcntr, 1, ALL_SET_AT(overflow_at_64bits));
> 
> The only change is that this should be:
> 
> 	ALL_SET_AT(pmu.version >= ID_DFR0_PMU_V3_8_5)
> 
> Because "overflow_at_64bits" implies PMCR_EL0.LP = 1.

Right, and test_chained_counters() is never called with overflow_at_64bits
== true.

How about renaming the parameter overflow_at_64bits -> unused (or something
like that) to make it clear that the function does the same thing
regardless of the value?

Thanks,
Alex

> 
> > 
> >         precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> >         report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > -       cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > -       report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > +       report(read_regn_el0(pmevcntr, 1) == 0, "CHAIN counter #1 wrapped");
> > 
> >         report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> >  }
> > 
> > The counters are 64bit, but the CHAIN event should still work because
> > PMCR_EL0.LP is 0, according to the event description in the Arm ARM (ARM
> > DDI 0487I.a, page D17-6461).
> > 
> > Thanks,
> > Alex
> > 
> > > 
> > > > Alternatively, the report message can be modified, and "wrapped"
> > > > replaced with "incremented" (or something like that), to avoid confusion.
> > > > 
> > > > > +
> > > > >  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> > > > >  }
> > > > >  
> > > > >  static void test_chained_sw_incr(void)
> > > > >  {
> > > > >  	uint32_t events[] = {SW_INCR, CHAIN};
> > > > > +	uint64_t cntr0, cntr1;
> > > > >  	int i;
> > > > >  
> > > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > > @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
> > > > >  		write_sysreg(0x1, pmswinc_el0);
> > > > >  
> > > > >  	isb();
> > > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > > >  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> > > > > -		(read_regn_el0(pmevcntr, 1) == 0) &&
> > > > > -		(read_regn_el0(pmevcntr, 0) == 84),
> > > > > -		"expected overflows and values after 100 SW_INCR/CHAIN");
> > > > > +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> > > > > +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> > > > 
> > > > This is hard to parse, it would be better if counter 0 is compared against
> > > > cntr0 and counter 1 against cntr1.
> > > 
> > > Ah, yes, code is correct but that's indeed confusing.
> > > 
> > > > 
> > > > Also, same suggestion here, looks like the test wants to check that the
> > > > odd-numbered counter wraps around when counting the CHAIN event.
> > > 
> > > Ack. Will update for v2.
> > > 
> > > Thanks!
> > > Ricardo
> > > 
> > > > 
> > > > Thanks,
> > > > Alex
> > > > 
> > > > > +	       "expected overflows and values after 100 SW_INCR/CHAIN");
> > > > >  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
> > > > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > > > >  }
> > > > > -- 
> > > > > 2.39.0.rc0.267.gcb52ba06e7-goog
> > > > > 

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-14 10:46             ` Alexandru Elisei
  0 siblings, 0 replies; 40+ messages in thread
From: Alexandru Elisei @ 2022-12-14 10:46 UTC (permalink / raw)
  To: Ricardo Koller; +Cc: kvm, maz, andrew.jones, kvmarm

Hi,

On Tue, Dec 13, 2022 at 10:01:06AM -0800, Ricardo Koller wrote:
> On Tue, Dec 13, 2022 at 04:43:38PM +0000, Alexandru Elisei wrote:
> > Hi,
> > 
> > On Tue, Dec 13, 2022 at 08:21:24AM -0800, Ricardo Koller wrote:
> > > On Tue, Dec 13, 2022 at 12:36:14PM +0000, Alexandru Elisei wrote:
> > > > Hi,
> > > > 
> > > > Some more comments below.
> > > > 
> > > > On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > > > > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > > > > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > > > > the counter values after overflowing should not assume that values will be
> > > > > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > > > > counters on PMUv3p5.
> > > > > 
> > > > > Fix tests by correctly checking overflowing-counters against the expected
> > > > > 64-bit value.
> > > > > 
> > > > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > > > ---
> > > > >  arm/pmu.c | 29 ++++++++++++++++++-----------
> > > > >  1 file changed, 18 insertions(+), 11 deletions(-)
> > > > > 
> > > > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > > > index cd47b14..eeac984 100644
> > > > > --- a/arm/pmu.c
> > > > > +++ b/arm/pmu.c
> > > > > @@ -54,10 +54,10 @@
> > > > >  #define EXT_COMMON_EVENTS_LOW	0x4000
> > > > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > > > >  
> > > > > -#define ALL_SET			0xFFFFFFFF
> > > > > -#define ALL_CLEAR		0x0
> > > > > -#define PRE_OVERFLOW		0xFFFFFFF0
> > > > > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > > > > +#define ALL_SET			0x00000000FFFFFFFFULL
> > > > > +#define ALL_CLEAR		0x0000000000000000ULL
> > > > > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > > > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > > > >  
> > > > >  #define PMU_PPI			23
> > > > >  
> > > > > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> > > > >  static void test_sw_incr(void)
> > > > >  {
> > > > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > > > > +	uint64_t cntr0;
> > > > >  	int i;
> > > > >  
> > > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> > > > >  		write_sysreg(0x3, pmswinc_el0);
> > > > >  
> > > > >  	isb();
> > > > > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > > > > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > > > > -		"counter #0 after + 100 SW_INCR");
> > > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > > > +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > > > > +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> > > > >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > > > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > > > >  	report(read_sysreg(pmovsclr_el0) == 0x1,
> > > > > @@ -584,6 +585,7 @@ static void test_sw_incr(void)
> > > > >  static void test_chained_counters(void)
> > > > >  {
> > > > >  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> > > > > +	uint64_t cntr1;
> > > > >  
> > > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > >  		return;
> > > > > @@ -618,13 +620,16 @@ static void test_chained_counters(void)
> > > > >  
> > > > >  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> > > > >  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > > > > -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> > > > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > > > +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > > > 
> > > > It looks to me like the intention of the test was to check that the counter
> > > > programmed with the CHAIN event wraps, judging from the report message.
> > > > 
> > > 
> > > Ah, right. Yeah, that message is confusing. It should be the short
> > > version of "Inrementing at 32-bits resulted in the right value".
> > > 
> > > > I think it would be interesting to keep that by programming counter #1 with
> > > > ~0ULL when PMUv3p5 (maybe call it ALL_SET64?) and test the counter value
> > > > against 0.
> > > 
> > > The last commit adds tests using ALL_SET64.  Tests can be run in two
> > > modes: overflow_at_64bits and not.  However, this test,
> > > test_chained_counters(), and all other chained tests only use the
> > > !overflow_at_64bits mode (even after the last commit). The reason is
> > > that there are no CHAIN events when overflowing at 64-bits (more details
> > > in the commit message). But, don't worry, there are lots of tests that
> > > check wrapping at 64-bits (overflow_at_64bits=true).
> > 
> > What I was suggesting is this (change on top of this series, not on top of
> > this patch, to get access to ALL_SET_AT):
> 
> Ooh, I see, I agree: it would be better to check that the odd counter
> increments from ~0ULL to 0 when using 64-bit counters.
> 
> > 
> > diff --git a/arm/pmu.c b/arm/pmu.c
> > index 3cb563b1abe4..fd7f20fc6c52 100644
> > --- a/arm/pmu.c
> > +++ b/arm/pmu.c
> > @@ -607,7 +607,6 @@ static void test_sw_incr(bool overflow_at_64bits)
> >  static void test_chained_counters(bool overflow_at_64bits)
> >  {
> >         uint32_t events[] = {CPU_CYCLES, CHAIN};
> > -       uint64_t cntr1;
> > 
> >         if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> >                                    overflow_at_64bits))
> > @@ -639,12 +638,11 @@ static void test_chained_counters(bool overflow_at_64bits)
> >         report(read_sysreg(pmovsclr_el0) == 0x1, "overflow recorded for chained incr #2");
> > 
> >         write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > -       write_regn_el0(pmevcntr, 1, ALL_SET);
> > +       write_regn_el0(pmevcntr, 1, ALL_SET_AT(overflow_at_64bits));
> 
> The only change is that this should be:
> 
> 	ALL_SET_AT(pmu.version >= ID_DFR0_PMU_V3_8_5)
> 
> Because "overflow_at_64bits" implies PMCR_EL0.LP = 1.

Right, and test_chained_counters() is never called with overflow_at_64bits
== true.

How about renaming the parameter overflow_at_64bits -> unused (or something
like that) to make it clear that the function does the same thing
regardless of the value?

Thanks,
Alex

> 
> > 
> >         precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> >         report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > -       cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > -       report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > +       report(read_regn_el0(pmevcntr, 1) == 0, "CHAIN counter #1 wrapped");
> > 
> >         report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> >  }
> > 
> > The counters are 64bit, but the CHAIN event should still work because
> > PMCR_EL0.LP is 0, according to the event description in the Arm ARM (ARM
> > DDI 0487I.a, page D17-6461).
> > 
> > Thanks,
> > Alex
> > 
> > > 
> > > > Alternatively, the report message can be modified, and "wrapped"
> > > > replaced with "incremented" (or something like that), to avoid confusion.
> > > > 
> > > > > +
> > > > >  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> > > > >  }
> > > > >  
> > > > >  static void test_chained_sw_incr(void)
> > > > >  {
> > > > >  	uint32_t events[] = {SW_INCR, CHAIN};
> > > > > +	uint64_t cntr0, cntr1;
> > > > >  	int i;
> > > > >  
> > > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > > @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
> > > > >  		write_sysreg(0x1, pmswinc_el0);
> > > > >  
> > > > >  	isb();
> > > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > > >  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> > > > > -		(read_regn_el0(pmevcntr, 1) == 0) &&
> > > > > -		(read_regn_el0(pmevcntr, 0) == 84),
> > > > > -		"expected overflows and values after 100 SW_INCR/CHAIN");
> > > > > +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> > > > > +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> > > > 
> > > > This is hard to parse, it would be better if counter 0 is compared against
> > > > cntr0 and counter 1 against cntr1.
> > > 
> > > Ah, yes, code is correct but that's indeed confusing.
> > > 
> > > > 
> > > > Also, same suggestion here, looks like the test wants to check that the
> > > > odd-numbered counter wraps around when counting the CHAIN event.
> > > 
> > > Ack. Will update for v2.
> > > 
> > > Thanks!
> > > Ricardo
> > > 
> > > > 
> > > > Thanks,
> > > > Alex
> > > > 
> > > > > +	       "expected overflows and values after 100 SW_INCR/CHAIN");
> > > > >  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
> > > > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > > > >  }
> > > > > -- 
> > > > > 2.39.0.rc0.267.gcb52ba06e7-goog
> > > > > 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
  2022-12-14 10:46             ` Alexandru Elisei
@ 2022-12-14 18:07               ` Ricardo Koller
  -1 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-14 18:07 UTC (permalink / raw)
  To: Alexandru Elisei; +Cc: kvm, maz, andrew.jones, kvmarm

On Wed, Dec 14, 2022 at 10:46:05AM +0000, Alexandru Elisei wrote:
> Hi,
> 
> On Tue, Dec 13, 2022 at 10:01:06AM -0800, Ricardo Koller wrote:
> > On Tue, Dec 13, 2022 at 04:43:38PM +0000, Alexandru Elisei wrote:
> > > Hi,
> > > 
> > > On Tue, Dec 13, 2022 at 08:21:24AM -0800, Ricardo Koller wrote:
> > > > On Tue, Dec 13, 2022 at 12:36:14PM +0000, Alexandru Elisei wrote:
> > > > > Hi,
> > > > > 
> > > > > Some more comments below.
> > > > > 
> > > > > On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > > > > > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > > > > > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > > > > > the counter values after overflowing should not assume that values will be
> > > > > > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > > > > > counters on PMUv3p5.
> > > > > > 
> > > > > > Fix tests by correctly checking overflowing-counters against the expected
> > > > > > 64-bit value.
> > > > > > 
> > > > > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > > > > ---
> > > > > >  arm/pmu.c | 29 ++++++++++++++++++-----------
> > > > > >  1 file changed, 18 insertions(+), 11 deletions(-)
> > > > > > 
> > > > > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > > > > index cd47b14..eeac984 100644
> > > > > > --- a/arm/pmu.c
> > > > > > +++ b/arm/pmu.c
> > > > > > @@ -54,10 +54,10 @@
> > > > > >  #define EXT_COMMON_EVENTS_LOW	0x4000
> > > > > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > > > > >  
> > > > > > -#define ALL_SET			0xFFFFFFFF
> > > > > > -#define ALL_CLEAR		0x0
> > > > > > -#define PRE_OVERFLOW		0xFFFFFFF0
> > > > > > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > > > > > +#define ALL_SET			0x00000000FFFFFFFFULL
> > > > > > +#define ALL_CLEAR		0x0000000000000000ULL
> > > > > > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > > > > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > > > > >  
> > > > > >  #define PMU_PPI			23
> > > > > >  
> > > > > > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> > > > > >  static void test_sw_incr(void)
> > > > > >  {
> > > > > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > > > > > +	uint64_t cntr0;
> > > > > >  	int i;
> > > > > >  
> > > > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > > > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> > > > > >  		write_sysreg(0x3, pmswinc_el0);
> > > > > >  
> > > > > >  	isb();
> > > > > > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > > > > > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > > > > > -		"counter #0 after + 100 SW_INCR");
> > > > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > > > > +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > > > > > +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> > > > > >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > > > > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > > > > >  	report(read_sysreg(pmovsclr_el0) == 0x1,
> > > > > > @@ -584,6 +585,7 @@ static void test_sw_incr(void)
> > > > > >  static void test_chained_counters(void)
> > > > > >  {
> > > > > >  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> > > > > > +	uint64_t cntr1;
> > > > > >  
> > > > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > > >  		return;
> > > > > > @@ -618,13 +620,16 @@ static void test_chained_counters(void)
> > > > > >  
> > > > > >  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> > > > > >  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > > > > > -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> > > > > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > > > > +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > > > > 
> > > > > It looks to me like the intention of the test was to check that the counter
> > > > > programmed with the CHAIN event wraps, judging from the report message.
> > > > > 
> > > > 
> > > > Ah, right. Yeah, that message is confusing. It should be the short
> > > > version of "Inrementing at 32-bits resulted in the right value".
> > > > 
> > > > > I think it would be interesting to keep that by programming counter #1 with
> > > > > ~0ULL when PMUv3p5 (maybe call it ALL_SET64?) and test the counter value
> > > > > against 0.
> > > > 
> > > > The last commit adds tests using ALL_SET64.  Tests can be run in two
> > > > modes: overflow_at_64bits and not.  However, this test,
> > > > test_chained_counters(), and all other chained tests only use the
> > > > !overflow_at_64bits mode (even after the last commit). The reason is
> > > > that there are no CHAIN events when overflowing at 64-bits (more details
> > > > in the commit message). But, don't worry, there are lots of tests that
> > > > check wrapping at 64-bits (overflow_at_64bits=true).
> > > 
> > > What I was suggesting is this (change on top of this series, not on top of
> > > this patch, to get access to ALL_SET_AT):
> > 
> > Ooh, I see, I agree: it would be better to check that the odd counter
> > increments from ~0ULL to 0 when using 64-bit counters.
> > 
> > > 
> > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > index 3cb563b1abe4..fd7f20fc6c52 100644
> > > --- a/arm/pmu.c
> > > +++ b/arm/pmu.c
> > > @@ -607,7 +607,6 @@ static void test_sw_incr(bool overflow_at_64bits)
> > >  static void test_chained_counters(bool overflow_at_64bits)
> > >  {
> > >         uint32_t events[] = {CPU_CYCLES, CHAIN};
> > > -       uint64_t cntr1;
> > > 
> > >         if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> > >                                    overflow_at_64bits))
> > > @@ -639,12 +638,11 @@ static void test_chained_counters(bool overflow_at_64bits)
> > >         report(read_sysreg(pmovsclr_el0) == 0x1, "overflow recorded for chained incr #2");
> > > 
> > >         write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > -       write_regn_el0(pmevcntr, 1, ALL_SET);
> > > +       write_regn_el0(pmevcntr, 1, ALL_SET_AT(overflow_at_64bits));
> > 
> > The only change is that this should be:
> > 
> > 	ALL_SET_AT(pmu.version >= ID_DFR0_PMU_V3_8_5)
> > 
> > Because "overflow_at_64bits" implies PMCR_EL0.LP = 1.
> 
> Right, and test_chained_counters() is never called with overflow_at_64bits
> == true.
> 
> How about renaming the parameter overflow_at_64bits -> unused (or something
> like that) to make it clear that the function does the same thing
> regardless of the value?

Sounds good, will do for v2.

> 
> Thanks,
> Alex
> 
> > 
> > > 
> > >         precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> > >         report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > > -       cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > -       report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > > +       report(read_regn_el0(pmevcntr, 1) == 0, "CHAIN counter #1 wrapped");
> > > 
> > >         report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> > >  }
> > > 
> > > The counters are 64bit, but the CHAIN event should still work because
> > > PMCR_EL0.LP is 0, according to the event description in the Arm ARM (ARM
> > > DDI 0487I.a, page D17-6461).
> > > 
> > > Thanks,
> > > Alex
> > > 
> > > > 
> > > > > Alternatively, the report message can be modified, and "wrapped"
> > > > > replaced with "incremented" (or something like that), to avoid confusion.
> > > > > 
> > > > > > +
> > > > > >  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> > > > > >  }
> > > > > >  
> > > > > >  static void test_chained_sw_incr(void)
> > > > > >  {
> > > > > >  	uint32_t events[] = {SW_INCR, CHAIN};
> > > > > > +	uint64_t cntr0, cntr1;
> > > > > >  	int i;
> > > > > >  
> > > > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > > > @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
> > > > > >  		write_sysreg(0x1, pmswinc_el0);
> > > > > >  
> > > > > >  	isb();
> > > > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > > > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > > > >  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> > > > > > -		(read_regn_el0(pmevcntr, 1) == 0) &&
> > > > > > -		(read_regn_el0(pmevcntr, 0) == 84),
> > > > > > -		"expected overflows and values after 100 SW_INCR/CHAIN");
> > > > > > +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> > > > > > +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> > > > > 
> > > > > This is hard to parse, it would be better if counter 0 is compared against
> > > > > cntr0 and counter 1 against cntr1.
> > > > 
> > > > Ah, yes, code is correct but that's indeed confusing.
> > > > 
> > > > > 
> > > > > Also, same suggestion here, looks like the test wants to check that the
> > > > > odd-numbered counter wraps around when counting the CHAIN event.
> > > > 
> > > > Ack. Will update for v2.
> > > > 
> > > > Thanks!
> > > > Ricardo
> > > > 
> > > > > 
> > > > > Thanks,
> > > > > Alex
> > > > > 
> > > > > > +	       "expected overflows and values after 100 SW_INCR/CHAIN");
> > > > > >  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
> > > > > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > > > > >  }
> > > > > > -- 
> > > > > > 2.39.0.rc0.267.gcb52ba06e7-goog
> > > > > > 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters
@ 2022-12-14 18:07               ` Ricardo Koller
  0 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-14 18:07 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: kvm, kvmarm, andrew.jones, maz, eric.auger, oliver.upton, reijiw

On Wed, Dec 14, 2022 at 10:46:05AM +0000, Alexandru Elisei wrote:
> Hi,
> 
> On Tue, Dec 13, 2022 at 10:01:06AM -0800, Ricardo Koller wrote:
> > On Tue, Dec 13, 2022 at 04:43:38PM +0000, Alexandru Elisei wrote:
> > > Hi,
> > > 
> > > On Tue, Dec 13, 2022 at 08:21:24AM -0800, Ricardo Koller wrote:
> > > > On Tue, Dec 13, 2022 at 12:36:14PM +0000, Alexandru Elisei wrote:
> > > > > Hi,
> > > > > 
> > > > > Some more comments below.
> > > > > 
> > > > > On Fri, Dec 02, 2022 at 04:55:25AM +0000, Ricardo Koller wrote:
> > > > > > PMUv3p5 uses 64-bit counters irrespective of whether the PMU is configured
> > > > > > for overflowing at 32 or 64-bits. The consequence is that tests that check
> > > > > > the counter values after overflowing should not assume that values will be
> > > > > > wrapped around 32-bits: they overflow into the other half of the 64-bit
> > > > > > counters on PMUv3p5.
> > > > > > 
> > > > > > Fix tests by correctly checking overflowing-counters against the expected
> > > > > > 64-bit value.
> > > > > > 
> > > > > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > > > > ---
> > > > > >  arm/pmu.c | 29 ++++++++++++++++++-----------
> > > > > >  1 file changed, 18 insertions(+), 11 deletions(-)
> > > > > > 
> > > > > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > > > > index cd47b14..eeac984 100644
> > > > > > --- a/arm/pmu.c
> > > > > > +++ b/arm/pmu.c
> > > > > > @@ -54,10 +54,10 @@
> > > > > >  #define EXT_COMMON_EVENTS_LOW	0x4000
> > > > > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > > > > >  
> > > > > > -#define ALL_SET			0xFFFFFFFF
> > > > > > -#define ALL_CLEAR		0x0
> > > > > > -#define PRE_OVERFLOW		0xFFFFFFF0
> > > > > > -#define PRE_OVERFLOW2		0xFFFFFFDC
> > > > > > +#define ALL_SET			0x00000000FFFFFFFFULL
> > > > > > +#define ALL_CLEAR		0x0000000000000000ULL
> > > > > > +#define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > > > > +#define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > > > > >  
> > > > > >  #define PMU_PPI			23
> > > > > >  
> > > > > > @@ -538,6 +538,7 @@ static void test_mem_access(void)
> > > > > >  static void test_sw_incr(void)
> > > > > >  {
> > > > > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > > > > > +	uint64_t cntr0;
> > > > > >  	int i;
> > > > > >  
> > > > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > > > @@ -572,9 +573,9 @@ static void test_sw_incr(void)
> > > > > >  		write_sysreg(0x3, pmswinc_el0);
> > > > > >  
> > > > > >  	isb();
> > > > > > -	report(read_regn_el0(pmevcntr, 0)  == 84, "counter #1 after + 100 SW_INCR");
> > > > > > -	report(read_regn_el0(pmevcntr, 1)  == 100,
> > > > > > -		"counter #0 after + 100 SW_INCR");
> > > > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > > > > +	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > > > > > +	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> > > > > >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > > > > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > > > > >  	report(read_sysreg(pmovsclr_el0) == 0x1,
> > > > > > @@ -584,6 +585,7 @@ static void test_sw_incr(void)
> > > > > >  static void test_chained_counters(void)
> > > > > >  {
> > > > > >  	uint32_t events[] = {CPU_CYCLES, CHAIN};
> > > > > > +	uint64_t cntr1;
> > > > > >  
> > > > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > > >  		return;
> > > > > > @@ -618,13 +620,16 @@ static void test_chained_counters(void)
> > > > > >  
> > > > > >  	precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> > > > > >  	report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > > > > > -	report(!read_regn_el0(pmevcntr, 1), "CHAIN counter #1 wrapped");
> > > > > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > > > > +	report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > > > > 
> > > > > It looks to me like the intention of the test was to check that the counter
> > > > > programmed with the CHAIN event wraps, judging from the report message.
> > > > > 
> > > > 
> > > > Ah, right. Yeah, that message is confusing. It should be the short
> > > > version of "Inrementing at 32-bits resulted in the right value".
> > > > 
> > > > > I think it would be interesting to keep that by programming counter #1 with
> > > > > ~0ULL when PMUv3p5 (maybe call it ALL_SET64?) and test the counter value
> > > > > against 0.
> > > > 
> > > > The last commit adds tests using ALL_SET64.  Tests can be run in two
> > > > modes: overflow_at_64bits and not.  However, this test,
> > > > test_chained_counters(), and all other chained tests only use the
> > > > !overflow_at_64bits mode (even after the last commit). The reason is
> > > > that there are no CHAIN events when overflowing at 64-bits (more details
> > > > in the commit message). But, don't worry, there are lots of tests that
> > > > check wrapping at 64-bits (overflow_at_64bits=true).
> > > 
> > > What I was suggesting is this (change on top of this series, not on top of
> > > this patch, to get access to ALL_SET_AT):
> > 
> > Ooh, I see, I agree: it would be better to check that the odd counter
> > increments from ~0ULL to 0 when using 64-bit counters.
> > 
> > > 
> > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > index 3cb563b1abe4..fd7f20fc6c52 100644
> > > --- a/arm/pmu.c
> > > +++ b/arm/pmu.c
> > > @@ -607,7 +607,6 @@ static void test_sw_incr(bool overflow_at_64bits)
> > >  static void test_chained_counters(bool overflow_at_64bits)
> > >  {
> > >         uint32_t events[] = {CPU_CYCLES, CHAIN};
> > > -       uint64_t cntr1;
> > > 
> > >         if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> > >                                    overflow_at_64bits))
> > > @@ -639,12 +638,11 @@ static void test_chained_counters(bool overflow_at_64bits)
> > >         report(read_sysreg(pmovsclr_el0) == 0x1, "overflow recorded for chained incr #2");
> > > 
> > >         write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > -       write_regn_el0(pmevcntr, 1, ALL_SET);
> > > +       write_regn_el0(pmevcntr, 1, ALL_SET_AT(overflow_at_64bits));
> > 
> > The only change is that this should be:
> > 
> > 	ALL_SET_AT(pmu.version >= ID_DFR0_PMU_V3_8_5)
> > 
> > Because "overflow_at_64bits" implies PMCR_EL0.LP = 1.
> 
> Right, and test_chained_counters() is never called with overflow_at_64bits
> == true.
> 
> How about renaming the parameter overflow_at_64bits -> unused (or something
> like that) to make it clear that the function does the same thing
> regardless of the value?

Sounds good, will do for v2.

> 
> Thanks,
> Alex
> 
> > 
> > > 
> > >         precise_instrs_loop(22, pmu.pmcr_ro | PMU_PMCR_E);
> > >         report_info("overflow reg = 0x%lx", read_sysreg(pmovsclr_el0));
> > > -       cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > -       report(read_regn_el0(pmevcntr, 1) == cntr1, "CHAIN counter #1 wrapped");
> > > +       report(read_regn_el0(pmevcntr, 1) == 0, "CHAIN counter #1 wrapped");
> > > 
> > >         report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> > >  }
> > > 
> > > The counters are 64bit, but the CHAIN event should still work because
> > > PMCR_EL0.LP is 0, according to the event description in the Arm ARM (ARM
> > > DDI 0487I.a, page D17-6461).
> > > 
> > > Thanks,
> > > Alex
> > > 
> > > > 
> > > > > Alternatively, the report message can be modified, and "wrapped"
> > > > > replaced with "incremented" (or something like that), to avoid confusion.
> > > > > 
> > > > > > +
> > > > > >  	report(read_sysreg(pmovsclr_el0) == 0x3, "overflow on even and odd counters");
> > > > > >  }
> > > > > >  
> > > > > >  static void test_chained_sw_incr(void)
> > > > > >  {
> > > > > >  	uint32_t events[] = {SW_INCR, CHAIN};
> > > > > > +	uint64_t cntr0, cntr1;
> > > > > >  	int i;
> > > > > >  
> > > > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events)))
> > > > > > @@ -665,10 +670,12 @@ static void test_chained_sw_incr(void)
> > > > > >  		write_sysreg(0x1, pmswinc_el0);
> > > > > >  
> > > > > >  	isb();
> > > > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 0 : ALL_SET + 1;
> > > > > > +	cntr1 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > > > >  	report((read_sysreg(pmovsclr_el0) == 0x3) &&
> > > > > > -		(read_regn_el0(pmevcntr, 1) == 0) &&
> > > > > > -		(read_regn_el0(pmevcntr, 0) == 84),
> > > > > > -		"expected overflows and values after 100 SW_INCR/CHAIN");
> > > > > > +	       (read_regn_el0(pmevcntr, 1) == cntr0) &&
> > > > > > +	       (read_regn_el0(pmevcntr, 0) == cntr1),
> > > > > 
> > > > > This is hard to parse, it would be better if counter 0 is compared against
> > > > > cntr0 and counter 1 against cntr1.
> > > > 
> > > > Ah, yes, code is correct but that's indeed confusing.
> > > > 
> > > > > 
> > > > > Also, same suggestion here, looks like the test wants to check that the
> > > > > odd-numbered counter wraps around when counting the CHAIN event.
> > > > 
> > > > Ack. Will update for v2.
> > > > 
> > > > Thanks!
> > > > Ricardo
> > > > 
> > > > > 
> > > > > Thanks,
> > > > > Alex
> > > > > 
> > > > > > +	       "expected overflows and values after 100 SW_INCR/CHAIN");
> > > > > >  	report_info("overflow=0x%lx, #0=%ld #1=%ld", read_sysreg(pmovsclr_el0),
> > > > > >  		    read_regn_el0(pmevcntr, 0), read_regn_el0(pmevcntr, 1));
> > > > > >  }
> > > > > > -- 
> > > > > > 2.39.0.rc0.267.gcb52ba06e7-goog
> > > > > > 

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

* Re: [kvm-unit-tests PATCH 3/3] arm: pmu: Add tests for 64-bit overflows
  2022-12-14 10:45         ` Alexandru Elisei
@ 2022-12-14 18:31           ` Ricardo Koller
  -1 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-14 18:31 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: kvm, kvmarm, andrew.jones, maz, eric.auger, oliver.upton, reijiw

On Wed, Dec 14, 2022 at 10:45:07AM +0000, Alexandru Elisei wrote:
> Hi,
> 
> On Tue, Dec 13, 2022 at 10:04:04AM -0800, Ricardo Koller wrote:
> > On Tue, Dec 13, 2022 at 05:03:40PM +0000, Alexandru Elisei wrote:
> > > Hi,
> > > 
> > > Checked that all places where ALL_SET/PRE_OVERFLOW were used are now taking
> > > into account the fact that counters are programmed to be 64bit.
> > > 
> > > In the case of 64bit counters, the printf format specifier is %ld, which
> > > means that ALL_SET_64 and PRE_OVERFLOW_64 are now displayed as negative
> > > numbers. For example:
> > > 
> > > INFO: pmu: pmu-sw-incr: 32-bit: SW_INCR counter #0 has value 4294967280
> > > PASS: pmu: pmu-sw-incr: 32-bit: PWSYNC does not increment if PMCR.E is unset
> > > [..]
> > > INFO: pmu: pmu-sw-incr: 64-bit: SW_INCR counter #0 has value -16
> > > PASS: pmu: pmu-sw-incr: 64-bit: PWSYNC does not increment if PMCR.E is unset
> > > 
> > 
> > Argh, I didn't notice this. I think this would be more useful if it
> > printed %llx in all cases.
> 
> Indeed, printing the hex value will make it easier to match it against the
> defines.
> 
> One more comment below.
> 
> > 
> > > I was thinking that the format specifiers could be changed to unsigned
> > > long.  The counters only increment, they don't decrement, and I can't think
> > > how printing them as signed could be useful.
> > > 
> > > One more comment below.
> > > 
> > > On Fri, Dec 02, 2022 at 04:55:27AM +0000, Ricardo Koller wrote:
> > > > Modify all tests checking overflows to support both 32 (PMCR_EL0.LP == 0)
> > > > and 64-bit overflows (PMCR_EL0.LP == 1). 64-bit overflows are only
> > > > supported on PMUv3p5.
> > > > 
> > > > Note that chained tests do not implement "overflow_at_64bits == true".
> > > > That's because there are no CHAIN events when "PMCR_EL0.LP == 1" (for more
> > > > details see AArch64.IncrementEventCounter() pseudocode in the ARM ARM DDI
> > > > 0487H.a, J1.1.1 "aarch64/debug").
> > > > 
> > > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > > ---
> > > >  arm/pmu.c | 91 ++++++++++++++++++++++++++++++++++++-------------------
> > > >  1 file changed, 60 insertions(+), 31 deletions(-)
> > > > 
> > > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > > index 59e5bfe..3cb563b 100644
> > > > --- a/arm/pmu.c
> > > > +++ b/arm/pmu.c
> > > > @@ -28,6 +28,7 @@
> > > >  #define PMU_PMCR_X         (1 << 4)
> > > >  #define PMU_PMCR_DP        (1 << 5)
> > > >  #define PMU_PMCR_LC        (1 << 6)
> > > > +#define PMU_PMCR_LP        (1 << 7)
> > > >  #define PMU_PMCR_N_SHIFT   11
> > > >  #define PMU_PMCR_N_MASK    0x1f
> > > >  #define PMU_PMCR_ID_SHIFT  16
> > > > @@ -55,10 +56,15 @@
> > > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > > >  
> > > >  #define ALL_SET			0x00000000FFFFFFFFULL
> > > > +#define ALL_SET_64		0xFFFFFFFFFFFFFFFFULL
> > > >  #define ALL_CLEAR		0x0000000000000000ULL
> > > >  #define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > > +#define PRE_OVERFLOW_64		0xFFFFFFFFFFFFFFF0ULL
> > > >  #define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > > >  
> > > > +#define PRE_OVERFLOW_AT(_64b)	(_64b ? PRE_OVERFLOW_64 : PRE_OVERFLOW)
> > > > +#define ALL_SET_AT(_64b)	(_64b ? ALL_SET_64 : ALL_SET)
> > > > +
> > > >  #define PMU_PPI			23
> > > >  
> > > >  struct pmu {
> > > > @@ -429,8 +435,10 @@ static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events,
> > > >  static void test_basic_event_count(bool overflow_at_64bits)
> > > >  {
> > > >  	uint32_t implemented_counter_mask, non_implemented_counter_mask;
> > > > -	uint32_t counter_mask;
> > > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > > >  	uint32_t events[] = {CPU_CYCLES, INST_RETIRED};
> > > > +	uint32_t counter_mask;
> > > >  
> > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> > > >  				   overflow_at_64bits))
> > > > @@ -452,13 +460,13 @@ static void test_basic_event_count(bool overflow_at_64bits)
> > > >  	 * clear cycle and all event counters and allow counter enablement
> > > >  	 * through PMCNTENSET. LC is RES1.
> > > >  	 */
> > > > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P);
> > > > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P | pmcr_lp);
> > > >  	isb();
> > > > -	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC), "pmcr: reset counters");
> > > > +	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC | pmcr_lp), "pmcr: reset counters");
> > > >  
> > > >  	/* Preset counter #0 to pre overflow value to trigger an overflow */
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > > +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
> > > >  		"counter #0 preset to pre-overflow value");
> > > >  	report(!read_regn_el0(pmevcntr, 1), "counter #1 is 0");
> > > >  
> > > > @@ -511,6 +519,8 @@ static void test_mem_access(bool overflow_at_64bits)
> > > >  {
> > > >  	void *addr = malloc(PAGE_SIZE);
> > > >  	uint32_t events[] = {MEM_ACCESS, MEM_ACCESS};
> > > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > > >  
> > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> > > >  				   overflow_at_64bits))
> > > > @@ -522,7 +532,7 @@ static void test_mem_access(bool overflow_at_64bits)
> > > >  	write_regn_el0(pmevtyper, 1, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
> > > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > >  	isb();
> > > > -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> > > > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > >  	report_info("counter #0 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 0));
> > > >  	report_info("counter #1 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 1));
> > > >  	/* We may measure more than 20 mem access depending on the core */
> > > > @@ -532,11 +542,11 @@ static void test_mem_access(bool overflow_at_64bits)
> > > >  
> > > >  	pmu_reset();
> > > >  
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> > > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > >  	isb();
> > > > -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> > > > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > >  	report(read_sysreg(pmovsclr_el0) == 0x3,
> > > >  	       "Ran 20 mem accesses with expected overflows on both counters");
> > > >  	report_info("cnt#0 = %ld cnt#1=%ld overflow=0x%lx",
> > > > @@ -546,6 +556,8 @@ static void test_mem_access(bool overflow_at_64bits)
> > > >  
> > > >  static void test_sw_incr(bool overflow_at_64bits)
> > > >  {
> > > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > > >  	uint64_t cntr0;
> > > >  	int i;
> > > > @@ -561,7 +573,7 @@ static void test_sw_incr(bool overflow_at_64bits)
> > > >  	/* enable counters #0 and #1 */
> > > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > >  
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > >  	isb();
> > > >  
> > > >  	for (i = 0; i < 100; i++)
> > > > @@ -569,21 +581,21 @@ static void test_sw_incr(bool overflow_at_64bits)
> > > >  
> > > >  	isb();
> > > >  	report_info("SW_INCR counter #0 has value %ld", read_regn_el0(pmevcntr, 0));
> > > > -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> > > > +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
> > > >  		"PWSYNC does not increment if PMCR.E is unset");
> > > >  
> > > >  	pmu_reset();
> > > >  
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> > > > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > >  	isb();
> > > >  
> > > >  	for (i = 0; i < 100; i++)
> > > >  		write_sysreg(0x3, pmswinc_el0);
> > > >  
> > > >  	isb();
> > > > -	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : pre_overflow + 100;
> > > >  	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > > >  	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> > > >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > > > @@ -844,6 +856,9 @@ static bool expect_interrupts(uint32_t bitmap)
> > > >  
> > > >  static void test_overflow_interrupt(bool overflow_at_64bits)
> > > >  {
> > > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > > +	uint64_t all_set = ALL_SET_AT(overflow_at_64bits);
> > > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > > >  	uint32_t events[] = {MEM_ACCESS, SW_INCR};
> > > >  	void *addr = malloc(PAGE_SIZE);
> > > >  	int i;
> > > > @@ -862,16 +877,16 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> > > >  	write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
> > > >  	write_regn_el0(pmevtyper, 1, SW_INCR | PMEVTYPER_EXCLUDE_EL0);
> > > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> > > >  	isb();
> > > >  
> > > >  	/* interrupts are disabled (PMINTENSET_EL1 == 0) */
> > > >  
> > > > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > > > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > >  	report(expect_interrupts(0), "no overflow interrupt after preset");
> > > >  
> > > > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> > > > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > >  	isb();
> > > >  
> > > >  	for (i = 0; i < 100; i++)
> > > > @@ -886,12 +901,12 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> > > >  
> > > >  	pmu_reset_stats();
> > > >  
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> > > >  	write_sysreg(ALL_SET, pmintenset_el1);
> > > >  	isb();
> > > >  
> > > > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > > > +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > >  	for (i = 0; i < 100; i++)
> > > >  		write_sysreg(0x3, pmswinc_el0);
> > > >  
> > > > @@ -900,25 +915,35 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> > > >  	report(expect_interrupts(0x3),
> > > >  		"overflow interrupts expected on #0 and #1");
> > > >  
> > > > -	/* promote to 64-b */
> > > > +	/*
> > > > +	 * promote to 64-b:
> > > > +	 *
> > > > +	 * This only applies to the !overflow_at_64bits case, as
> > > > +	 * overflow_at_64bits doesn't implement CHAIN events. The
> > > > +	 * overflow_at_64bits case just checks that chained counters are
> > > > +	 * not incremented when PMCR.LP == 1.
> > > > +	 */
> > > 
> > > If this doesn't do anything for when overflow_at_64bits, and since the
> > > interrupt is already tested before this part, why not exit early?
> > > 
> > > Or the test could check that the CHAIN event indeed does not increment when
> > > LP=1 at the end of this function.
> > 
> > That's precisely what it's doing.
> 
> Where? Are you referring to this part?
> 
> 	if (overflow_at_64bits)
> 		report(expect_interrupts(0x1),
> 		       "expect overflow interrupt on even counter");
> 
> My suggestion was to check that the counter that counts the CHAIN event
> didn't increment (PMEVCNTR1_EL0 == all_set).

Ah, I see. Yes, this could check that there are no interrupts and that
the even counter doesn't increment.

> I was thinking that since KVM
> emulates the CHAIN event in software, it might be useful to check that the
> final state of all registers is consistent. I'll leave it up to you to
> decide if you want to add this extra check.

Will add it if no other test is checking that, which I think is the
case.

Thanks!
Ricardo

> 
> Thanks,
> Alex
> 
> > 
> > Thanks!
> > Ricardo
> > 
> > > 
> > > Thanks,
> > > Alex
> > > 
> > > >  
> > > >  	pmu_reset_stats();
> > > >  
> > > >  	write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0);
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > >  	isb();
> > > > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > > > -	report(expect_interrupts(0x1),
> > > > -		"expect overflow interrupt on 32b boundary");
> > > > +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > > +	report(expect_interrupts(0x1), "expect overflow interrupt");
> > > >  
> > > >  	/* overflow on odd counter */
> > > >  	pmu_reset_stats();
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > -	write_regn_el0(pmevcntr, 1, ALL_SET);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > > +	write_regn_el0(pmevcntr, 1, all_set);
> > > >  	isb();
> > > > -	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E);
> > > > -	report(expect_interrupts(0x3),
> > > > -		"expect overflow interrupt on even and odd counter");
> > > > +	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > > +	if (overflow_at_64bits)
> > > > +		report(expect_interrupts(0x1),
> > > > +		       "expect overflow interrupt on even counter");
> > > > +	else
> > > > +		report(expect_interrupts(0x3),
> > > > +		       "expect overflow interrupt on even and odd counter");
> > > >  }
> > > >  #endif
> > > >  
> > > > @@ -1119,10 +1144,13 @@ int main(int argc, char *argv[])
> > > >  		report_prefix_pop();
> > > >  	} else if (strcmp(argv[1], "pmu-basic-event-count") == 0) {
> > > >  		run_test(argv[1], test_basic_event_count, false);
> > > > +		run_test(argv[1], test_basic_event_count, true);
> > > >  	} else if (strcmp(argv[1], "pmu-mem-access") == 0) {
> > > >  		run_test(argv[1], test_mem_access, false);
> > > > +		run_test(argv[1], test_mem_access, true);
> > > >  	} else if (strcmp(argv[1], "pmu-sw-incr") == 0) {
> > > >  		run_test(argv[1], test_sw_incr, false);
> > > > +		run_test(argv[1], test_sw_incr, true);
> > > >  	} else if (strcmp(argv[1], "pmu-chained-counters") == 0) {
> > > >  		run_test(argv[1], test_chained_counters, false);
> > > >  	} else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) {
> > > > @@ -1131,6 +1159,7 @@ int main(int argc, char *argv[])
> > > >  		run_test(argv[1], test_chain_promotion, false);
> > > >  	} else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) {
> > > >  		run_test(argv[1], test_overflow_interrupt, false);
> > > > +		run_test(argv[1], test_overflow_interrupt, true);
> > > >  	} else {
> > > >  		report_abort("Unknown sub-test '%s'", argv[1]);
> > > >  	}
> > > > -- 
> > > > 2.39.0.rc0.267.gcb52ba06e7-goog
> > > > 

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

* Re: [kvm-unit-tests PATCH 3/3] arm: pmu: Add tests for 64-bit overflows
@ 2022-12-14 18:31           ` Ricardo Koller
  0 siblings, 0 replies; 40+ messages in thread
From: Ricardo Koller @ 2022-12-14 18:31 UTC (permalink / raw)
  To: Alexandru Elisei; +Cc: kvm, maz, andrew.jones, kvmarm

On Wed, Dec 14, 2022 at 10:45:07AM +0000, Alexandru Elisei wrote:
> Hi,
> 
> On Tue, Dec 13, 2022 at 10:04:04AM -0800, Ricardo Koller wrote:
> > On Tue, Dec 13, 2022 at 05:03:40PM +0000, Alexandru Elisei wrote:
> > > Hi,
> > > 
> > > Checked that all places where ALL_SET/PRE_OVERFLOW were used are now taking
> > > into account the fact that counters are programmed to be 64bit.
> > > 
> > > In the case of 64bit counters, the printf format specifier is %ld, which
> > > means that ALL_SET_64 and PRE_OVERFLOW_64 are now displayed as negative
> > > numbers. For example:
> > > 
> > > INFO: pmu: pmu-sw-incr: 32-bit: SW_INCR counter #0 has value 4294967280
> > > PASS: pmu: pmu-sw-incr: 32-bit: PWSYNC does not increment if PMCR.E is unset
> > > [..]
> > > INFO: pmu: pmu-sw-incr: 64-bit: SW_INCR counter #0 has value -16
> > > PASS: pmu: pmu-sw-incr: 64-bit: PWSYNC does not increment if PMCR.E is unset
> > > 
> > 
> > Argh, I didn't notice this. I think this would be more useful if it
> > printed %llx in all cases.
> 
> Indeed, printing the hex value will make it easier to match it against the
> defines.
> 
> One more comment below.
> 
> > 
> > > I was thinking that the format specifiers could be changed to unsigned
> > > long.  The counters only increment, they don't decrement, and I can't think
> > > how printing them as signed could be useful.
> > > 
> > > One more comment below.
> > > 
> > > On Fri, Dec 02, 2022 at 04:55:27AM +0000, Ricardo Koller wrote:
> > > > Modify all tests checking overflows to support both 32 (PMCR_EL0.LP == 0)
> > > > and 64-bit overflows (PMCR_EL0.LP == 1). 64-bit overflows are only
> > > > supported on PMUv3p5.
> > > > 
> > > > Note that chained tests do not implement "overflow_at_64bits == true".
> > > > That's because there are no CHAIN events when "PMCR_EL0.LP == 1" (for more
> > > > details see AArch64.IncrementEventCounter() pseudocode in the ARM ARM DDI
> > > > 0487H.a, J1.1.1 "aarch64/debug").
> > > > 
> > > > Signed-off-by: Ricardo Koller <ricarkol@google.com>
> > > > ---
> > > >  arm/pmu.c | 91 ++++++++++++++++++++++++++++++++++++-------------------
> > > >  1 file changed, 60 insertions(+), 31 deletions(-)
> > > > 
> > > > diff --git a/arm/pmu.c b/arm/pmu.c
> > > > index 59e5bfe..3cb563b 100644
> > > > --- a/arm/pmu.c
> > > > +++ b/arm/pmu.c
> > > > @@ -28,6 +28,7 @@
> > > >  #define PMU_PMCR_X         (1 << 4)
> > > >  #define PMU_PMCR_DP        (1 << 5)
> > > >  #define PMU_PMCR_LC        (1 << 6)
> > > > +#define PMU_PMCR_LP        (1 << 7)
> > > >  #define PMU_PMCR_N_SHIFT   11
> > > >  #define PMU_PMCR_N_MASK    0x1f
> > > >  #define PMU_PMCR_ID_SHIFT  16
> > > > @@ -55,10 +56,15 @@
> > > >  #define EXT_COMMON_EVENTS_HIGH	0x403F
> > > >  
> > > >  #define ALL_SET			0x00000000FFFFFFFFULL
> > > > +#define ALL_SET_64		0xFFFFFFFFFFFFFFFFULL
> > > >  #define ALL_CLEAR		0x0000000000000000ULL
> > > >  #define PRE_OVERFLOW		0x00000000FFFFFFF0ULL
> > > > +#define PRE_OVERFLOW_64		0xFFFFFFFFFFFFFFF0ULL
> > > >  #define PRE_OVERFLOW2		0x00000000FFFFFFDCULL
> > > >  
> > > > +#define PRE_OVERFLOW_AT(_64b)	(_64b ? PRE_OVERFLOW_64 : PRE_OVERFLOW)
> > > > +#define ALL_SET_AT(_64b)	(_64b ? ALL_SET_64 : ALL_SET)
> > > > +
> > > >  #define PMU_PPI			23
> > > >  
> > > >  struct pmu {
> > > > @@ -429,8 +435,10 @@ static bool satisfy_prerequisites(uint32_t *events, unsigned int nb_events,
> > > >  static void test_basic_event_count(bool overflow_at_64bits)
> > > >  {
> > > >  	uint32_t implemented_counter_mask, non_implemented_counter_mask;
> > > > -	uint32_t counter_mask;
> > > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > > >  	uint32_t events[] = {CPU_CYCLES, INST_RETIRED};
> > > > +	uint32_t counter_mask;
> > > >  
> > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> > > >  				   overflow_at_64bits))
> > > > @@ -452,13 +460,13 @@ static void test_basic_event_count(bool overflow_at_64bits)
> > > >  	 * clear cycle and all event counters and allow counter enablement
> > > >  	 * through PMCNTENSET. LC is RES1.
> > > >  	 */
> > > > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P);
> > > > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_LC | PMU_PMCR_C | PMU_PMCR_P | pmcr_lp);
> > > >  	isb();
> > > > -	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC), "pmcr: reset counters");
> > > > +	report(get_pmcr() == (pmu.pmcr_ro | PMU_PMCR_LC | pmcr_lp), "pmcr: reset counters");
> > > >  
> > > >  	/* Preset counter #0 to pre overflow value to trigger an overflow */
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > > +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
> > > >  		"counter #0 preset to pre-overflow value");
> > > >  	report(!read_regn_el0(pmevcntr, 1), "counter #1 is 0");
> > > >  
> > > > @@ -511,6 +519,8 @@ static void test_mem_access(bool overflow_at_64bits)
> > > >  {
> > > >  	void *addr = malloc(PAGE_SIZE);
> > > >  	uint32_t events[] = {MEM_ACCESS, MEM_ACCESS};
> > > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > > >  
> > > >  	if (!satisfy_prerequisites(events, ARRAY_SIZE(events),
> > > >  				   overflow_at_64bits))
> > > > @@ -522,7 +532,7 @@ static void test_mem_access(bool overflow_at_64bits)
> > > >  	write_regn_el0(pmevtyper, 1, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
> > > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > >  	isb();
> > > > -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> > > > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > >  	report_info("counter #0 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 0));
> > > >  	report_info("counter #1 is %ld (MEM_ACCESS)", read_regn_el0(pmevcntr, 1));
> > > >  	/* We may measure more than 20 mem access depending on the core */
> > > > @@ -532,11 +542,11 @@ static void test_mem_access(bool overflow_at_64bits)
> > > >  
> > > >  	pmu_reset();
> > > >  
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> > > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > >  	isb();
> > > > -	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E);
> > > > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > >  	report(read_sysreg(pmovsclr_el0) == 0x3,
> > > >  	       "Ran 20 mem accesses with expected overflows on both counters");
> > > >  	report_info("cnt#0 = %ld cnt#1=%ld overflow=0x%lx",
> > > > @@ -546,6 +556,8 @@ static void test_mem_access(bool overflow_at_64bits)
> > > >  
> > > >  static void test_sw_incr(bool overflow_at_64bits)
> > > >  {
> > > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > > >  	uint32_t events[] = {SW_INCR, SW_INCR};
> > > >  	uint64_t cntr0;
> > > >  	int i;
> > > > @@ -561,7 +573,7 @@ static void test_sw_incr(bool overflow_at_64bits)
> > > >  	/* enable counters #0 and #1 */
> > > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > >  
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > >  	isb();
> > > >  
> > > >  	for (i = 0; i < 100; i++)
> > > > @@ -569,21 +581,21 @@ static void test_sw_incr(bool overflow_at_64bits)
> > > >  
> > > >  	isb();
> > > >  	report_info("SW_INCR counter #0 has value %ld", read_regn_el0(pmevcntr, 0));
> > > > -	report(read_regn_el0(pmevcntr, 0) == PRE_OVERFLOW,
> > > > +	report(read_regn_el0(pmevcntr, 0) == pre_overflow,
> > > >  		"PWSYNC does not increment if PMCR.E is unset");
> > > >  
> > > >  	pmu_reset();
> > > >  
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> > > > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > >  	isb();
> > > >  
> > > >  	for (i = 0; i < 100; i++)
> > > >  		write_sysreg(0x3, pmswinc_el0);
> > > >  
> > > >  	isb();
> > > > -	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : PRE_OVERFLOW + 100;
> > > > +	cntr0 = (pmu.version < ID_DFR0_PMU_V3_8_5) ? 84 : pre_overflow + 100;
> > > >  	report(read_regn_el0(pmevcntr, 0) == cntr0, "counter #0 after + 100 SW_INCR");
> > > >  	report(read_regn_el0(pmevcntr, 1) == 100, "counter #1 after + 100 SW_INCR");
> > > >  	report_info("counter values after 100 SW_INCR #0=%ld #1=%ld",
> > > > @@ -844,6 +856,9 @@ static bool expect_interrupts(uint32_t bitmap)
> > > >  
> > > >  static void test_overflow_interrupt(bool overflow_at_64bits)
> > > >  {
> > > > +	uint64_t pre_overflow = PRE_OVERFLOW_AT(overflow_at_64bits);
> > > > +	uint64_t all_set = ALL_SET_AT(overflow_at_64bits);
> > > > +	uint64_t pmcr_lp = overflow_at_64bits ? PMU_PMCR_LP : 0;
> > > >  	uint32_t events[] = {MEM_ACCESS, SW_INCR};
> > > >  	void *addr = malloc(PAGE_SIZE);
> > > >  	int i;
> > > > @@ -862,16 +877,16 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> > > >  	write_regn_el0(pmevtyper, 0, MEM_ACCESS | PMEVTYPER_EXCLUDE_EL0);
> > > >  	write_regn_el0(pmevtyper, 1, SW_INCR | PMEVTYPER_EXCLUDE_EL0);
> > > >  	write_sysreg_s(0x3, PMCNTENSET_EL0);
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> > > >  	isb();
> > > >  
> > > >  	/* interrupts are disabled (PMINTENSET_EL1 == 0) */
> > > >  
> > > > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > > > +	mem_access_loop(addr, 20, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > >  	report(expect_interrupts(0), "no overflow interrupt after preset");
> > > >  
> > > > -	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E);
> > > > +	set_pmcr(pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > >  	isb();
> > > >  
> > > >  	for (i = 0; i < 100; i++)
> > > > @@ -886,12 +901,12 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> > > >  
> > > >  	pmu_reset_stats();
> > > >  
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > -	write_regn_el0(pmevcntr, 1, PRE_OVERFLOW);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > > +	write_regn_el0(pmevcntr, 1, pre_overflow);
> > > >  	write_sysreg(ALL_SET, pmintenset_el1);
> > > >  	isb();
> > > >  
> > > > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > > > +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > >  	for (i = 0; i < 100; i++)
> > > >  		write_sysreg(0x3, pmswinc_el0);
> > > >  
> > > > @@ -900,25 +915,35 @@ static void test_overflow_interrupt(bool overflow_at_64bits)
> > > >  	report(expect_interrupts(0x3),
> > > >  		"overflow interrupts expected on #0 and #1");
> > > >  
> > > > -	/* promote to 64-b */
> > > > +	/*
> > > > +	 * promote to 64-b:
> > > > +	 *
> > > > +	 * This only applies to the !overflow_at_64bits case, as
> > > > +	 * overflow_at_64bits doesn't implement CHAIN events. The
> > > > +	 * overflow_at_64bits case just checks that chained counters are
> > > > +	 * not incremented when PMCR.LP == 1.
> > > > +	 */
> > > 
> > > If this doesn't do anything for when overflow_at_64bits, and since the
> > > interrupt is already tested before this part, why not exit early?
> > > 
> > > Or the test could check that the CHAIN event indeed does not increment when
> > > LP=1 at the end of this function.
> > 
> > That's precisely what it's doing.
> 
> Where? Are you referring to this part?
> 
> 	if (overflow_at_64bits)
> 		report(expect_interrupts(0x1),
> 		       "expect overflow interrupt on even counter");
> 
> My suggestion was to check that the counter that counts the CHAIN event
> didn't increment (PMEVCNTR1_EL0 == all_set).

Ah, I see. Yes, this could check that there are no interrupts and that
the even counter doesn't increment.

> I was thinking that since KVM
> emulates the CHAIN event in software, it might be useful to check that the
> final state of all registers is consistent. I'll leave it up to you to
> decide if you want to add this extra check.

Will add it if no other test is checking that, which I think is the
case.

Thanks!
Ricardo

> 
> Thanks,
> Alex
> 
> > 
> > Thanks!
> > Ricardo
> > 
> > > 
> > > Thanks,
> > > Alex
> > > 
> > > >  
> > > >  	pmu_reset_stats();
> > > >  
> > > >  	write_regn_el0(pmevtyper, 1, CHAIN | PMEVTYPER_EXCLUDE_EL0);
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > >  	isb();
> > > > -	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E);
> > > > -	report(expect_interrupts(0x1),
> > > > -		"expect overflow interrupt on 32b boundary");
> > > > +	mem_access_loop(addr, 200, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > > +	report(expect_interrupts(0x1), "expect overflow interrupt");
> > > >  
> > > >  	/* overflow on odd counter */
> > > >  	pmu_reset_stats();
> > > > -	write_regn_el0(pmevcntr, 0, PRE_OVERFLOW);
> > > > -	write_regn_el0(pmevcntr, 1, ALL_SET);
> > > > +	write_regn_el0(pmevcntr, 0, pre_overflow);
> > > > +	write_regn_el0(pmevcntr, 1, all_set);
> > > >  	isb();
> > > > -	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E);
> > > > -	report(expect_interrupts(0x3),
> > > > -		"expect overflow interrupt on even and odd counter");
> > > > +	mem_access_loop(addr, 400, pmu.pmcr_ro | PMU_PMCR_E | pmcr_lp);
> > > > +	if (overflow_at_64bits)
> > > > +		report(expect_interrupts(0x1),
> > > > +		       "expect overflow interrupt on even counter");
> > > > +	else
> > > > +		report(expect_interrupts(0x3),
> > > > +		       "expect overflow interrupt on even and odd counter");
> > > >  }
> > > >  #endif
> > > >  
> > > > @@ -1119,10 +1144,13 @@ int main(int argc, char *argv[])
> > > >  		report_prefix_pop();
> > > >  	} else if (strcmp(argv[1], "pmu-basic-event-count") == 0) {
> > > >  		run_test(argv[1], test_basic_event_count, false);
> > > > +		run_test(argv[1], test_basic_event_count, true);
> > > >  	} else if (strcmp(argv[1], "pmu-mem-access") == 0) {
> > > >  		run_test(argv[1], test_mem_access, false);
> > > > +		run_test(argv[1], test_mem_access, true);
> > > >  	} else if (strcmp(argv[1], "pmu-sw-incr") == 0) {
> > > >  		run_test(argv[1], test_sw_incr, false);
> > > > +		run_test(argv[1], test_sw_incr, true);
> > > >  	} else if (strcmp(argv[1], "pmu-chained-counters") == 0) {
> > > >  		run_test(argv[1], test_chained_counters, false);
> > > >  	} else if (strcmp(argv[1], "pmu-chained-sw-incr") == 0) {
> > > > @@ -1131,6 +1159,7 @@ int main(int argc, char *argv[])
> > > >  		run_test(argv[1], test_chain_promotion, false);
> > > >  	} else if (strcmp(argv[1], "pmu-overflow-interrupt") == 0) {
> > > >  		run_test(argv[1], test_overflow_interrupt, false);
> > > > +		run_test(argv[1], test_overflow_interrupt, true);
> > > >  	} else {
> > > >  		report_abort("Unknown sub-test '%s'", argv[1]);
> > > >  	}
> > > > -- 
> > > > 2.39.0.rc0.267.gcb52ba06e7-goog
> > > > 
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

end of thread, other threads:[~2022-12-14 18:31 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-02  4:55 [kvm-unit-tests PATCH 0/3] arm: pmu: Add support for PMUv3p5 Ricardo Koller
2022-12-02  4:55 ` Ricardo Koller
2022-12-02  4:55 ` [kvm-unit-tests PATCH 1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters Ricardo Koller
2022-12-02  4:55   ` Ricardo Koller
2022-12-09 17:47   ` Alexandru Elisei
2022-12-09 17:47     ` Alexandru Elisei
2022-12-10 11:01     ` Marc Zyngier
2022-12-10 11:01       ` Marc Zyngier
2022-12-11 11:40       ` Alexandru Elisei
2022-12-11 11:40         ` Alexandru Elisei
2022-12-12  9:05         ` Marc Zyngier
2022-12-12  9:05           ` Marc Zyngier
2022-12-12 13:56           ` Alexandru Elisei
2022-12-12 13:56             ` Alexandru Elisei
2022-12-12 21:00     ` Ricardo Koller
2022-12-12 21:00       ` Ricardo Koller
2022-12-13 12:36   ` Alexandru Elisei
2022-12-13 12:36     ` Alexandru Elisei
2022-12-13 16:21     ` Ricardo Koller
2022-12-13 16:21       ` Ricardo Koller
2022-12-13 16:43       ` Alexandru Elisei
2022-12-13 16:43         ` Alexandru Elisei
2022-12-13 18:01         ` Ricardo Koller
2022-12-13 18:01           ` Ricardo Koller
2022-12-14 10:46           ` Alexandru Elisei
2022-12-14 10:46             ` Alexandru Elisei
2022-12-14 18:07             ` Ricardo Koller
2022-12-14 18:07               ` Ricardo Koller
2022-12-02  4:55 ` [kvm-unit-tests PATCH 2/3] arm: pmu: Prepare for testing 64-bit overflows Ricardo Koller
2022-12-02  4:55   ` Ricardo Koller
2022-12-02  4:55 ` [kvm-unit-tests PATCH 3/3] arm: pmu: Add tests for " Ricardo Koller
2022-12-02  4:55   ` Ricardo Koller
2022-12-13 17:03   ` Alexandru Elisei
2022-12-13 17:03     ` Alexandru Elisei
2022-12-13 18:04     ` Ricardo Koller
2022-12-13 18:04       ` Ricardo Koller
2022-12-14 10:45       ` Alexandru Elisei
2022-12-14 10:45         ` Alexandru Elisei
2022-12-14 18:31         ` Ricardo Koller
2022-12-14 18:31           ` Ricardo Koller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.