aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/vsyscall.c
diff options
context:
space:
mode:
authorEric Dumazet <dada1@cosmosbay.com>2007-05-02 13:27:11 -0400
committerAndi Kleen <andi@basil.nowhere.org>2007-05-02 13:27:11 -0400
commitc8118c6c07f2edfd697aaa0b93e08c3b65a5a675 (patch)
treeefba31a24e3f2c629f727d53767fb18aaab915e2 /arch/x86_64/kernel/vsyscall.c
parent272a3713bb9e302e0455c894c41180a482d2c8a3 (diff)
[PATCH] x86-64: vsyscall_gtod_data diet and vgettimeofday() fix
Current vsyscall_gtod_data is large (3 or 4 cache lines dirtied at timer interrupt). We can shrink it to exactly 64 bytes (1 cache line on AMD64) Instead of copying a whole struct clocksource, we copy only needed fields. I deleted an unused field : offset_base This patch fixes one oddity in vgettimeofday(): It can returns a timeval with tv_usec = 1000000. Maybe not a bug, but why not doing the right thing ? Signed-off-by: Eric Dumazet <dada1@cosmosbay.com> Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch/x86_64/kernel/vsyscall.c')
-rw-r--r--arch/x86_64/kernel/vsyscall.c53
1 files changed, 36 insertions, 17 deletions
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index ba330f870679..dc32cef96195 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -51,13 +51,28 @@
51 asm("" : "=r" (v) : "0" (x)); \ 51 asm("" : "=r" (v) : "0" (x)); \
52 ((v - VSYSCALL_FIRST_PAGE) + __pa_symbol(&__vsyscall_0)); }) 52 ((v - VSYSCALL_FIRST_PAGE) + __pa_symbol(&__vsyscall_0)); })
53 53
54/*
55 * vsyscall_gtod_data contains data that is :
56 * - readonly from vsyscalls
57 * - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64)
58 * Try to keep this structure as small as possible to avoid cache line ping pongs
59 */
54struct vsyscall_gtod_data_t { 60struct vsyscall_gtod_data_t {
55 seqlock_t lock; 61 seqlock_t lock;
56 int sysctl_enabled; 62
57 struct timeval wall_time_tv; 63 /* open coded 'struct timespec' */
64 time_t wall_time_sec;
65 u32 wall_time_nsec;
66
67 int sysctl_enabled;
58 struct timezone sys_tz; 68 struct timezone sys_tz;
59 cycle_t offset_base; 69 struct { /* extract of a clocksource struct */
60 struct clocksource clock; 70 cycle_t (*vread)(void);
71 cycle_t cycle_last;
72 cycle_t mask;
73 u32 mult;
74 u32 shift;
75 } clock;
61}; 76};
62int __vgetcpu_mode __section_vgetcpu_mode; 77int __vgetcpu_mode __section_vgetcpu_mode;
63 78
@@ -73,9 +88,13 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
73 88
74 write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags); 89 write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
75 /* copy vsyscall data */ 90 /* copy vsyscall data */
76 vsyscall_gtod_data.clock = *clock; 91 vsyscall_gtod_data.clock.vread = clock->vread;
77 vsyscall_gtod_data.wall_time_tv.tv_sec = wall_time->tv_sec; 92 vsyscall_gtod_data.clock.cycle_last = clock->cycle_last;
78 vsyscall_gtod_data.wall_time_tv.tv_usec = wall_time->tv_nsec/1000; 93 vsyscall_gtod_data.clock.mask = clock->mask;
94 vsyscall_gtod_data.clock.mult = clock->mult;
95 vsyscall_gtod_data.clock.shift = clock->shift;
96 vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
97 vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
79 vsyscall_gtod_data.sys_tz = sys_tz; 98 vsyscall_gtod_data.sys_tz = sys_tz;
80 write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags); 99 write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
81} 100}
@@ -110,7 +129,8 @@ static __always_inline long time_syscall(long *t)
110static __always_inline void do_vgettimeofday(struct timeval * tv) 129static __always_inline void do_vgettimeofday(struct timeval * tv)
111{ 130{
112 cycle_t now, base, mask, cycle_delta; 131 cycle_t now, base, mask, cycle_delta;
113 unsigned long seq, mult, shift, nsec_delta; 132 unsigned seq;
133 unsigned long mult, shift, nsec;
114 cycle_t (*vread)(void); 134 cycle_t (*vread)(void);
115 do { 135 do {
116 seq = read_seqbegin(&__vsyscall_gtod_data.lock); 136 seq = read_seqbegin(&__vsyscall_gtod_data.lock);
@@ -126,21 +146,20 @@ static __always_inline void do_vgettimeofday(struct timeval * tv)
126 mult = __vsyscall_gtod_data.clock.mult; 146 mult = __vsyscall_gtod_data.clock.mult;
127 shift = __vsyscall_gtod_data.clock.shift; 147 shift = __vsyscall_gtod_data.clock.shift;
128 148
129 *tv = __vsyscall_gtod_data.wall_time_tv; 149 tv->tv_sec = __vsyscall_gtod_data.wall_time_sec;
130 150 nsec = __vsyscall_gtod_data.wall_time_nsec;
131 } while (read_seqretry(&__vsyscall_gtod_data.lock, seq)); 151 } while (read_seqretry(&__vsyscall_gtod_data.lock, seq));
132 152
133 /* calculate interval: */ 153 /* calculate interval: */
134 cycle_delta = (now - base) & mask; 154 cycle_delta = (now - base) & mask;
135 /* convert to nsecs: */ 155 /* convert to nsecs: */
136 nsec_delta = (cycle_delta * mult) >> shift; 156 nsec += (cycle_delta * mult) >> shift;
137 157
138 /* convert to usecs and add to timespec: */ 158 while (nsec >= NSEC_PER_SEC) {
139 tv->tv_usec += nsec_delta / NSEC_PER_USEC;
140 while (tv->tv_usec > USEC_PER_SEC) {
141 tv->tv_sec += 1; 159 tv->tv_sec += 1;
142 tv->tv_usec -= USEC_PER_SEC; 160 nsec -= NSEC_PER_SEC;
143 } 161 }
162 tv->tv_usec = nsec / NSEC_PER_USEC;
144} 163}
145 164
146int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) 165int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
@@ -159,7 +178,7 @@ time_t __vsyscall(1) vtime(time_t *t)
159 time_t result; 178 time_t result;
160 if (unlikely(!__vsyscall_gtod_data.sysctl_enabled)) 179 if (unlikely(!__vsyscall_gtod_data.sysctl_enabled))
161 return time_syscall(t); 180 return time_syscall(t);
162 result = __vsyscall_gtod_data.wall_time_tv.tv_sec; 181 result = __vsyscall_gtod_data.wall_time_sec;
163 if (t) 182 if (t)
164 *t = result; 183 *t = result;
165 return result; 184 return result;