This is 1 of 3 patches for ia64 clocksource.
As john stultz wrote:
> So w/ x86_64, we've split the xtime_lock and get vgtod_lock, so that
> only when the vsyscall page is being updated do we hold a write on the
> vgtod_lock. This is safe as the vsyscall gtod does not access the
> kernel's time structures (xtime and friends). Instead it reads its copy
> of them that is made in update_vsyscall().
>
> So it should be fine to use the gtod_lock.sequence, assuming you're also
> not touching the kernel's xtime directly (and instead using copy of
> xtime made in update_vsyscall).
having copy of xtime is good solution.
This patch does:
- add wall_time/monotonic_time member to struct fsys_gtod_data.
- copy xtime to wall_time in update_vsyscall.
- calculate monotonic time in update_vsyscall, instead of doing
it in each gettimeofday call. And save it to monotonic_time.
- force loading gtod_lock.sequence before touching protected data.
- modify comments.
Then, the results of my test:
> # clocksource (Bob's) : default
> CPU 0: 4.66 (usecs) (0 errors / 2145680 iterations)
> CPU 1: 4.65 (usecs) (493 errors / 2148438 iterations)
> CPU 2: 4.63 (usecs) (668 errors / 2159461 iterations)
> CPU 3: 4.62 (usecs) (654 errors / 2163997 iterations)
> # clocksource (Bob's) : nojitter
> CPU 0: 0.14 (usecs) (0 errors / 70945550 iterations)
> CPU 1: 0.14 (usecs) (470 errors / 71640889 iterations)
> CPU 2: 0.14 (usecs) (664 errors / 70960917 iterations)
> CPU 3: 0.14 (usecs) (571 errors / 70956121 iterations)
> # clocksource (Bob's) : nolwsys
> CPU 0: 2.88 (usecs) (0 errors / 3475147 iterations)
> CPU 1: 2.88 (usecs) (0 errors / 3474881 iterations)
> CPU 2: 2.96 (usecs) (0 errors / 3382229 iterations)
> CPU 3: 2.97 (usecs) (0 errors / 3371004 iterations)
are now
> # savextime : default
> CPU 0: 5.49 (usecs) (0 errors / 1822461 iterations)
> CPU 1: 5.46 (usecs) (0 errors / 1830527 iterations)
> CPU 2: 5.45 (usecs) (0 errors / 1834697 iterations)
> CPU 3: 5.46 (usecs) (0 errors / 1831464 iterations)
> # savextime : nojitter
> CPU 0: 0.14 (usecs) (0 errors / 70918167 iterations)
> CPU 1: 0.14 (usecs) (0 errors / 71620242 iterations)
> CPU 2: 0.14 (usecs) (0 errors / 70946394 iterations)
> CPU 3: 0.14 (usecs) (0 errors / 70933043 iterations)
> # savextime : nolwsys
> CPU 0: 2.89 (usecs) (0 errors / 3459498 iterations)
> CPU 1: 2.89 (usecs) (0 errors / 3458876 iterations)
> CPU 2: 2.96 (usecs) (0 errors / 3377799 iterations)
> CPU 3: 2.97 (usecs) (0 errors / 3372353 iterations)
so errors are vanished by proper locking, but something in
"default" is still wrong.
(Continue to next patch.)
Thanks,
H.Seto
Signed-off-by: Hidetoshi Seto <[EMAIL PROTECTED]>
-----
arch/ia64/kernel/asm-offsets.c | 28 +++++++++----
arch/ia64/kernel/fsys.S | 71 +++++++++++++++++-----------------
arch/ia64/kernel/fsyscall_gtod_data.h | 2
arch/ia64/kernel/time.c | 14 ++++++
4 files changed, 73 insertions(+), 42 deletions(-)
Index: linux-2.6.22/arch/ia64/kernel/asm-offsets.c
===================================================================
--- linux-2.6.22.orig/arch/ia64/kernel/asm-offsets.c
+++ linux-2.6.22/arch/ia64/kernel/asm-offsets.c
@@ -258,12 +258,24 @@
BLANK();
/* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */
- DEFINE(IA64_GTOD_LOCK_OFFSET, offsetof (struct fsyscall_gtod_data_t,
lock));
- DEFINE(IA64_CLKSRC_MASK_OFFSET, offsetof (struct fsyscall_gtod_data_t,
clk_mask));
- DEFINE(IA64_CLKSRC_MULT_OFFSET, offsetof (struct fsyscall_gtod_data_t,
clk_mult));
- DEFINE(IA64_CLKSRC_SHIFT_OFFSET, offsetof (struct fsyscall_gtod_data_t,
clk_shift));
- DEFINE(IA64_CLKSRC_MMIO_OFFSET, offsetof (struct fsyscall_gtod_data_t,
clk_fsys_mmio));
- DEFINE(IA64_CLKSRC_CYCLE_LAST_OFFSET, offsetof (struct
fsyscall_gtod_data_t, clk_cycle_last));
- DEFINE(IA64_ITC_LASTCYCLE_OFFSET, offsetof (struct
fsyscall_gtod_data_t, itc_lastcycle));
- DEFINE(IA64_ITC_JITTER_OFFSET, offsetof (struct fsyscall_gtod_data_t,
itc_jitter));
+ DEFINE(IA64_GTOD_LOCK_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, lock));
+ DEFINE(IA64_GTOD_WALL_TIME_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, wall_time));
+ DEFINE(IA64_GTOD_MONO_TIME_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, monotonic_time));
+ DEFINE(IA64_CLKSRC_MASK_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, clk_mask));
+ DEFINE(IA64_CLKSRC_MULT_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, clk_mult));
+ DEFINE(IA64_CLKSRC_SHIFT_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, clk_shift));
+ DEFINE(IA64_CLKSRC_MMIO_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, clk_fsys_mmio));
+ DEFINE(IA64_CLKSRC_CYCLE_LAST_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, clk_cycle_last));
+ DEFINE(IA64_ITC_LASTCYCLE_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, itc_lastcycle));
+ DEFINE(IA64_ITC_JITTER_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, itc_jitter));
}
Index: linux-2.6.22/arch/ia64/kernel/fsyscall_gtod_data.h
===================================================================
--- linux-2.6.22.orig/arch/ia64/kernel/fsyscall_gtod_data.h
+++ linux-2.6.22/arch/ia64/kernel/fsyscall_gtod_data.h
@@ -7,6 +7,8 @@
struct fsyscall_gtod_data_t {
seqlock_t lock;
+ struct timespec wall_time;
+ struct timespec monotonic_time;
cycle_t clk_mask;
u32 clk_mult;
u32 clk_shift;
Index: linux-2.6.22/arch/ia64/kernel/time.c
===================================================================
--- linux-2.6.22.orig/arch/ia64/kernel/time.c
+++ linux-2.6.22/arch/ia64/kernel/time.c
@@ -373,6 +373,20 @@
fsyscall_gtod_data.clk_fsys_mmio = c->fsys_mmio;
fsyscall_gtod_data.clk_cycle_last = c->cycle_last;
+ /* copy kernel time structures */
+ fsyscall_gtod_data.wall_time.tv_sec = wall->tv_sec;
+ fsyscall_gtod_data.wall_time.tv_nsec = wall->tv_nsec;
+ fsyscall_gtod_data.monotonic_time.tv_sec = wall_to_monotonic.tv_sec
+ + wall->tv_sec;
+ fsyscall_gtod_data.monotonic_time.tv_nsec = wall_to_monotonic.tv_nsec
+ + wall->tv_nsec;
+
+ /* normalize */
+ while (fsyscall_gtod_data.monotonic_time.tv_nsec >= NSEC_PER_SEC) {
+ fsyscall_gtod_data.monotonic_time.tv_nsec -= NSEC_PER_SEC;
+ fsyscall_gtod_data.monotonic_time.tv_sec++;
+ }
+
write_sequnlock_irqrestore(&fsyscall_gtod_data.lock, flags);
}
Index: linux-2.6.22/arch/ia64/kernel/fsys.S
===================================================================
--- linux-2.6.22.orig/arch/ia64/kernel/fsys.S
+++ linux-2.6.22/arch/ia64/kernel/fsys.S
@@ -178,18 +178,19 @@
// r14 = address of mask / mask value
// r15 = preserved: system call number
// r16 = preserved: current task pointer
- // r17 = wall to monotonic use
+ // r17 = (not used)
+ // r18 = (not used)
// r19 = address of itc_lastcycle
- // r20 = struct fsyscall_gtod_data / address of first element
+ // r20 = struct fsyscall_gtod_data (= address of gtod_lock.sequence)
// r21 = address of mmio_ptr
- // r22 = address of wall_to_monotonic
- // r23 = address of shift/ value
+ // r22 = address of wall_time or monotonic_time
+ // r23 = address of shift / value
// r24 = address mult factor / cycle_last value
// r25 = itc_lastcycle value
// r26 = address clocksource cycle_last
- // r27 = pointer to xtime
+ // r27 = (not used)
// r28 = sequence number at the beginning of critcal section
- // r29 = address of seqlock
+ // r29 = address of itc_jitter
// r30 = time processing flags / memory address
// r31 = pointer to result
// Predicates
@@ -203,30 +204,36 @@
// p14 = Divide by 1000
// p15 = Add monotonic
//
- // Note that instructions are optimized for McKinley. McKinley can
process two
- // bundles simultaneously and therefore we continuously try to feed the
CPU
- // two bundles and then a stop.
- tnat.nz p6,p0 = r31 // branch deferred since it does not fit into
bundle structure
+ // Note that instructions are optimized for McKinley. McKinley can
+ // process two bundles simultaneously and therefore we continuously
+ // try to feed the CPU two bundles and then a stop.
+ //
+ // Additional note that code has changed a lot. Optimization is TBD.
+ // Comments begin with "?" are maybe outdated.
+ tnat.nz p6,p0 = r31 // ? branch deferred to fit later bundle
mov pr = r30,0xc000 // Set predicates according to function
add r2 = TI_FLAGS+IA64_TASK_SIZE,r16
movl r20 = fsyscall_gtod_data // load fsyscall gettimeofday data address
;;
add r29 = IA64_ITC_JITTER_OFFSET,r20
- movl r27 = xtime
+ add r22 = IA64_GTOD_WALL_TIME_OFFSET,r20 // wall_time
ld4 r2 = [r2] // process work pending flags
-(p15) movl r22 = wall_to_monotonic
;;
+(p15) add r22 = IA64_GTOD_MONO_TIME_OFFSET,r20 // monotonic_time
add r21 = IA64_CLKSRC_MMIO_OFFSET,r20
add r19 = IA64_ITC_LASTCYCLE_OFFSET,r20
and r2 = TIF_ALLWORK_MASK,r2
-(p6) br.cond.spnt.few .fail_einval // deferred branch
+(p6) br.cond.spnt.few .fail_einval // ? deferred branch
;;
add r26 = IA64_CLKSRC_CYCLE_LAST_OFFSET,r20 // clksrc_cycle_last
cmp.ne p6, p0 = 0, r2 // Fallback if work is scheduled
(p6) br.cond.spnt.many fsys_fallback_syscall
;; // get lock.seq here new code, outer loop2!
.time_redo:
- ld4.acq r28 = [r20] // gtod_lock.sequence, Must be first in struct
+ ld4.acq r28 = [r20] // gtod_lock.sequence, Must take first
+ ;;
+ and r28 = ~1,r28 // And make sequence even to force retry if odd
+ ;;
ld8 r30 = [r21] // clocksource->mmio_ptr
add r24 = IA64_CLKSRC_MULT_OFFSET,r20
ld4 r2 = [r29] // itc_jitter value
@@ -235,7 +242,7 @@
;;
ld4 r3 = [r24] // clocksource mult value
ld8 r14 = [r14] // clocksource mask value
- cmp.eq p8,p9 = 0,r30 // Check for cpu timer, no mmio_ptr, set p8,
clear p9
+ cmp.eq p8,p9 = 0,r30 // use cpu timer if no mmio_ptr
;;
setf.sig f7 = r3 // Setup for mult scaling of counter
(p8) cmp.ne p13,p0 = r2,r0 // need itc_jitter compensation, set p13
@@ -246,17 +253,16 @@
.cmpxchg_redo:
.pred.rel.mutex p8,p9
(p8) mov r2 = ar.itc // CPU_TIMER. 36 clocks latency!!!
-(p9) ld8 r2 = [r30] // readq(ti->address). Could also have latency
issues..
+(p9) ld8 r2 = [r30] // MMIO_TIMER. Could also have latency issues..
(p13) ld8 r25 = [r19] // get itc_lastcycle value
- ;; // could be removed by moving the last add
upward
- ld8 r9 = [r27],IA64_TIMESPEC_TV_NSEC_OFFSET
-(p15) ld8 r17 = [r22],IA64_TIMESPEC_TV_NSEC_OFFSET
+ ;; // ? could be removed by moving the last add upward
+ ld8 r9 = [r22],IA64_TIMESPEC_TV_NSEC_OFFSET // tv_sec
;;
- ld8 r8 = [r27],-IA64_TIMESPEC_TV_NSEC_OFFSET // xtime.tv_nsec
+ ld8 r8 = [r22],-IA64_TIMESPEC_TV_NSEC_OFFSET // tv_nsec
(p13) sub r3 = r25,r2 // Diff needed before comparison (thanks davidm)
;;
(p13) cmp.gt.unc p6,p7 = r3,r0 // check if it is less than last. p6,p7 cleared
- sub r10 = r2,r24 // current_counter - last_counter
+ sub r10 = r2,r24 // current_cycle - last_cycle
;;
(p6) sub r10 = r25,r24 // time we got was less than last_cycle
(p7) mov ar.ccv = r25 // more than last_cycle. Prep for cmpxchg
@@ -267,23 +273,20 @@
nop.i 123
;;
(p7) cmpxchg8.rel r3 = [r19],r2,ar.ccv
-EX(.fail_efault, probe.w.fault r31, 3) // This takes 5 cycles and we have
spare time
+ // fault check takes 5 cycles and we have spare time
+EX(.fail_efault, probe.w.fault r31, 3)
xmpy.l f8 = f8,f7 // nsec_per_cyc*(counter-last_counter)
-(p15) add r9 = r9,r17 // Add wall to monotonic.secs to result secs
;;
// End cmpxchg critical section loop1
-(p15) ld8 r17 = [r22],-IA64_TIMESPEC_TV_NSEC_OFFSET
(p7) cmp.ne p7,p0 = r25,r3 // if cmpxchg not successful redo
(p7) br.cond.dpnt.few .cmpxchg_redo // inner loop1
- // simulate tbit.nz.or p7,p0 = r28,0
- and r28 = ~1,r28 // Make sequence even to force retry if odd
+ // ? simulate tbit.nz.or p7,p0 = r28,0
getf.sig r2 = f8
mf
;;
- ld4 r10 = [r20] // gtod_lock.sequence, old xtime_lock.sequence
-(p15) add r8 = r8, r17 // Add monotonic.nsecs to nsecs
+ ld4 r10 = [r20] // gtod_lock.sequence
shr.u r2 = r2,r23 // shift by factor
- ;; // overloaded 3 bundles!
+ ;; // ? overloaded 3 bundles!
// End critical section.
add r8 = r8,r2 // Add xtime.nsecs
cmp4.ne.or p7,p0 = r28,r10
@@ -297,19 +300,19 @@
.time_normalize:
mov r21 = r8
cmp.ge p6,p0 = r8,r2
-(p14) shr.u r20 = r8, 3 // We can repeat this if necessary just
wasting some time
+(p14) shr.u r20 = r8, 3 // We can repeat this if necessary just wasting time
;;
(p14) setf.sig f8 = r20
(p6) sub r8 = r8,r2
-(p6) add r9 = 1,r9 // two nops before the branch.
-(p14) setf.sig f7 = r3 // Chances for repeats are 1 in 10000
for gettod
+(p6) add r9 = 1,r9 // two nops before the branch.
+(p14) setf.sig f7 = r3 // Chances for repeats are 1 in 10000 for gettod
(p6) br.cond.dpnt.few .time_normalize
;;
// Divided by 8 though shift. Now divide by 125
// The compiler was able to do that with a multiply
// and a shift and we do the same
-EX(.fail_efault, probe.w.fault r23, 3) // This also costs 5 cycles
-(p14) xmpy.hu f8 = f8, f7 // xmpy has 5 cycles latency so
use it...
+EX(.fail_efault, probe.w.fault r23, 3) // This also costs 5 cycles
+(p14) xmpy.hu f8 = f8, f7 // xmpy has 5 cycles latency so use it
;;
mov r8 = r0
(p14) getf.sig r2 = f8
-
To unsubscribe from this list: send the line "unsubscribe linux-ia64" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html