diff mbox series

[v2] timekeeping: get_jiffies_boot_64() for jiffies that include sleep time

Message ID 20190619142350.1985-1-Jason@zx2c4.com
State New
Headers show
Series [v2] timekeeping: get_jiffies_boot_64() for jiffies that include sleep time | expand

Commit Message

Jason A. Donenfeld June 19, 2019, 2:23 p.m. UTC
This enables using the usual get_jiffies_64() but taking into account
time spent sleeping, giving the high performance characteristics of
querying jiffies without the drawback.

We accomplish this by precomputing the boottime jiffies offset whenever
it is updated, rather than doing the expensive-ish div_u64 on each
query.

Since the resolution of this is in terms of jiffies, this allows
determining limits for comparison in terms of jiffies too, which makes
the comparisons more exact, despite jiffies being a fairly coarse stamp.

Adding the suspend offset to jiffies as such doesn't actually race in a
way different from the usual races associated with the suspend offset:
either boot offset has been updated before the call to
get_jiffies_boot_64(), in which case we're fine, or it hasn't in which
case, this is no different than any of the existing suspend querying
functions, which may be invoked early in system resumption before the
offset is updated.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc; John Stultz <john.stultz@linaro.org>
---
 include/linux/jiffies.h             |  1 +
 include/linux/timekeeper_internal.h |  2 ++
 kernel/time/timekeeping.c           | 11 +++++++++++
 3 files changed, 14 insertions(+)

-- 
2.21.0

Comments

Arnd Bergmann June 19, 2019, 2:41 p.m. UTC | #1
On Wed, Jun 19, 2019 at 4:24 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>

> This enables using the usual get_jiffies_64() but taking into account

> time spent sleeping, giving the high performance characteristics of

> querying jiffies without the drawback.


Can you quantify how much this gains you over ktime_get_coarse_boottime
in practice? You are effectively adding yet another abstraction for time,
which is something I'd hope to avoid unless you have a strong reason other
than it being faster in theory.

How often do you read the current time?

      Arnd
Jason A. Donenfeld June 19, 2019, 3:31 p.m. UTC | #2
Hi Arnd,

On Wed, Jun 19, 2019 at 5:08 PM Arnd Bergmann <arnd@arndb.de> wrote:
> Can you quantify how much this gains you over ktime_get_coarse_boottime

> in practice? You are effectively adding yet another abstraction for time,

> which is something I'd hope to avoid unless you have a strong reason other

> than it being faster in theory.


Excellent idea. It turns out to be precisely 0 (see below). A
motivation still remains, though: this allows comparison with units
specified in terms of jiffies, which means that the unit being
compared matches the exact tick of the clock, making those comparisons
as precise as possible, for what they are. I suppose you could argue,
on the other hand, that nanoseconds give so much precision already,
that approximations using them amount practically to the same thing.
I'm not sure which way to reason about that.

For interest, here are a few comparisons taken with kbench9000:

get_jiffies_boot_64 26
ktime_get_coarse_boottime 26
ktime_get_boot_fast_ns with tsc 70
ktime_get_boot_fast_ns with hpet 4922
ktime_get_boot_fast_ns with acpi_pm 1884

As expected, hpet is really quite painful.

Jason
Arnd Bergmann June 19, 2019, 8:02 p.m. UTC | #3
On Wed, Jun 19, 2019 at 5:31 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>

> Hi Arnd,

>

> On Wed, Jun 19, 2019 at 5:08 PM Arnd Bergmann <arnd@arndb.de> wrote:

> > Can you quantify how much this gains you over ktime_get_coarse_boottime

> > in practice? You are effectively adding yet another abstraction for time,

> > which is something I'd hope to avoid unless you have a strong reason other

> > than it being faster in theory.

>

> Excellent idea. It turns out to be precisely 0 (see below). A

> motivation still remains, though: this allows comparison with units

> specified in terms of jiffies, which means that the unit being

> compared matches the exact tick of the clock, making those comparisons

> as precise as possible, for what they are. I suppose you could argue,

> on the other hand, that nanoseconds give so much precision already,

> that approximations using them amount practically to the same thing.

> I'm not sure which way to reason about that.

>

> For interest, here are a few comparisons taken with kbench9000:

>

> get_jiffies_boot_64 26

> ktime_get_coarse_boottime 26

> ktime_get_boot_fast_ns with tsc 70

> ktime_get_boot_fast_ns with hpet 4922

> ktime_get_boot_fast_ns with acpi_pm 1884

>

> As expected, hpet is really quite painful.


I would prefer not to add the new interface then. We might in
fact move users of get_jiffies_64() to ktime_get_coarse() for
consistency given the small overhead of that function.

      Arnd
Jason A. Donenfeld June 19, 2019, 8:06 p.m. UTC | #4
On Wed, Jun 19, 2019 at 10:02 PM Arnd Bergmann <arnd@arndb.de> wrote:
> > get_jiffies_boot_64 26

> > ktime_get_coarse_boottime 26

> > ktime_get_boot_fast_ns with tsc 70

> > ktime_get_boot_fast_ns with hpet 4922

> > ktime_get_boot_fast_ns with acpi_pm 1884

> >

> > As expected, hpet is really quite painful.

>

> I would prefer not to add the new interface then. We might in

> fact move users of get_jiffies_64() to ktime_get_coarse() for

> consistency given the small overhead of that function.


In light of the measurements, that seems like a good plan to me.

One thing to consider with moving jiffies users over that way is
ktime_t. Do you want to introduce helpers like
ktime_get_boot_coarse_ns(), just like there is already with the other
various functions like ktime_get_boot_ns(), ktime_get_boot_fast_ns(),
etc? (I'd personally prefer using the _ns variants, at least.) I can
send a patch for this.

Jason
Arnd Bergmann June 19, 2019, 8:57 p.m. UTC | #5
On Wed, Jun 19, 2019 at 10:07 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>

> On Wed, Jun 19, 2019 at 10:02 PM Arnd Bergmann <arnd@arndb.de> wrote:

> > > get_jiffies_boot_64 26

> > > ktime_get_coarse_boottime 26

> > > ktime_get_boot_fast_ns with tsc 70

> > > ktime_get_boot_fast_ns with hpet 4922

> > > ktime_get_boot_fast_ns with acpi_pm 1884

> > >

> > > As expected, hpet is really quite painful.

> >

> > I would prefer not to add the new interface then. We might in

> > fact move users of get_jiffies_64() to ktime_get_coarse() for

> > consistency given the small overhead of that function.

>

> In light of the measurements, that seems like a good plan to me.

>

> One thing to consider with moving jiffies users over that way is

> ktime_t. Do you want to introduce helpers like

> ktime_get_boot_coarse_ns(), just like there is already with the other

> various functions like ktime_get_boot_ns(), ktime_get_boot_fast_ns(),

> etc? (I'd personally prefer using the _ns variants, at least.) I can

> send a patch for this.


That sounds reasonable, but then I think we should have the full
set of coarse_*_ns() functions, again for consistency:

                u64 ktime_get_coarse_ns(void)
                u64 ktime_get_coarse_boottime_ns(void)
                u64 ktime_get_coarse_real_ns(void)
                u64 ktime_get_coarse_clocktai_ns(void)

and document them in Documentation/core-api/timekeeping.rst.

We seem to also be lacking the basic ktime_get_coarse(), which
seems like a major omission.
Both ktime_get_coarse_ns and ktime_get_coarse can be wrappers
around ktime_get_coarse_ts64() then, while the others would
use ktime_get_coarse_with_offset().

       Arnd
Jason A. Donenfeld June 20, 2019, 1:24 p.m. UTC | #6
On Wed, Jun 19, 2019 at 10:57 PM Arnd Bergmann <arnd@arndb.de> wrote:
>

> On Wed, Jun 19, 2019 at 10:07 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:

> >

> > On Wed, Jun 19, 2019 at 10:02 PM Arnd Bergmann <arnd@arndb.de> wrote:

> > > > get_jiffies_boot_64 26

> > > > ktime_get_coarse_boottime 26

> > > > ktime_get_boot_fast_ns with tsc 70

> > > > ktime_get_boot_fast_ns with hpet 4922

> > > > ktime_get_boot_fast_ns with acpi_pm 1884

> > > >

> > > > As expected, hpet is really quite painful.

> > >

> > > I would prefer not to add the new interface then. We might in

> > > fact move users of get_jiffies_64() to ktime_get_coarse() for

> > > consistency given the small overhead of that function.

> >

> > In light of the measurements, that seems like a good plan to me.

> >

> > One thing to consider with moving jiffies users over that way is

> > ktime_t. Do you want to introduce helpers like

> > ktime_get_boot_coarse_ns(), just like there is already with the other

> > various functions like ktime_get_boot_ns(), ktime_get_boot_fast_ns(),

> > etc? (I'd personally prefer using the _ns variants, at least.) I can

> > send a patch for this.

>

> That sounds reasonable, but then I think we should have the full

> set of coarse_*_ns() functions, again for consistency:

>

>                 u64 ktime_get_coarse_ns(void)

>                 u64 ktime_get_coarse_boottime_ns(void)

>                 u64 ktime_get_coarse_real_ns(void)

>                 u64 ktime_get_coarse_clocktai_ns(void)

>

> and document them in Documentation/core-api/timekeeping.rst.

>

> We seem to also be lacking the basic ktime_get_coarse(), which

> seems like a major omission.

> Both ktime_get_coarse_ns and ktime_get_coarse can be wrappers

> around ktime_get_coarse_ts64() then, while the others would

> use ktime_get_coarse_with_offset().


Exactly what I had in mind. I'll have something posted fairly soon.

Jason
diff mbox series

Patch

diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index 1b6d31da7cbc..e4a9776d8b2a 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -80,6 +80,7 @@  extern int register_refined_jiffies(long clock_tick_rate);
 extern u64 __cacheline_aligned_in_smp jiffies_64;
 extern unsigned long volatile __cacheline_aligned_in_smp __jiffy_arch_data jiffies;
 
+u64 get_jiffies_boot_64(void);
 #if (BITS_PER_LONG < 64)
 u64 get_jiffies_64(void);
 #else
diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h
index 7acb953298a7..2e4c52fe0250 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -51,6 +51,7 @@  struct tk_read_base {
  * @wall_to_monotonic:	CLOCK_REALTIME to CLOCK_MONOTONIC offset
  * @offs_real:		Offset clock monotonic -> clock realtime
  * @offs_boot:		Offset clock monotonic -> clock boottime
+ * @offs_boot_jiffies64	Offset clock monotonic -> clock boottime in jiffies64
  * @offs_tai:		Offset clock monotonic -> clock tai
  * @tai_offset:		The current UTC to TAI offset in seconds
  * @clock_was_set_seq:	The sequence number of clock was set events
@@ -93,6 +94,7 @@  struct timekeeper {
 	struct timespec64	wall_to_monotonic;
 	ktime_t			offs_real;
 	ktime_t			offs_boot;
+	u64			offs_boot_jiffies64;
 	ktime_t			offs_tai;
 	s32			tai_offset;
 	unsigned int		clock_was_set_seq;
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 85f5912d8f70..a3707b454446 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -146,6 +146,7 @@  static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec64 wtm)
 static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
 {
 	tk->offs_boot = ktime_add(tk->offs_boot, delta);
+	tk->offs_boot_jiffies64 = nsecs_to_jiffies64(ktime_to_ns(tk->offs_boot));
 }
 
 /*
@@ -539,6 +540,16 @@  u64 ktime_get_real_fast_ns(void)
 }
 EXPORT_SYMBOL_GPL(ktime_get_real_fast_ns);
 
+/**
+ * get_jiffies_boot_64 - The normal get_jiffies_64(), but taking into
+ * account the time spent sleeping.
+ */
+u64 get_jiffies_boot_64(void)
+{
+	return get_jiffies_64() + tk_core.timekeeper.offs_boot_jiffies64;
+}
+EXPORT_SYMBOL(get_jiffies_boot_64);
+
 /**
  * halt_fast_timekeeper - Prevent fast timekeeper from accessing clocksource.
  * @tk: Timekeeper to snapshot.