All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y
@ 2009-07-06 13:49 Martin Schwidefsky
  2009-07-06 14:07 ` Eric Dumazet
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Martin Schwidefsky @ 2009-07-06 13:49 UTC (permalink / raw)
  To: linux-kernel; +Cc: Ingo Molnar, Thomas Gleixner, john stultz

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

The generic ktime_get function defined in kernel/hrtimer.c is suboptimial
for GENERIC_TIME=y:

 0)               |  ktime_get() {
 0)               |    ktime_get_ts() {
 0)               |      getnstimeofday() {
 0)               |        read_tod_clock() {
 0)   0.601 us    |        }
 0)   1.938 us    |      }
 0)               |      set_normalized_timespec() {
 0)   0.602 us    |      }
 0)   4.375 us    |    }
 0)   5.523 us    |  }

Overall there are two read_seqbegin/read_seqretry loops and a lot of
unnecessary struct timespec calculations. ktime_get returns a nano second
value which is the sum of xtime, wall_to_monotonic and the nano second
delta from the clock source.

ktime_get can be optimized for GENERIC_TIME=y. The new version only calls
clocksource_read:

 0)               |  ktime_get() {
 0)               |    read_tod_clock() {
 0)   0.610 us    |    }
 0)   1.977 us    |  }

It uses a single read_seqbegin/readseqretry loop and just adds everthing
to a nano second value.

ktime_get_ts is optimized in a similar fashion.

Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: john stultz <johnstul@us.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---
 kernel/hrtimer.c          |    4 ++
 kernel/time/timekeeping.c |   63 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)


diff -urpN linux-2.5/kernel/hrtimer.c linux-2.5-patched/kernel/hrtimer.c
--- linux-2.5/kernel/hrtimer.c	2009-07-03 10:46:07.000000000 +0200
+++ linux-2.5-patched/kernel/hrtimer.c	2009-07-03 10:46:23.000000000 +0200
@@ -46,6 +46,7 @@
 
 #include <asm/uaccess.h>
 
+#ifndef CONFIG_GENERIC_TIME
 /**
  * ktime_get - get the monotonic time in ktime_t format
  *
@@ -60,6 +61,7 @@ ktime_t ktime_get(void)
 	return timespec_to_ktime(now);
 }
 EXPORT_SYMBOL_GPL(ktime_get);
+#endif
 
 /**
  * ktime_get_real - get the real (wall-) time in ktime_t format
@@ -104,6 +106,7 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, 
 	}
 };
 
+#ifndef CONFIG_GENERIC_TIME
 /**
  * ktime_get_ts - get the monotonic clock in timespec format
  * @ts:		pointer to timespec variable
@@ -128,6 +131,7 @@ void ktime_get_ts(struct timespec *ts)
 				ts->tv_nsec + tomono.tv_nsec);
 }
 EXPORT_SYMBOL_GPL(ktime_get_ts);
+#endif
 
 /*
  * Get the coarse grained time at the softirq based on xtime and
diff -urpN linux-2.5/kernel/time/timekeeping.c linux-2.5-patched/kernel/time/timekeeping.c
--- linux-2.5/kernel/time/timekeeping.c	2009-07-03 10:46:07.000000000 +0200
+++ linux-2.5-patched/kernel/time/timekeeping.c	2009-07-03 10:46:23.000000000 +0200
@@ -118,6 +118,69 @@ void getnstimeofday(struct timespec *ts)
 
 EXPORT_SYMBOL(getnstimeofday);
 
+ktime_t ktime_get(void)
+{
+	cycle_t cycle_now, cycle_delta;
+	struct timespec time;
+	unsigned long seq;
+	s64 nsecs;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		time.tv_sec = xtime.tv_sec + wall_to_monotonic.tv_sec;
+		time.tv_nsec = xtime.tv_nsec + wall_to_monotonic.tv_nsec;
+
+		/* read clocksource: */
+		cycle_now = clocksource_read(clock);
+
+		/* calculate the delta since the last update_wall_time: */
+		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+
+		/* convert to nanoseconds: */
+		nsecs = cyc2ns(clock, cycle_delta);
+
+	} while (read_seqretry(&xtime_lock, seq));
+	nsecs += time.tv_sec * 1000000000ULL + time.tv_nsec;
+	return (ktime_t) { .tv64 = nsecs };
+}
+EXPORT_SYMBOL_GPL(ktime_get);
+
+/**
+ * ktime_get_ts - get the monotonic clock in timespec format
+ * @ts:		pointer to timespec variable
+ *
+ * The function calculates the monotonic clock from the realtime
+ * clock and the wall_to_monotonic offset and stores the result
+ * in normalized timespec format in the variable pointed to by @ts.
+ */
+void ktime_get_ts(struct timespec *ts)
+{
+	cycle_t cycle_now, cycle_delta;
+	struct timespec tomono;
+	unsigned long seq;
+	s64 nsecs;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		*ts = xtime;
+		tomono = wall_to_monotonic;
+
+		/* read clocksource: */
+		cycle_now = clocksource_read(clock);
+
+		/* calculate the delta since the last update_wall_time: */
+		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+
+		/* convert to nanoseconds: */
+		nsecs = cyc2ns(clock, cycle_delta);
+
+	} while (read_seqretry(&xtime_lock, seq));
+
+	set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec,
+				ts->tv_nsec + tomono.tv_nsec + nsecs);
+}
+EXPORT_SYMBOL_GPL(ktime_get_ts);
+
 /**
  * do_gettimeofday - Returns the time of day in a timeval
  * @tv:		pointer to the timeval to be set


-- 
blue skies,
   Martin.

"Reality continues to ruin my life." - Calvin.


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

* Re: [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y
  2009-07-06 13:49 [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y Martin Schwidefsky
@ 2009-07-06 14:07 ` Eric Dumazet
  2009-07-06 14:15   ` Martin Schwidefsky
  2009-07-06 18:41 ` john stultz
  2009-07-06 20:31 ` Thomas Gleixner
  2 siblings, 1 reply; 9+ messages in thread
From: Eric Dumazet @ 2009-07-06 14:07 UTC (permalink / raw)
  To: Martin Schwidefsky
  Cc: linux-kernel, Ingo Molnar, Thomas Gleixner, john stultz

Martin Schwidefsky a écrit :
> From: Martin Schwidefsky <schwidefsky@de.ibm.com>
> 
> The generic ktime_get function defined in kernel/hrtimer.c is suboptimial
> for GENERIC_TIME=y:
> 
>  0)               |  ktime_get() {
>  0)               |    ktime_get_ts() {
>  0)               |      getnstimeofday() {
>  0)               |        read_tod_clock() {
>  0)   0.601 us    |        }
>  0)   1.938 us    |      }
>  0)               |      set_normalized_timespec() {
>  0)   0.602 us    |      }
>  0)   4.375 us    |    }
>  0)   5.523 us    |  }
> 
> Overall there are two read_seqbegin/read_seqretry loops and a lot of
> unnecessary struct timespec calculations. ktime_get returns a nano second
> value which is the sum of xtime, wall_to_monotonic and the nano second
> delta from the clock source.
> 
> ktime_get can be optimized for GENERIC_TIME=y. The new version only calls
> clocksource_read:
> 
>  0)               |  ktime_get() {
>  0)               |    read_tod_clock() {
>  0)   0.610 us    |    }
>  0)   1.977 us    |  }
> 
> It uses a single read_seqbegin/readseqretry loop and just adds everthing
> to a nano second value.
> 
> ktime_get_ts is optimized in a similar fashion.
> 
> Cc: Ingo Molnar <mingo@elte.hu>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: john stultz <johnstul@us.ibm.com>
> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
> ---
>  kernel/hrtimer.c          |    4 ++
>  kernel/time/timekeeping.c |   63 ++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 67 insertions(+)
> 
> 
> diff -urpN linux-2.5/kernel/hrtimer.c linux-2.5-patched/kernel/hrtimer.c
> --- linux-2.5/kernel/hrtimer.c	2009-07-03 10:46:07.000000000 +0200
> +++ linux-2.5-patched/kernel/hrtimer.c	2009-07-03 10:46:23.000000000 +0200
> @@ -46,6 +46,7 @@
>  
>  #include <asm/uaccess.h>
>  
> +#ifndef CONFIG_GENERIC_TIME
>  /**
>   * ktime_get - get the monotonic time in ktime_t format
>   *
> @@ -60,6 +61,7 @@ ktime_t ktime_get(void)
>  	return timespec_to_ktime(now);
>  }
>  EXPORT_SYMBOL_GPL(ktime_get);
> +#endif
>  
>  /**
>   * ktime_get_real - get the real (wall-) time in ktime_t format
> @@ -104,6 +106,7 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, 
>  	}
>  };
>  
> +#ifndef CONFIG_GENERIC_TIME
>  /**
>   * ktime_get_ts - get the monotonic clock in timespec format
>   * @ts:		pointer to timespec variable
> @@ -128,6 +131,7 @@ void ktime_get_ts(struct timespec *ts)
>  				ts->tv_nsec + tomono.tv_nsec);
>  }
>  EXPORT_SYMBOL_GPL(ktime_get_ts);
> +#endif
>  
>  /*
>   * Get the coarse grained time at the softirq based on xtime and
> diff -urpN linux-2.5/kernel/time/timekeeping.c linux-2.5-patched/kernel/time/timekeeping.c
> --- linux-2.5/kernel/time/timekeeping.c	2009-07-03 10:46:07.000000000 +0200
> +++ linux-2.5-patched/kernel/time/timekeeping.c	2009-07-03 10:46:23.000000000 +0200
> @@ -118,6 +118,69 @@ void getnstimeofday(struct timespec *ts)
>  
>  EXPORT_SYMBOL(getnstimeofday);
>  
> +ktime_t ktime_get(void)
> +{
> +	cycle_t cycle_now, cycle_delta;
> +	struct timespec time;
> +	unsigned long seq;
> +	s64 nsecs;
> +
> +	do {
> +		seq = read_seqbegin(&xtime_lock);

minor nit : read_seqbegin() returns an "unsigned int", not an "unsigned long"

But apparently, most callers store the value into an unsigned long... oh well...

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

* Re: [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y
  2009-07-06 14:07 ` Eric Dumazet
@ 2009-07-06 14:15   ` Martin Schwidefsky
  0 siblings, 0 replies; 9+ messages in thread
From: Martin Schwidefsky @ 2009-07-06 14:15 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: linux-kernel, Ingo Molnar, Thomas Gleixner, john stultz

On Mon, 06 Jul 2009 16:07:22 +0200
Eric Dumazet <eric.dumazet@gmail.com> wrote:

> > diff -urpN linux-2.5/kernel/time/timekeeping.c linux-2.5-patched/kernel/time/timekeeping.c
> > --- linux-2.5/kernel/time/timekeeping.c	2009-07-03 10:46:07.000000000 +0200
> > +++ linux-2.5-patched/kernel/time/timekeeping.c	2009-07-03 10:46:23.000000000 +0200
> > @@ -118,6 +118,69 @@ void getnstimeofday(struct timespec *ts)
> >  
> >  EXPORT_SYMBOL(getnstimeofday);
> >  
> > +ktime_t ktime_get(void)
> > +{
> > +	cycle_t cycle_now, cycle_delta;
> > +	struct timespec time;
> > +	unsigned long seq;
> > +	s64 nsecs;
> > +
> > +	do {
> > +		seq = read_seqbegin(&xtime_lock);  
> 
> minor nit : read_seqbegin() returns an "unsigned int", not an "unsigned long"
 
Hmm, just cut-copy-pasted the seq-loop. Seems like a job for the janitor ..
But I will update my patch.

-- 
blue skies,
   Martin.

"Reality continues to ruin my life." - Calvin.


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

* Re: [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y
  2009-07-06 13:49 [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y Martin Schwidefsky
  2009-07-06 14:07 ` Eric Dumazet
@ 2009-07-06 18:41 ` john stultz
  2009-07-06 20:31 ` Thomas Gleixner
  2 siblings, 0 replies; 9+ messages in thread
From: john stultz @ 2009-07-06 18:41 UTC (permalink / raw)
  To: Martin Schwidefsky; +Cc: linux-kernel, Ingo Molnar, Thomas Gleixner

On Mon, 2009-07-06 at 15:49 +0200, Martin Schwidefsky wrote:
> From: Martin Schwidefsky <schwidefsky@de.ibm.com>
> 
> The generic ktime_get function defined in kernel/hrtimer.c is suboptimial
> for GENERIC_TIME=y:
> 
>  0)               |  ktime_get() {
>  0)               |    ktime_get_ts() {
>  0)               |      getnstimeofday() {
>  0)               |        read_tod_clock() {
>  0)   0.601 us    |        }
>  0)   1.938 us    |      }
>  0)               |      set_normalized_timespec() {
>  0)   0.602 us    |      }
>  0)   4.375 us    |    }
>  0)   5.523 us    |  }
> 
> Overall there are two read_seqbegin/read_seqretry loops and a lot of
> unnecessary struct timespec calculations. ktime_get returns a nano second
> value which is the sum of xtime, wall_to_monotonic and the nano second
> delta from the clock source.
> 
> ktime_get can be optimized for GENERIC_TIME=y. The new version only calls
> clocksource_read:
> 
>  0)               |  ktime_get() {
>  0)               |    read_tod_clock() {
>  0)   0.610 us    |    }
>  0)   1.977 us    |  }
> 
> It uses a single read_seqbegin/readseqretry loop and just adds everthing
> to a nano second value.
> 
> ktime_get_ts is optimized in a similar fashion.
> 
> Cc: Ingo Molnar <mingo@elte.hu>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: john stultz <johnstul@us.ibm.com>
> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>


Looks good to me.
Acked-by: John Stultz <johnstul@us.ibm.com>


> ---
>  kernel/hrtimer.c          |    4 ++
>  kernel/time/timekeeping.c |   63 ++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 67 insertions(+)
> 
> 
> diff -urpN linux-2.5/kernel/hrtimer.c linux-2.5-patched/kernel/hrtimer.c
> --- linux-2.5/kernel/hrtimer.c	2009-07-03 10:46:07.000000000 +0200
> +++ linux-2.5-patched/kernel/hrtimer.c	2009-07-03 10:46:23.000000000 +0200
> @@ -46,6 +46,7 @@
> 
>  #include <asm/uaccess.h>
> 
> +#ifndef CONFIG_GENERIC_TIME
>  /**
>   * ktime_get - get the monotonic time in ktime_t format
>   *
> @@ -60,6 +61,7 @@ ktime_t ktime_get(void)
>  	return timespec_to_ktime(now);
>  }
>  EXPORT_SYMBOL_GPL(ktime_get);
> +#endif
> 
>  /**
>   * ktime_get_real - get the real (wall-) time in ktime_t format
> @@ -104,6 +106,7 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, 
>  	}
>  };
> 
> +#ifndef CONFIG_GENERIC_TIME
>  /**
>   * ktime_get_ts - get the monotonic clock in timespec format
>   * @ts:		pointer to timespec variable
> @@ -128,6 +131,7 @@ void ktime_get_ts(struct timespec *ts)
>  				ts->tv_nsec + tomono.tv_nsec);
>  }
>  EXPORT_SYMBOL_GPL(ktime_get_ts);
> +#endif
> 
>  /*
>   * Get the coarse grained time at the softirq based on xtime and
> diff -urpN linux-2.5/kernel/time/timekeeping.c linux-2.5-patched/kernel/time/timekeeping.c
> --- linux-2.5/kernel/time/timekeeping.c	2009-07-03 10:46:07.000000000 +0200
> +++ linux-2.5-patched/kernel/time/timekeeping.c	2009-07-03 10:46:23.000000000 +0200
> @@ -118,6 +118,69 @@ void getnstimeofday(struct timespec *ts)
> 
>  EXPORT_SYMBOL(getnstimeofday);
> 
> +ktime_t ktime_get(void)
> +{
> +	cycle_t cycle_now, cycle_delta;
> +	struct timespec time;
> +	unsigned long seq;
> +	s64 nsecs;
> +
> +	do {
> +		seq = read_seqbegin(&xtime_lock);
> +		time.tv_sec = xtime.tv_sec + wall_to_monotonic.tv_sec;
> +		time.tv_nsec = xtime.tv_nsec + wall_to_monotonic.tv_nsec;
> +
> +		/* read clocksource: */
> +		cycle_now = clocksource_read(clock);
> +
> +		/* calculate the delta since the last update_wall_time: */
> +		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
> +
> +		/* convert to nanoseconds: */
> +		nsecs = cyc2ns(clock, cycle_delta);
> +
> +	} while (read_seqretry(&xtime_lock, seq));
> +	nsecs += time.tv_sec * 1000000000ULL + time.tv_nsec;
> +	return (ktime_t) { .tv64 = nsecs };
> +}
> +EXPORT_SYMBOL_GPL(ktime_get);
> +
> +/**
> + * ktime_get_ts - get the monotonic clock in timespec format
> + * @ts:		pointer to timespec variable
> + *
> + * The function calculates the monotonic clock from the realtime
> + * clock and the wall_to_monotonic offset and stores the result
> + * in normalized timespec format in the variable pointed to by @ts.
> + */
> +void ktime_get_ts(struct timespec *ts)
> +{
> +	cycle_t cycle_now, cycle_delta;
> +	struct timespec tomono;
> +	unsigned long seq;
> +	s64 nsecs;
> +
> +	do {
> +		seq = read_seqbegin(&xtime_lock);
> +		*ts = xtime;
> +		tomono = wall_to_monotonic;
> +
> +		/* read clocksource: */
> +		cycle_now = clocksource_read(clock);
> +
> +		/* calculate the delta since the last update_wall_time: */
> +		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
> +
> +		/* convert to nanoseconds: */
> +		nsecs = cyc2ns(clock, cycle_delta);
> +
> +	} while (read_seqretry(&xtime_lock, seq));
> +
> +	set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec,
> +				ts->tv_nsec + tomono.tv_nsec + nsecs);
> +}
> +EXPORT_SYMBOL_GPL(ktime_get_ts);
> +
>  /**
>   * do_gettimeofday - Returns the time of day in a timeval
>   * @tv:		pointer to the timeval to be set
> 
> 


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

* Re: [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y
  2009-07-06 13:49 [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y Martin Schwidefsky
  2009-07-06 14:07 ` Eric Dumazet
  2009-07-06 18:41 ` john stultz
@ 2009-07-06 20:31 ` Thomas Gleixner
  2009-07-07  7:40   ` Martin Schwidefsky
  2 siblings, 1 reply; 9+ messages in thread
From: Thomas Gleixner @ 2009-07-06 20:31 UTC (permalink / raw)
  To: Martin Schwidefsky; +Cc: linux-kernel, Ingo Molnar, john stultz

On Mon, 6 Jul 2009, Martin Schwidefsky wrote:
> +ktime_t ktime_get(void)
> +{
> +	cycle_t cycle_now, cycle_delta;
> +	struct timespec time;
> +	unsigned long seq;
> +	s64 nsecs;
> +
> +	do {
> +		seq = read_seqbegin(&xtime_lock);
> +		time.tv_sec = xtime.tv_sec + wall_to_monotonic.tv_sec;
> +		time.tv_nsec = xtime.tv_nsec + wall_to_monotonic.tv_nsec;

That's actually a violation of the timespec semantics. tv_nsec can end
up greater than (10^9 - 1). Please use separate sec and nsec variables.

  	        secs = xtime.tv_sec + wall_to_monotonic.tv_sec;
  	     	nsecs = xtime.tv_nsec + wall_to_monotonic.tv_nsec;

> +		/* read clocksource: */
> +		cycle_now = clocksource_read(clock);
> +
> +		/* calculate the delta since the last update_wall_time: */
> +		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
> +
> +		/* convert to nanoseconds: */
> +		nsecs = cyc2ns(clock, cycle_delta);

So that needs to be changed to:

		nsecs += cyc2ns(clock, cycle_delta);

> +
> +	} while (read_seqretry(&xtime_lock, seq));
> +	nsecs += time.tv_sec * 1000000000ULL + time.tv_nsec;
> +	return (ktime_t) { .tv64 = nsecs };

This will break all 32bit architectures which do not have
CONFIG_KTIME_SCALAR set.

With the above changes applied:

  return ktime_add_ns(ktime_set(secs, 0), nsecs);

will do the trick. Might need some comments though :)

Thanks,

	tglx

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

* Re: [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y
  2009-07-06 20:31 ` Thomas Gleixner
@ 2009-07-07  7:40   ` Martin Schwidefsky
  2009-07-07  8:08     ` Thomas Gleixner
  0 siblings, 1 reply; 9+ messages in thread
From: Martin Schwidefsky @ 2009-07-07  7:40 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: linux-kernel, Ingo Molnar, john stultz

On Mon, 6 Jul 2009 22:31:39 +0200 (CEST)
Thomas Gleixner <tglx@linutronix.de> wrote:

> On Mon, 6 Jul 2009, Martin Schwidefsky wrote:
> > +ktime_t ktime_get(void)
> > +{
> > +	cycle_t cycle_now, cycle_delta;
> > +	struct timespec time;
> > +	unsigned long seq;
> > +	s64 nsecs;
> > +
> > +	do {
> > +		seq = read_seqbegin(&xtime_lock);
> > +		time.tv_sec = xtime.tv_sec + wall_to_monotonic.tv_sec;
> > +		time.tv_nsec = xtime.tv_nsec + wall_to_monotonic.tv_nsec;
> 
> That's actually a violation of the timespec semantics. tv_nsec can end
> up greater than (10^9 - 1). Please use separate sec and nsec variables.

Well the tv_sec/tv_nsec fields of a timespec are long values. But its
no problem to switch to local variables.

>   	        secs = xtime.tv_sec + wall_to_monotonic.tv_sec;
>   	     	nsecs = xtime.tv_nsec + wall_to_monotonic.tv_nsec;
> 
> > +		/* read clocksource: */
> > +		cycle_now = clocksource_read(clock);
> > +
> > +		/* calculate the delta since the last update_wall_time: */
> > +		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
> > +
> > +		/* convert to nanoseconds: */
> > +		nsecs = cyc2ns(clock, cycle_delta);
> 
> So that needs to be changed to:
> 
> 		nsecs += cyc2ns(clock, cycle_delta);

Ok.

> > +
> > +	} while (read_seqretry(&xtime_lock, seq));
> > +	nsecs += time.tv_sec * 1000000000ULL + time.tv_nsec;
> > +	return (ktime_t) { .tv64 = nsecs };
> 
> This will break all 32bit architectures which do not have
> CONFIG_KTIME_SCALAR set.

Yep, that is a bug.
 
> With the above changes applied:
> 
>   return ktime_add_ns(ktime_set(secs, 0), nsecs);
> 
> will do the trick. Might need some comments though :)

Ok, will update the patch. Thanks for the review.

-- 
blue skies,
   Martin.

"Reality continues to ruin my life." - Calvin.


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

* Re: [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y
  2009-07-07  7:40   ` Martin Schwidefsky
@ 2009-07-07  8:08     ` Thomas Gleixner
  2009-07-07  9:27       ` Martin Schwidefsky
  0 siblings, 1 reply; 9+ messages in thread
From: Thomas Gleixner @ 2009-07-07  8:08 UTC (permalink / raw)
  To: Martin Schwidefsky; +Cc: linux-kernel, Ingo Molnar, john stultz

Martin,

On Tue, 7 Jul 2009, Martin Schwidefsky wrote:
> On Mon, 6 Jul 2009 22:31:39 +0200 (CEST)
> Thomas Gleixner <tglx@linutronix.de> wrote:
> 
> > On Mon, 6 Jul 2009, Martin Schwidefsky wrote:
> > > +ktime_t ktime_get(void)
> > > +{
> > > +	cycle_t cycle_now, cycle_delta;
> > > +	struct timespec time;
> > > +	unsigned long seq;
> > > +	s64 nsecs;
> > > +
> > > +	do {
> > > +		seq = read_seqbegin(&xtime_lock);
> > > +		time.tv_sec = xtime.tv_sec + wall_to_monotonic.tv_sec;
> > > +		time.tv_nsec = xtime.tv_nsec + wall_to_monotonic.tv_nsec;
> > 
> > That's actually a violation of the timespec semantics. tv_nsec can end
> > up greater than (10^9 - 1). Please use separate sec and nsec variables.
> 
> Well the tv_sec/tv_nsec fields of a timespec are long values. But its
> no problem to switch to local variables.

Right. I'm not worried about an overflow of the variable. I was about
to suggest using timespec_to_ktime() to fix the !SCALAR problem when I
noticed that the timespec is possibly not normalized. Not using a
timespec makes the code more obvious I think.

Thanks,

	tglx


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

* Re: [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y
  2009-07-07  8:08     ` Thomas Gleixner
@ 2009-07-07  9:27       ` Martin Schwidefsky
  2009-07-07 12:06         ` [tip:timers/core] timekeeping: " tip-bot for Martin Schwidefsky
  0 siblings, 1 reply; 9+ messages in thread
From: Martin Schwidefsky @ 2009-07-07  9:27 UTC (permalink / raw)
  To: Thomas Gleixner; +Cc: linux-kernel, Ingo Molnar, john stultz

On Tue, 7 Jul 2009 10:08:56 +0200 (CEST)
Thomas Gleixner <tglx@linutronix.de> wrote:

> Martin,
> 
> On Tue, 7 Jul 2009, Martin Schwidefsky wrote:
> > On Mon, 6 Jul 2009 22:31:39 +0200 (CEST)
> > Thomas Gleixner <tglx@linutronix.de> wrote:
> > 
> > > On Mon, 6 Jul 2009, Martin Schwidefsky wrote:
> > > > +ktime_t ktime_get(void)
> > > > +{
> > > > +	cycle_t cycle_now, cycle_delta;
> > > > +	struct timespec time;
> > > > +	unsigned long seq;
> > > > +	s64 nsecs;
> > > > +
> > > > +	do {
> > > > +		seq = read_seqbegin(&xtime_lock);
> > > > +		time.tv_sec = xtime.tv_sec + wall_to_monotonic.tv_sec;
> > > > +		time.tv_nsec = xtime.tv_nsec + wall_to_monotonic.tv_nsec;
> > > 
> > > That's actually a violation of the timespec semantics. tv_nsec can end
> > > up greater than (10^9 - 1). Please use separate sec and nsec variables.
> > 
> > Well the tv_sec/tv_nsec fields of a timespec are long values. But its
> > no problem to switch to local variables.
> 
> Right. I'm not worried about an overflow of the variable. I was about
> to suggest using timespec_to_ktime() to fix the !SCALAR problem when I
> noticed that the timespec is possibly not normalized. Not using a
> timespec makes the code more obvious I think.

That makes sense. New patch:

--
Subject: [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

The generic ktime_get function defined in kernel/hrtimer.c is suboptimial
for GENERIC_TIME=y:

 0)               |  ktime_get() {
 0)               |    ktime_get_ts() {
 0)               |      getnstimeofday() {
 0)               |        read_tod_clock() {
 0)   0.601 us    |        }
 0)   1.938 us    |      }
 0)               |      set_normalized_timespec() {
 0)   0.602 us    |      }
 0)   4.375 us    |    }
 0)   5.523 us    |  }

Overall there are two read_seqbegin/read_seqretry loops and a lot of
unnecessary struct timespec calculations. ktime_get returns a nano second
value which is the sum of xtime, wall_to_monotonic and the nano second
delta from the clock source.

ktime_get can be optimized for GENERIC_TIME=y. The new version only calls
clocksource_read:

 0)               |  ktime_get() {
 0)               |    read_tod_clock() {
 0)   0.610 us    |    }
 0)   1.977 us    |  }

It uses a single read_seqbegin/readseqretry loop and just adds everthing
to a nano second value.

ktime_get_ts is optimized in a similar fashion.

Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Acked-by: john stultz <johnstul@us.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---

 kernel/hrtimer.c          |    4 ++
 kernel/time/timekeeping.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)

diff -urpN linux-2.6/kernel/hrtimer.c linux-2.6-patched/kernel/hrtimer.c
--- linux-2.6/kernel/hrtimer.c	2009-07-07 11:24:29.000000000 +0200
+++ linux-2.6-patched/kernel/hrtimer.c	2009-07-07 11:24:37.000000000 +0200
@@ -48,6 +48,7 @@
 
 #include <asm/uaccess.h>
 
+#ifndef CONFIG_GENERIC_TIME
 /**
  * ktime_get - get the monotonic time in ktime_t format
  *
@@ -62,6 +63,7 @@ ktime_t ktime_get(void)
 	return timespec_to_ktime(now);
 }
 EXPORT_SYMBOL_GPL(ktime_get);
+#endif
 
 /**
  * ktime_get_real - get the real (wall-) time in ktime_t format
@@ -106,6 +108,7 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, 
 	}
 };
 
+#ifndef CONFIG_GENERIC_TIME
 /**
  * ktime_get_ts - get the monotonic clock in timespec format
  * @ts:		pointer to timespec variable
@@ -130,6 +133,7 @@ void ktime_get_ts(struct timespec *ts)
 				ts->tv_nsec + tomono.tv_nsec);
 }
 EXPORT_SYMBOL_GPL(ktime_get_ts);
+#endif
 
 /*
  * Get the coarse grained time at the softirq based on xtime and
diff -urpN linux-2.6/kernel/time/timekeeping.c linux-2.6-patched/kernel/time/timekeeping.c
--- linux-2.6/kernel/time/timekeeping.c	2009-07-07 11:24:29.000000000 +0200
+++ linux-2.6-patched/kernel/time/timekeeping.c	2009-07-07 11:24:37.000000000 +0200
@@ -125,6 +125,71 @@ void getnstimeofday(struct timespec *ts)
 
 EXPORT_SYMBOL(getnstimeofday);
 
+ktime_t ktime_get(void)
+{
+	cycle_t cycle_now, cycle_delta;
+	unsigned int seq;
+	s64 secs, nsecs;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		secs = xtime.tv_sec + wall_to_monotonic.tv_sec;
+		nsecs = xtime.tv_nsec + wall_to_monotonic.tv_nsec;
+
+		/* read clocksource: */
+		cycle_now = clocksource_read(clock);
+
+		/* calculate the delta since the last update_wall_time: */
+		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+
+		/* convert to nanoseconds: */
+		nsecs += cyc2ns(clock, cycle_delta);
+
+	} while (read_seqretry(&xtime_lock, seq));
+	/*
+	 * Use ktime_set/ktime_add_ns to create a proper ktime on
+	 * 32-bit architectures without CONFIG_KTIME_SCALAR.
+	 */
+	return ktime_add_ns(ktime_set(secs, 0), nsecs);
+}
+EXPORT_SYMBOL_GPL(ktime_get);
+
+/**
+ * ktime_get_ts - get the monotonic clock in timespec format
+ * @ts:		pointer to timespec variable
+ *
+ * The function calculates the monotonic clock from the realtime
+ * clock and the wall_to_monotonic offset and stores the result
+ * in normalized timespec format in the variable pointed to by @ts.
+ */
+void ktime_get_ts(struct timespec *ts)
+{
+	cycle_t cycle_now, cycle_delta;
+	struct timespec tomono;
+	unsigned int seq;
+	s64 nsecs;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		*ts = xtime;
+		tomono = wall_to_monotonic;
+
+		/* read clocksource: */
+		cycle_now = clocksource_read(clock);
+
+		/* calculate the delta since the last update_wall_time: */
+		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+
+		/* convert to nanoseconds: */
+		nsecs = cyc2ns(clock, cycle_delta);
+
+	} while (read_seqretry(&xtime_lock, seq));
+
+	set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec,
+				ts->tv_nsec + tomono.tv_nsec + nsecs);
+}
+EXPORT_SYMBOL_GPL(ktime_get_ts);
+
 /**
  * do_gettimeofday - Returns the time of day in a timeval
  * @tv:		pointer to the timeval to be set



-- 
blue skies,
   Martin.

"Reality continues to ruin my life." - Calvin.


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

* [tip:timers/core] timekeeping: optimized ktime_get[_ts] for GENERIC_TIME=y
  2009-07-07  9:27       ` Martin Schwidefsky
@ 2009-07-07 12:06         ` tip-bot for Martin Schwidefsky
  0 siblings, 0 replies; 9+ messages in thread
From: tip-bot for Martin Schwidefsky @ 2009-07-07 12:06 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, johnstul, schwidefsky, tglx

Commit-ID:  951ed4d36b77ba9fe1ea08fc3c59d8bb6c9bda32
Gitweb:     http://git.kernel.org/tip/951ed4d36b77ba9fe1ea08fc3c59d8bb6c9bda32
Author:     Martin Schwidefsky <schwidefsky@de.ibm.com>
AuthorDate: Tue, 7 Jul 2009 11:27:28 +0200
Committer:  Thomas Gleixner <tglx@linutronix.de>
CommitDate: Tue, 7 Jul 2009 12:47:33 +0200

timekeeping: optimized ktime_get[_ts] for GENERIC_TIME=y

The generic ktime_get function defined in kernel/hrtimer.c is suboptimial
for GENERIC_TIME=y:

 0)               |  ktime_get() {
 0)               |    ktime_get_ts() {
 0)               |      getnstimeofday() {
 0)               |        read_tod_clock() {
 0)   0.601 us    |        }
 0)   1.938 us    |      }
 0)               |      set_normalized_timespec() {
 0)   0.602 us    |      }
 0)   4.375 us    |    }
 0)   5.523 us    |  }

Overall there are two read_seqbegin/read_seqretry loops and a lot of
unnecessary struct timespec calculations. ktime_get returns a nano second
value which is the sum of xtime, wall_to_monotonic and the nano second
delta from the clock source.

ktime_get can be optimized for GENERIC_TIME=y. The new version only calls
clocksource_read:

 0)               |  ktime_get() {
 0)               |    read_tod_clock() {
 0)   0.610 us    |    }
 0)   1.977 us    |  }

It uses a single read_seqbegin/readseqretry loop and just adds everthing
to a nano second value.

ktime_get_ts is optimized in a similar fashion.

[ tglx: added WARN_ON(timekeeping_suspended) as in getnstimeofday() ]

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Acked-by: john stultz <johnstul@us.ibm.com>
LKML-Reference: <20090707112728.3005244d@skybase>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>


---
 kernel/hrtimer.c          |    4 ++
 kernel/time/timekeeping.c |   69 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 73 insertions(+), 0 deletions(-)

diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 9002958..829e066 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -48,6 +48,7 @@
 
 #include <asm/uaccess.h>
 
+#ifndef CONFIG_GENERIC_TIME
 /**
  * ktime_get - get the monotonic time in ktime_t format
  *
@@ -62,6 +63,7 @@ ktime_t ktime_get(void)
 	return timespec_to_ktime(now);
 }
 EXPORT_SYMBOL_GPL(ktime_get);
+#endif
 
 /**
  * ktime_get_real - get the real (wall-) time in ktime_t format
@@ -106,6 +108,7 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
 	}
 };
 
+#ifndef CONFIG_GENERIC_TIME
 /**
  * ktime_get_ts - get the monotonic clock in timespec format
  * @ts:		pointer to timespec variable
@@ -130,6 +133,7 @@ void ktime_get_ts(struct timespec *ts)
 				ts->tv_nsec + tomono.tv_nsec);
 }
 EXPORT_SYMBOL_GPL(ktime_get_ts);
+#endif
 
 /*
  * Get the coarse grained time at the softirq based on xtime and
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index e8c77d9..7a24813 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -125,6 +125,75 @@ void getnstimeofday(struct timespec *ts)
 
 EXPORT_SYMBOL(getnstimeofday);
 
+ktime_t ktime_get(void)
+{
+	cycle_t cycle_now, cycle_delta;
+	unsigned int seq;
+	s64 secs, nsecs;
+
+	WARN_ON(timekeeping_suspended);
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		secs = xtime.tv_sec + wall_to_monotonic.tv_sec;
+		nsecs = xtime.tv_nsec + wall_to_monotonic.tv_nsec;
+
+		/* read clocksource: */
+		cycle_now = clocksource_read(clock);
+
+		/* calculate the delta since the last update_wall_time: */
+		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+
+		/* convert to nanoseconds: */
+		nsecs += cyc2ns(clock, cycle_delta);
+
+	} while (read_seqretry(&xtime_lock, seq));
+	/*
+	 * Use ktime_set/ktime_add_ns to create a proper ktime on
+	 * 32-bit architectures without CONFIG_KTIME_SCALAR.
+	 */
+	return ktime_add_ns(ktime_set(secs, 0), nsecs);
+}
+EXPORT_SYMBOL_GPL(ktime_get);
+
+/**
+ * ktime_get_ts - get the monotonic clock in timespec format
+ * @ts:		pointer to timespec variable
+ *
+ * The function calculates the monotonic clock from the realtime
+ * clock and the wall_to_monotonic offset and stores the result
+ * in normalized timespec format in the variable pointed to by @ts.
+ */
+void ktime_get_ts(struct timespec *ts)
+{
+	cycle_t cycle_now, cycle_delta;
+	struct timespec tomono;
+	unsigned int seq;
+	s64 nsecs;
+
+	WARN_ON(timekeeping_suspended);
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		*ts = xtime;
+		tomono = wall_to_monotonic;
+
+		/* read clocksource: */
+		cycle_now = clocksource_read(clock);
+
+		/* calculate the delta since the last update_wall_time: */
+		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+
+		/* convert to nanoseconds: */
+		nsecs = cyc2ns(clock, cycle_delta);
+
+	} while (read_seqretry(&xtime_lock, seq));
+
+	set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec,
+				ts->tv_nsec + tomono.tv_nsec + nsecs);
+}
+EXPORT_SYMBOL_GPL(ktime_get_ts);
+
 /**
  * do_gettimeofday - Returns the time of day in a timeval
  * @tv:		pointer to the timeval to be set

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

end of thread, other threads:[~2009-07-07 12:07 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-07-06 13:49 [PATCH] optimized ktime_get[_ts] for GENERIC_TIME=y Martin Schwidefsky
2009-07-06 14:07 ` Eric Dumazet
2009-07-06 14:15   ` Martin Schwidefsky
2009-07-06 18:41 ` john stultz
2009-07-06 20:31 ` Thomas Gleixner
2009-07-07  7:40   ` Martin Schwidefsky
2009-07-07  8:08     ` Thomas Gleixner
2009-07-07  9:27       ` Martin Schwidefsky
2009-07-07 12:06         ` [tip:timers/core] timekeeping: " tip-bot for Martin Schwidefsky

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.