diff mbox series

[kvm-unit-tests,1/3] arm: pmu: Fix overflow checks for PMUv3p5 long counters

Message ID 20221202045527.3646838-2-ricarkol@google.com (mailing list archive)
State New, archived
Headers show
Series arm: pmu: Add support for PMUv3p5 | expand

Commit Message

Ricardo Koller Dec. 2, 2022, 4:55 a.m. UTC
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(-)

Comments

Alexandru Elisei Dec. 9, 2022, 5:47 p.m. UTC | #1
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
>
Marc Zyngier Dec. 10, 2022, 11:01 a.m. UTC | #2
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.
Alexandru Elisei Dec. 11, 2022, 11:40 a.m. UTC | #3
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
Marc Zyngier Dec. 12, 2022, 9:05 a.m. UTC | #4
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.
Alexandru Elisei Dec. 12, 2022, 1:56 p.m. UTC | #5
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
Ricardo Koller Dec. 12, 2022, 9 p.m. UTC | #6
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
> >
Alexandru Elisei Dec. 13, 2022, 12:36 p.m. UTC | #7
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
>
Ricardo Koller Dec. 13, 2022, 4:21 p.m. UTC | #8
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
> >
Alexandru Elisei Dec. 13, 2022, 4:43 p.m. UTC | #9
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
> > >
Ricardo Koller Dec. 13, 2022, 6:01 p.m. UTC | #10
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
> > > >
Alexandru Elisei Dec. 14, 2022, 10:46 a.m. UTC | #11
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
> > > > >
Ricardo Koller Dec. 14, 2022, 6:07 p.m. UTC | #12
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
> > > > > >
diff mbox series

Patch

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));
 }