diff mbox series

[v1,2/3] arm64: idle: Cache AMU counters before entering idle

Message ID 20240229162520.970986-3-vanshikonda@os.amperecomputing.com
State New
Headers show
Series arm64: Use AMU counters for measuring CPU frequency | expand

Commit Message

Vanshidhar Konda Feb. 29, 2024, 4:25 p.m. UTC
AMU counters do not increment while a CPU is in idle. Saving the value
of the core and constant counters prior to invoking WFI allows FIE to
compute the frequency of a CPU that is idle.

Signed-off-by: Vanshidhar Konda <vanshikonda@os.amperecomputing.com>
---
 arch/arm64/kernel/idle.c     | 10 ++++++++++
 arch/arm64/kernel/topology.c | 14 ++++++++------
 2 files changed, 18 insertions(+), 6 deletions(-)

Comments

Vanshidhar Konda March 11, 2024, 6:27 p.m. UTC | #1
On Thu, Mar 07, 2024 at 11:17:26AM +0800, lihuisong (C) wrote:
>
>在 2024/3/1 0:25, Vanshidhar Konda 写道:
>>AMU counters do not increment while a CPU is in idle. Saving the value
>>of the core and constant counters prior to invoking WFI allows FIE to
>>compute the frequency of a CPU that is idle.
>>
>>Signed-off-by: Vanshidhar Konda <vanshikonda@os.amperecomputing.com>
>>---
>>  arch/arm64/kernel/idle.c     | 10 ++++++++++
>>  arch/arm64/kernel/topology.c | 14 ++++++++------
>>  2 files changed, 18 insertions(+), 6 deletions(-)
>>
>>diff --git a/arch/arm64/kernel/idle.c b/arch/arm64/kernel/idle.c
>>index 05cfb347ec26..5ed2e57188a8 100644
>>--- a/arch/arm64/kernel/idle.c
>>+++ b/arch/arm64/kernel/idle.c
>>@@ -26,6 +26,16 @@ void __cpuidle cpu_do_idle(void)
>>  	arm_cpuidle_save_irq_context(&context);
>>+#ifdef CONFIG_ARM64_AMU_EXTN
>>+	/* Update the AMU counters before entering WFI. The cached AMU counter
>>+	 * value is used to determine CPU frequency while the CPU is idle
>>+	 * without needing to wake up the CPU.
>>+	 */
>>+
>>+	if (cpu_has_amu_feat(smp_processor_id()))
>>+		update_freq_counters_refs();
>>+#endif
>The below point I has mentioned in [1].
>This is just for the WFI state.
>What about other deeper idle states, like retention and power down?
>The path to enter idle state is different for them. We should do this 
>for all idle states.
>

Yes. That makes sense. I'll account for them in the next version of the
patch. I'll work on the next version of the patch based on the updated
patch from @Beata.

Thanks,
Vanshi

>>+
>>  	dsb(sy);
>>  	wfi();
>>diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
>>index db8d14525cf4..8905eb0c681f 100644
>>--- a/arch/arm64/kernel/topology.c
>>+++ b/arch/arm64/kernel/topology.c
>>@@ -240,13 +240,15 @@ unsigned int arch_freq_get_on_cpu(int cpu)
>>  	} while (read_seqcount_retry(&cpu_sample->seq, seq));
>>  	/*
>>-	 * Bail on invalid count and when the last update was too long ago,
>>-	 * which covers idle and NOHZ full CPUs.
>>+	 * Bail on invalid count and when the last update was too long ago.
>>+	 * This covers idle, NOHZ full and isolated CPUs.
>>+	 *
>>+	 * Idle CPUs don't need to be measured because AMU counters stop
>>+	 * incrementing during WFI/WFE.
>>  	 */
>>-	if (!delta_const_cnt || ((jiffies - last) > MAX_SAMPLE_AGE)) {
>>-		if (!(housekeeping_cpu(cpu, HK_TYPE_TICK) && idle_cpu(cpu)))
>>-			goto fallback;
>>-	}
>>+	if (!delta_const_cnt ||
>>+	    ((jiffies - last) > MAX_SAMPLE_AGE && !idle_cpu(cpu)))
>>+		goto fallback;
>>  	/*
>>  	 * CPU frequency = reference perf (in Hz) * (/\ delivered) / (/\ reference)
>[1] https://lore.kernel.org/linux-arm-kernel/20231212072617.14756-1-lihuisong@huawei.com/
>
Beata Michalska March 12, 2024, 8:44 a.m. UTC | #2
On Mon, Mar 11, 2024 at 11:27:27AM -0700, Vanshidhar Konda wrote:
> On Thu, Mar 07, 2024 at 11:17:26AM +0800, lihuisong (C) wrote:
> > 
> > 在 2024/3/1 0:25, Vanshidhar Konda 写道:
> > > AMU counters do not increment while a CPU is in idle. Saving the value
> > > of the core and constant counters prior to invoking WFI allows FIE to
> > > compute the frequency of a CPU that is idle.
> > > 
> > > Signed-off-by: Vanshidhar Konda <vanshikonda@os.amperecomputing.com>
> > > ---
> > >  arch/arm64/kernel/idle.c     | 10 ++++++++++
> > >  arch/arm64/kernel/topology.c | 14 ++++++++------
> > >  2 files changed, 18 insertions(+), 6 deletions(-)
> > > 
> > > diff --git a/arch/arm64/kernel/idle.c b/arch/arm64/kernel/idle.c
> > > index 05cfb347ec26..5ed2e57188a8 100644
> > > --- a/arch/arm64/kernel/idle.c
> > > +++ b/arch/arm64/kernel/idle.c
> > > @@ -26,6 +26,16 @@ void __cpuidle cpu_do_idle(void)
> > >  	arm_cpuidle_save_irq_context(&context);
> > > +#ifdef CONFIG_ARM64_AMU_EXTN
> > > +	/* Update the AMU counters before entering WFI. The cached AMU counter
> > > +	 * value is used to determine CPU frequency while the CPU is idle
> > > +	 * without needing to wake up the CPU.
> > > +	 */
> > > +
> > > +	if (cpu_has_amu_feat(smp_processor_id()))
> > > +		update_freq_counters_refs();
> > > +#endif
> > The below point I has mentioned in [1].
> > This is just for the WFI state.
> > What about other deeper idle states, like retention and power down?
> > The path to enter idle state is different for them. We should do this
> > for all idle states.
> > 
> 
> Yes. That makes sense. I'll account for them in the next version of the
> patch. I'll work on the next version of the patch based on the updated
> patch from @Beata.
> 
This should now be covered by [1]

---
[1]https://lore.kernel.org/all/20240312083431.3239989-4-beata.michalska@arm.com/

---
BR
Beata

> Thanks,
> Vanshi
> 
> > > +
> > >  	dsb(sy);
> > >  	wfi();
> > > diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
> > > index db8d14525cf4..8905eb0c681f 100644
> > > --- a/arch/arm64/kernel/topology.c
> > > +++ b/arch/arm64/kernel/topology.c
> > > @@ -240,13 +240,15 @@ unsigned int arch_freq_get_on_cpu(int cpu)
> > >  	} while (read_seqcount_retry(&cpu_sample->seq, seq));
> > >  	/*
> > > -	 * Bail on invalid count and when the last update was too long ago,
> > > -	 * which covers idle and NOHZ full CPUs.
> > > +	 * Bail on invalid count and when the last update was too long ago.
> > > +	 * This covers idle, NOHZ full and isolated CPUs.
> > > +	 *
> > > +	 * Idle CPUs don't need to be measured because AMU counters stop
> > > +	 * incrementing during WFI/WFE.
> > >  	 */
> > > -	if (!delta_const_cnt || ((jiffies - last) > MAX_SAMPLE_AGE)) {
> > > -		if (!(housekeeping_cpu(cpu, HK_TYPE_TICK) && idle_cpu(cpu)))
> > > -			goto fallback;
> > > -	}
> > > +	if (!delta_const_cnt ||
> > > +	    ((jiffies - last) > MAX_SAMPLE_AGE && !idle_cpu(cpu)))
> > > +		goto fallback;
> > >  	/*
> > >  	 * CPU frequency = reference perf (in Hz) * (/\ delivered) / (/\ reference)
> > [1] https://lore.kernel.org/linux-arm-kernel/20231212072617.14756-1-lihuisong@huawei.com/
> >
diff mbox series

Patch

diff --git a/arch/arm64/kernel/idle.c b/arch/arm64/kernel/idle.c
index 05cfb347ec26..5ed2e57188a8 100644
--- a/arch/arm64/kernel/idle.c
+++ b/arch/arm64/kernel/idle.c
@@ -26,6 +26,16 @@  void __cpuidle cpu_do_idle(void)
 
 	arm_cpuidle_save_irq_context(&context);
 
+#ifdef CONFIG_ARM64_AMU_EXTN
+	/* Update the AMU counters before entering WFI. The cached AMU counter
+	 * value is used to determine CPU frequency while the CPU is idle
+	 * without needing to wake up the CPU.
+	 */
+
+	if (cpu_has_amu_feat(smp_processor_id()))
+		update_freq_counters_refs();
+#endif
+
 	dsb(sy);
 	wfi();
 
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index db8d14525cf4..8905eb0c681f 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -240,13 +240,15 @@  unsigned int arch_freq_get_on_cpu(int cpu)
 	} while (read_seqcount_retry(&cpu_sample->seq, seq));
 
 	/*
-	 * Bail on invalid count and when the last update was too long ago,
-	 * which covers idle and NOHZ full CPUs.
+	 * Bail on invalid count and when the last update was too long ago.
+	 * This covers idle, NOHZ full and isolated CPUs.
+	 *
+	 * Idle CPUs don't need to be measured because AMU counters stop
+	 * incrementing during WFI/WFE.
 	 */
-	if (!delta_const_cnt || ((jiffies - last) > MAX_SAMPLE_AGE)) {
-		if (!(housekeeping_cpu(cpu, HK_TYPE_TICK) && idle_cpu(cpu)))
-			goto fallback;
-	}
+	if (!delta_const_cnt ||
+	    ((jiffies - last) > MAX_SAMPLE_AGE && !idle_cpu(cpu)))
+		goto fallback;
 
 	/*
 	 * CPU frequency = reference perf (in Hz) * (/\ delivered) / (/\ reference)