diff mbox series

[3/3] oslat: Allow for arch specific timer frequency measurements

Message ID 20210908100209.118609-3-nsaenzju@redhat.com
State New
Headers show
Series [1/3] oslat: rename cpu_mhz/cpu_hz to timer_mhz/cpu_hz | expand

Commit Message

Nicolas Saenz Julienne Sept. 8, 2021, 10:02 a.m. UTC
Some architectures have special purpose registers to query the system
timer's frequency. Let's use that when available.

Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
---
 src/oslat/oslat.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

Comments

Nicolas Saenz Julienne Sept. 9, 2021, 10:29 a.m. UTC | #1
On Wed, 2021-09-08 at 14:16 -0400, Peter Xu wrote:
> On Wed, Sep 08, 2021 at 12:02:09PM +0200, Nicolas Saenz Julienne wrote:

> > Some architectures have special purpose registers to query the system

> > timer's frequency. Let's use that when available.

> > 

> > Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>

> > ---

> >  src/oslat/oslat.c | 20 +++++++++++++++++++-

> >  1 file changed, 19 insertions(+), 1 deletion(-)

> > 

> > diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c

> > index bd155a6..23ca9b6 100644

> > --- a/src/oslat/oslat.c

> > +++ b/src/oslat/oslat.c

> > @@ -51,6 +51,9 @@

> >  # define atomic_inc(ptr)   __sync_add_and_fetch((ptr), 1)

> >  # if defined(__x86_64__)

> >  #  define relax()          __asm__ __volatile__("pause" ::: "memory")

> > +

> > +#define measure_timer_mhz generic_measure_timer_mhz

> > +

> >  static inline void frc(uint64_t *pval)

> >  {

> >  	uint32_t low, high;

> > @@ -61,12 +64,18 @@ static inline void frc(uint64_t *pval)

> >  }

> >  # elif defined(__i386__)

> >  #  define relax()          __asm__ __volatile__("pause" ::: "memory")

> > +

> > +#define measure_timer_mhz generic_measure_timer_mhz

> > +

> >  static inline void frc(uint64_t *pval)

> >  {

> >  	__asm__ __volatile__("rdtsc" : "=A" (*pval));

> >  }

> >  # elif defined(__PPC64__)

> >  #  define relax()          do { } while (0)

> > +

> > +#define measure_timer_mhz generic_measure_timer_mhz

> > +

> >  static inline void frc(uint64_t *pval)

> >  {

> >  	__asm__ __volatile__("mfspr %0, 268\n" : "=r" (*pval));

> > @@ -74,6 +83,15 @@ static inline void frc(uint64_t *pval)

> >  # elif defined(__aarch64__)

> >  #  define relax()          __asm__ __volatile("yield" : : : "memory")

> >  

> > +static inline unsigned int measure_timer_mhz(void)

> > +{

> > +	unsigned int val;

> > +

> > +	__asm__ __volatile__("mrs %0, cntfrq_el0" : "=r" (val));

> > +

> > +	return val / 1e6;

> > +}

> > +

> >  static inline void frc(uint64_t *pval)

> >  {

> >  

> > @@ -257,7 +275,7 @@ static cycles_t __measure_timer_hz(void)

> >  	return (cycles_t) ((e - s) / sec);

> >  }

> >  

> > -static unsigned int measure_timer_mhz(void)

> > +static unsigned int __attribute__((unused)) generic_measure_timer_mhz(void)

> 

> This is okay I guess, but does not look nice, as it's marked unused even if

> it's used..


Yes the compiler attribute naming is unfortunate. That's why the kernel renamed
it to '__maybe_unused'.

> How about for any arch that supports a faster version to read the freq, do:

> 

> #define measure_timer_mhz_fast

> unsigned int measure_timer_mhz_fast(void)

> {

>     ...

> }

> 

> Then at entry of measure_timer_mhz():

> 

> #ifdef measure_timer_mhz_fast

>     return measure_timer_mhz_fast();

> #endif


Sounds good to me.

> I'm also wondering the diff between the two methods on arm64 and whether

> there's a huge difference on the numbers.


There isn't much, after rounding the end result in MHz is the same regardless
of the method used. IIUC, gettimeoftheday() uses the frequency register's value
to scale the counter measurements. So it makes sense for the results to be
coherent.

I figured it's cleaner to get the data from the source instead of inferring it
with extra math.

-- 
Nicolás Sáenz
Peter Xu Sept. 9, 2021, 6:04 p.m. UTC | #2
On Thu, Sep 09, 2021 at 12:29:17PM +0200, nsaenzju@redhat.com wrote:
> > I'm also wondering the diff between the two methods on arm64 and whether

> > there's a huge difference on the numbers.

> 

> There isn't much, after rounding the end result in MHz is the same regardless

> of the method used. IIUC, gettimeoftheday() uses the frequency register's value

> to scale the counter measurements. So it makes sense for the results to be

> coherent.

> 

> I figured it's cleaner to get the data from the source instead of inferring it

> with extra math.


Fair enough.  Thanks,

-- 
Peter Xu
diff mbox series

Patch

diff --git a/src/oslat/oslat.c b/src/oslat/oslat.c
index bd155a6..23ca9b6 100644
--- a/src/oslat/oslat.c
+++ b/src/oslat/oslat.c
@@ -51,6 +51,9 @@ 
 # define atomic_inc(ptr)   __sync_add_and_fetch((ptr), 1)
 # if defined(__x86_64__)
 #  define relax()          __asm__ __volatile__("pause" ::: "memory")
+
+#define measure_timer_mhz generic_measure_timer_mhz
+
 static inline void frc(uint64_t *pval)
 {
 	uint32_t low, high;
@@ -61,12 +64,18 @@  static inline void frc(uint64_t *pval)
 }
 # elif defined(__i386__)
 #  define relax()          __asm__ __volatile__("pause" ::: "memory")
+
+#define measure_timer_mhz generic_measure_timer_mhz
+
 static inline void frc(uint64_t *pval)
 {
 	__asm__ __volatile__("rdtsc" : "=A" (*pval));
 }
 # elif defined(__PPC64__)
 #  define relax()          do { } while (0)
+
+#define measure_timer_mhz generic_measure_timer_mhz
+
 static inline void frc(uint64_t *pval)
 {
 	__asm__ __volatile__("mfspr %0, 268\n" : "=r" (*pval));
@@ -74,6 +83,15 @@  static inline void frc(uint64_t *pval)
 # elif defined(__aarch64__)
 #  define relax()          __asm__ __volatile("yield" : : : "memory")
 
+static inline unsigned int measure_timer_mhz(void)
+{
+	unsigned int val;
+
+	__asm__ __volatile__("mrs %0, cntfrq_el0" : "=r" (val));
+
+	return val / 1e6;
+}
+
 static inline void frc(uint64_t *pval)
 {
 
@@ -257,7 +275,7 @@  static cycles_t __measure_timer_hz(void)
 	return (cycles_t) ((e - s) / sec);
 }
 
-static unsigned int measure_timer_mhz(void)
+static unsigned int __attribute__((unused)) generic_measure_timer_mhz(void)
 {
 	cycles_t m, mprev, d;