diff options
author | Eric Dumazet <dada1@cosmosbay.com> | 2007-05-02 13:27:11 -0400 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2007-05-02 13:27:11 -0400 |
commit | c8118c6c07f2edfd697aaa0b93e08c3b65a5a675 (patch) | |
tree | efba31a24e3f2c629f727d53767fb18aaab915e2 /arch/x86_64/kernel/vsyscall.c | |
parent | 272a3713bb9e302e0455c894c41180a482d2c8a3 (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.c | 53 |
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 | */ | ||
54 | struct vsyscall_gtod_data_t { | 60 | struct 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 | }; |
62 | int __vgetcpu_mode __section_vgetcpu_mode; | 77 | int __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) | |||
110 | static __always_inline void do_vgettimeofday(struct timeval * tv) | 129 | static __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 | ||
146 | int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) | 165 | int __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; |