public inbox for linux-kernel@vger.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox