All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] tile: add clock_gettime support to vDSO
@ 2014-09-30 19:29 Chris Metcalf
  2014-09-30 22:17 ` Thomas Gleixner
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Chris Metcalf @ 2014-09-30 19:29 UTC (permalink / raw)
  To: linux-kernel, Thomas Gleixner, John Stultz, Henrik Austad

This change adds support for clock_gettime with CLOCK_REALTIME
and CLOCK_MONOTONIC using vDSO.  In addition, with this change
we switch to use seqlocks instead of integer counters.

We also support the *_COARSE clockid_t, for apps that want speed
but aren't concerned about fine-grained timestamps; this saves
about 20 cycles per call (see http://lwn.net/Articles/342018/).

Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
---
 arch/tile/include/asm/vdso.h          |   9 +-
 arch/tile/kernel/time.c               |  31 ++++---
 arch/tile/kernel/vdso/vdso.lds.S      |   2 +
 arch/tile/kernel/vdso/vgettimeofday.c | 166 +++++++++++++++++++++++++---------
 4 files changed, 153 insertions(+), 55 deletions(-)

diff --git a/arch/tile/include/asm/vdso.h b/arch/tile/include/asm/vdso.h
index 9f6a78d665fa..4527701fcead 100644
--- a/arch/tile/include/asm/vdso.h
+++ b/arch/tile/include/asm/vdso.h
@@ -15,6 +15,7 @@
 #ifndef __TILE_VDSO_H__
 #define __TILE_VDSO_H__
 
+#include <linux/seqlock.h>
 #include <linux/types.h>
 
 /*
@@ -26,8 +27,8 @@
  */
 
 struct vdso_data {
-	__u64 tz_update_count;  /* Timezone atomicity ctr             */
-	__u64 tb_update_count;  /* Timebase atomicity ctr             */
+	seqcount_t tz_seq;	/* Timezone seqlock                   */
+	seqcount_t tb_seq;	/* Timebase seqlock                   */
 	__u64 xtime_tod_stamp;  /* TOD clock for xtime                */
 	__u64 xtime_clock_sec;  /* Kernel time second                 */
 	__u64 xtime_clock_nsec; /* Kernel time nanosecond             */
@@ -37,6 +38,10 @@ struct vdso_data {
 	__u32 shift;            /* Cycle to nanosecond divisor (power of two) */
 	__u32 tz_minuteswest;   /* Minutes west of Greenwich          */
 	__u32 tz_dsttime;       /* Type of dst correction             */
+	__u64 xtime_clock_coarse_sec;	/* Coarse kernel time         */
+	__u64 xtime_clock_coarse_nsec;
+	__u64 wtom_clock_coarse_sec;    /* Coarse wall to monotonic time */
+	__u64 wtom_clock_coarse_nsec;
 };
 
 extern struct vdso_data *vdso_data;
diff --git a/arch/tile/kernel/time.c b/arch/tile/kernel/time.c
index 462dcd0c1700..77624b38bdb9 100644
--- a/arch/tile/kernel/time.c
+++ b/arch/tile/kernel/time.c
@@ -249,13 +249,10 @@ cycles_t ns2cycles(unsigned long nsecs)
 
 void update_vsyscall_tz(void)
 {
-	/* Userspace gettimeofday will spin while this value is odd. */
-	++vdso_data->tz_update_count;
-	smp_wmb();
+	write_seqcount_begin(&vdso_data->tz_seq);
 	vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
 	vdso_data->tz_dsttime = sys_tz.tz_dsttime;
-	smp_wmb();
-	++vdso_data->tz_update_count;
+	write_seqcount_end(&vdso_data->tz_seq);
 }
 
 void update_vsyscall(struct timekeeper *tk)
@@ -263,20 +260,30 @@ void update_vsyscall(struct timekeeper *tk)
 	struct timespec wall_time = tk_xtime(tk);
 	struct timespec *wtm = &tk->wall_to_monotonic;
 	struct clocksource *clock = tk->clock;
+	struct timespec ts;
 
 	if (clock != &cycle_counter_cs)
 		return;
 
-	/* Userspace gettimeofday will spin while this value is odd. */
-	++vdso_data->tb_update_count;
-	smp_wmb();
+	write_seqcount_begin(&vdso_data->tb_seq);
+
 	vdso_data->xtime_tod_stamp = clock->cycle_last;
 	vdso_data->xtime_clock_sec = wall_time.tv_sec;
 	vdso_data->xtime_clock_nsec = wall_time.tv_nsec;
-	vdso_data->wtom_clock_sec = wtm->tv_sec;
-	vdso_data->wtom_clock_nsec = wtm->tv_nsec;
+
+	ts = timespec_add(wall_time, *wtm);
+	vdso_data->wtom_clock_sec = ts.tv_sec;
+	vdso_data->wtom_clock_nsec = ts.tv_nsec;
+
 	vdso_data->mult = clock->mult;
 	vdso_data->shift = clock->shift;
-	smp_wmb();
-	++vdso_data->tb_update_count;
+
+	ts = __current_kernel_time();
+	vdso_data->xtime_clock_coarse_sec = ts.tv_sec;
+	vdso_data->xtime_clock_coarse_nsec = ts.tv_nsec;
+	ts = timespec_add(ts, *wtm);
+	vdso_data->wtom_clock_coarse_sec = ts.tv_sec;
+	vdso_data->wtom_clock_coarse_nsec = ts.tv_nsec;
+
+	write_seqcount_end(&vdso_data->tb_seq);
 }
diff --git a/arch/tile/kernel/vdso/vdso.lds.S b/arch/tile/kernel/vdso/vdso.lds.S
index 041cd6c39c83..731529f3f06f 100644
--- a/arch/tile/kernel/vdso/vdso.lds.S
+++ b/arch/tile/kernel/vdso/vdso.lds.S
@@ -82,6 +82,8 @@ VERSION
 		__vdso_rt_sigreturn;
 		__vdso_gettimeofday;
 		gettimeofday;
+		__vdso_clock_gettime;
+		clock_gettime;
 	local:*;
 	};
 }
diff --git a/arch/tile/kernel/vdso/vgettimeofday.c b/arch/tile/kernel/vdso/vgettimeofday.c
index 51ec8e46f5f9..a09043492d1e 100644
--- a/arch/tile/kernel/vdso/vgettimeofday.c
+++ b/arch/tile/kernel/vdso/vgettimeofday.c
@@ -15,8 +15,14 @@
 #define VDSO_BUILD  /* avoid some shift warnings for -m32 in <asm/page.h> */
 #include <linux/time.h>
 #include <asm/timex.h>
+#include <asm/unistd.h>
 #include <asm/vdso.h>
 
+struct syscall_return_value {
+	long value;
+	long error;
+};
+
 #if CHIP_HAS_SPLIT_CYCLE()
 static inline cycles_t get_cycles_inline(void)
 {
@@ -50,58 +56,136 @@ inline unsigned long get_datapage(void)
 	return ret;
 }
 
-int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+static inline int do_realtime(struct vdso_data *vdso, struct timespec *ts)
+{
+	int count;
+	cycles_t cycles;
+	unsigned long ns;
+
+	do {
+		count = read_seqcount_begin(&vdso->tb_seq);
+		cycles = get_cycles() - vdso->xtime_tod_stamp;
+		ns = (cycles * vdso->mult) >> vdso->shift;
+		ts->tv_sec = vdso->xtime_clock_sec;
+		ts->tv_nsec = vdso->xtime_clock_nsec;
+	} while (unlikely(read_seqcount_retry(&vdso->tb_seq, count)));
+
+	timespec_add_ns(ts, ns);
+	return 0;
+}
+
+static inline int do_monotonic(struct vdso_data *vdso, struct timespec *ts)
 {
+	int count;
 	cycles_t cycles;
-	unsigned long count, sec, ns;
-	volatile struct vdso_data *vdso_data;
+	unsigned long ns;
+
+	do {
+		count = read_seqcount_begin(&vdso->tb_seq);
+		cycles = get_cycles() - vdso->xtime_tod_stamp;
+		ns = (cycles * vdso->mult) >> vdso->shift;
+		ts->tv_sec = vdso->wtom_clock_sec;
+		ts->tv_nsec = vdso->wtom_clock_nsec;
+	} while (unlikely(read_seqcount_retry(&vdso->tb_seq, count)));
+
+	timespec_add_ns(ts, ns);
+	return 0;
+}
+
+static inline int do_realtime_coarse(struct vdso_data *vdso,
+				     struct timespec *ts)
+{
+	unsigned long count;
+
+	do {
+		count = read_seqcount_begin(&vdso->tb_seq);
+		ts->tv_sec = vdso->xtime_clock_coarse_sec;
+		ts->tv_nsec = vdso->xtime_clock_coarse_nsec;
+	} while (unlikely(read_seqcount_retry(&vdso->tb_seq, count)));
+
+	return 0;
+}
+
+static inline int do_monotonic_coarse(struct vdso_data *vdso,
+				      struct timespec *ts)
+{
+	unsigned long count;
+
+	do {
+		count = read_seqcount_begin(&vdso->tb_seq);
+		ts->tv_sec = vdso->wtom_clock_coarse_sec;
+		ts->tv_nsec = vdso->wtom_clock_coarse_nsec;
+	} while (unlikely(read_seqcount_retry(&vdso->tb_seq, count)));
+
+	return 0;
+}
+
+struct syscall_return_value __vdso_gettimeofday(struct timeval *tv,
+						struct timezone *tz)
+{
+	struct syscall_return_value ret = { 0, 0 };
+	unsigned long count;
+	struct vdso_data *vdso = (struct vdso_data *)get_datapage();
 
-	vdso_data = (struct vdso_data *)get_datapage();
 	/* The use of the timezone is obsolete, normally tz is NULL. */
 	if (unlikely(tz != NULL)) {
-		while (1) {
-			/* Spin until the update finish. */
-			count = vdso_data->tz_update_count;
-			if (count & 1)
-				continue;
-
-			tz->tz_minuteswest = vdso_data->tz_minuteswest;
-			tz->tz_dsttime = vdso_data->tz_dsttime;
-
-			/* Check whether updated, read again if so. */
-			if (count == vdso_data->tz_update_count)
-				break;
-		}
+		do {
+			count = read_seqcount_begin(&vdso->tz_seq);
+			tz->tz_minuteswest = vdso->tz_minuteswest;
+			tz->tz_dsttime = vdso->tz_dsttime;
+		} while (unlikely(read_seqcount_retry(&vdso->tz_seq, count)));
 	}
 
 	if (unlikely(tv == NULL))
-		return 0;
-
-	while (1) {
-		/* Spin until the update finish. */
-		count = vdso_data->tb_update_count;
-		if (count & 1)
-			continue;
-
-		cycles = (get_cycles() - vdso_data->xtime_tod_stamp);
-		ns = (cycles * vdso_data->mult) >> vdso_data->shift;
-		sec = vdso_data->xtime_clock_sec;
-		ns += vdso_data->xtime_clock_nsec;
-		if (ns >= NSEC_PER_SEC) {
-			ns -= NSEC_PER_SEC;
-			sec += 1;
-		}
-
-		/* Check whether updated, read again if so. */
-		if (count == vdso_data->tb_update_count)
-			break;
-	}
+		return ret;
 
-	tv->tv_sec = sec;
-	tv->tv_usec = ns / 1000;
+	do_realtime(vdso, (struct timespec *)tv);
+	tv->tv_usec /= 1000;
 
-	return 0;
+	return ret;
 }
 
 int gettimeofday(struct timeval *tv, struct timezone *tz)
 	__attribute__((weak, alias("__vdso_gettimeofday")));
+
+static struct syscall_return_value vdso_fallback_gettime(long clock,
+							 struct timespec *ts)
+{
+	struct syscall_return_value ret;
+	__asm__ __volatile__ (
+		"swint1"
+		: "=R00" (ret.value), "=R01" (ret.error)
+		: "R10" (__NR_clock_gettime), "R00" (clock), "R01" (ts)
+		: "r2", "r3", "r4", "r5", "r6", "r7",
+		"r8",  "r9", "r11", "r12", "r13", "r14", "r15",
+		"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+		"r24", "r25", "r26", "r27", "r28", "r29", "memory");
+	return ret;
+}
+
+struct syscall_return_value __vdso_clock_gettime(clockid_t clock,
+						 struct timespec *ts)
+{
+	struct vdso_data *vdso = (struct vdso_data *)get_datapage();
+	struct syscall_return_value ret = { 0, 0 };
+
+	switch (clock) {
+	case CLOCK_REALTIME:
+		do_realtime(vdso, ts);
+		return ret;
+	case CLOCK_MONOTONIC:
+		do_monotonic(vdso, ts);
+		return ret;
+	case CLOCK_REALTIME_COARSE:
+		do_realtime_coarse(vdso, ts);
+		return ret;
+	case CLOCK_MONOTONIC_COARSE:
+		do_monotonic_coarse(vdso, ts);
+		return ret;
+	default:
+		return vdso_fallback_gettime(clock, ts);
+	}
+}
+
+int clock_gettime(clockid_t clock, struct timespec *ts)
+	__attribute__((weak, alias("__vdso_clock_gettime")));
-- 
1.8.3.1


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

end of thread, other threads:[~2014-10-02 17:41 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-09-30 19:29 [PATCH] tile: add clock_gettime support to vDSO Chris Metcalf
2014-09-30 22:17 ` Thomas Gleixner
2014-09-30 22:30 ` John Stultz
2014-10-01 20:48 ` [PATCH v2 1/2] tile: switch to using seqlocks for the vDSO time code Chris Metcalf
2014-10-01 21:02 ` [PATCH v2 2/2] tile: add clock_gettime support to vDSO Chris Metcalf
2014-10-01 21:24 ` [PATCH] " Henrik Austad
2014-10-02 14:17   ` Chris Metcalf
2014-10-02 14:32   ` [PATCH v3 2/2] " Chris Metcalf
2014-10-02 17:41     ` John Stultz
2014-10-02 14:48   ` [PATCH v3 1/2] tile: switch to using seqlocks for the vDSO time code Chris Metcalf

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.