timekeeping: Provide fast accessor to the seconds part of CLOCK_MONOTONIC
authorHeena Sirwani <heenasirwani@gmail.com>
Wed, 29 Oct 2014 10:31:16 +0000 (16:01 +0530)
committerThomas Gleixner <tglx@linutronix.de>
Wed, 29 Oct 2014 14:15:40 +0000 (15:15 +0100)
This is the counterpart to get_seconds() based on CLOCK_MONOTONIC. The
use case for this interface are kernel internal coarse grained
timestamps which do neither require the nanoseconds fraction of
current time nor the CLOCK_REALTIME properties. Such timestamps can
currently only retrieved by calling ktime_get_ts64() and using the
tv_sec field of the returned timespec64. That's inefficient as it
involves the read of the clocksource, math operations and must be
protected by the timekeeper sequence counter.

To avoid the sequence counter protection we restrict the return value
to unsigned 32bit on 32bit machines. This covers ~136 years of uptime
and therefor an overflow is not expected to hit anytime soon.

To avoid math in the function we calculate the current seconds portion
of CLOCK_MONOTONIC when the timekeeper gets updated in
tk_update_ktime_data() similar to the CLOCK_REALTIME counterpart
xtime_sec.

[ tglx: Massaged changelog, simplified and commented the update
   function, added docbook comment ]

Signed-off-by: Heena Sirwani <heenasirwani@gmail.com>
Reviewed-by: Arnd Bergman <arnd@arndb.de>
Cc: John Stultz <john.stultz@linaro.org>
Cc: opw-kernel@googlegroups.com
Link: http://lkml.kernel.org/r/da0b63f4bdf3478909f92becb35861197da3a905.1414578445.git.heenasirwani@gmail.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
include/linux/timekeeper_internal.h
include/linux/timekeeping.h
kernel/time/timekeeping.c

index 95640dcd1899c533fc696a3fa964bbd39b3e9f01..05af9a3348934602456ec18b9cd29df84ac5a167 100644 (file)
@@ -42,6 +42,7 @@ struct tk_read_base {
  * struct timekeeper - Structure holding internal timekeeping values.
  * @tkr:               The readout base structure
  * @xtime_sec:         Current CLOCK_REALTIME time in seconds
+ * @ktime_sec:         Current CLOCK_MONOTONIC time in seconds
  * @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset
  * @offs_real:         Offset clock monotonic -> clock realtime
  * @offs_boot:         Offset clock monotonic -> clock boottime
@@ -77,6 +78,7 @@ struct tk_read_base {
 struct timekeeper {
        struct tk_read_base     tkr;
        u64                     xtime_sec;
+       unsigned long           ktime_sec;
        struct timespec64       wall_to_monotonic;
        ktime_t                 offs_real;
        ktime_t                 offs_boot;
index 1caa6b04fdc5ce09a0c27b4951ba03b200182940..115d55e11bc99cc2b55d0f155c99cfd2c2900443 100644 (file)
@@ -28,6 +28,7 @@ struct timespec __current_kernel_time(void);
 struct timespec get_monotonic_coarse(void);
 extern void getrawmonotonic(struct timespec *ts);
 extern void ktime_get_ts64(struct timespec64 *ts);
+extern time64_t ktime_get_seconds(void);
 
 extern int __getnstimeofday64(struct timespec64 *tv);
 extern void getnstimeofday64(struct timespec64 *tv);
index ec1791fae96575ffe49c9aa1a2f42cbc6b21df2a..a693270efafba79c36bf87907b15daabc09c5a7f 100644 (file)
@@ -417,7 +417,8 @@ EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier);
  */
 static inline void tk_update_ktime_data(struct timekeeper *tk)
 {
-       s64 nsec;
+       u64 seconds;
+       u32 nsec;
 
        /*
         * The xtime based monotonic readout is:
@@ -426,13 +427,22 @@ static inline void tk_update_ktime_data(struct timekeeper *tk)
         *      nsec = base_mono + now();
         * ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec
         */
-       nsec = (s64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);
-       nsec *= NSEC_PER_SEC;
-       nsec += tk->wall_to_monotonic.tv_nsec;
-       tk->tkr.base_mono = ns_to_ktime(nsec);
+       seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);
+       nsec = (u32) tk->wall_to_monotonic.tv_nsec;
+       tk->tkr.base_mono = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
 
        /* Update the monotonic raw base */
        tk->base_raw = timespec64_to_ktime(tk->raw_time);
+
+       /*
+        * The sum of the nanoseconds portions of xtime and
+        * wall_to_monotonic can be greater/equal one second. Take
+        * this into account before updating tk->ktime_sec.
+        */
+       nsec += (u32)(tk->tkr.xtime_nsec >> tk->tkr.shift);
+       if (nsec >= NSEC_PER_SEC)
+               seconds++;
+       tk->ktime_sec = seconds;
 }
 
 /* must hold timekeeper_lock */
@@ -648,6 +658,24 @@ void ktime_get_ts64(struct timespec64 *ts)
 }
 EXPORT_SYMBOL_GPL(ktime_get_ts64);
 
+/**
+ * ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC
+ *
+ * Returns the seconds portion of CLOCK_MONOTONIC with a single non
+ * serialized read. tk->ktime_sec is of type 'unsigned long' so this
+ * works on both 32 and 64 bit systems. On 32 bit systems the readout
+ * covers ~136 years of uptime which should be enough to prevent
+ * premature wrap arounds.
+ */
+time64_t ktime_get_seconds(void)
+{
+       struct timekeeper *tk = &tk_core.timekeeper;
+
+       WARN_ON(timekeeping_suspended);
+       return tk->ktime_sec;
+}
+EXPORT_SYMBOL_GPL(ktime_get_seconds);
+
 #ifdef CONFIG_NTP_PPS
 
 /**
This page took 0.027897 seconds and 5 git commands to generate.