summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwollman <wollman@FreeBSD.org>1995-10-12 20:39:49 +0000
committerwollman <wollman@FreeBSD.org>1995-10-12 20:39:49 +0000
commit6cbc65227cc7ad9c94c8b8e0d2cd945feaeee532 (patch)
tree0210e3544aff15122235dd5f5b4bcde4edecf47f
parentfab8249e23e33d2dccce4d67cf895dbfbd79e733 (diff)
downloadFreeBSD-src-6cbc65227cc7ad9c94c8b8e0d2cd945feaeee532.zip
FreeBSD-src-6cbc65227cc7ad9c94c8b8e0d2cd945feaeee532.tar.gz
Reduce jitter of Pentium microtime() implementation by letting the counter
free-run and doing a subtract in microtime() rather than resetting the counter to zero at every clock tick. In combination with the changes to kern_clock.c, this should eliminate all the immediately obvious sources of systematic jitter in timekeeping on Pentium machines.
-rw-r--r--sys/amd64/amd64/tsc.c21
-rw-r--r--sys/amd64/include/clock.h61
-rw-r--r--sys/amd64/isa/clock.c21
-rw-r--r--sys/i386/i386/microtime.s8
-rw-r--r--sys/i386/i386/tsc.c21
-rw-r--r--sys/i386/include/clock.h61
-rw-r--r--sys/i386/isa/clock.c21
-rw-r--r--sys/isa/atrtc.c21
8 files changed, 156 insertions, 79 deletions
diff --git a/sys/amd64/amd64/tsc.c b/sys/amd64/amd64/tsc.c
index 188e25b..310972f 100644
--- a/sys/amd64/amd64/tsc.c
+++ b/sys/amd64/amd64/tsc.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
- * $Id: clock.c,v 1.35 1995/06/11 19:31:18 rgrimes Exp $
+ * $Id: clock.c,v 1.36 1995/08/25 19:24:56 bde Exp $
*/
/*
@@ -95,6 +95,8 @@ int disable_rtc_set = 0; /* disable resettodr() if != 0 */
u_int idelayed;
#ifdef I586_CPU
int pentium_mhz;
+long long i586_ctr_bias;
+long long i586_last_tick;
#endif
u_int stat_imask = SWI_CLOCK_MASK;
int timer0_max_count;
@@ -279,8 +281,6 @@ getit(void)
}
#ifdef I586_CPU
-static long long cycles_per_sec = 0;
-
/*
* Figure out how fast the cyclecounter runs. This must be run with
* clock interrupts disabled, but with the timer/counter programmed
@@ -293,15 +293,15 @@ calibrate_cyclecounter(void)
* Don't need volatile; should always use unsigned if 2's
* complement arithmetic is desired.
*/
- unsigned long long count, last_count;
+ unsigned long long count;
- __asm __volatile(".byte 0xf,0x31" : "=A" (last_count));
+ __asm __volatile(".byte 0x0f, 0x30" : : "A"(0LL), "c" (0x10));
DELAY(1000000);
__asm __volatile(".byte 0xf,0x31" : "=A" (count));
/*
* XX lose if the clock rate is not nearly a multiple of 1000000.
*/
- pentium_mhz = ((count - last_count) + 500000) / 1000000;
+ pentium_mhz = (count + 500000) / 1000000;
}
#endif
@@ -569,6 +569,15 @@ cpu_initclocks()
/* XXX */ (inthand2_t *)clkintr, &clk_imask,
/* unit */ 0);
INTREN(IRQ0);
+#ifdef I586_CPU
+ /*
+ * Finish setting up anti-jitter measures.
+ */
+ if (pentium_mhz) {
+ I586_CYCLECTR(i586_last_tick);
+ i586_ctr_bias = i586_last_tick;
+ }
+#endif
/* Initialize RTC. */
writertc(RTC_STATUSA, rtc_statusa);
diff --git a/sys/amd64/include/clock.h b/sys/amd64/include/clock.h
index 3d87a07..96476a7 100644
--- a/sys/amd64/include/clock.h
+++ b/sys/amd64/include/clock.h
@@ -8,40 +8,35 @@
#define _MACHINE_CLOCK_H_
#ifdef I586_CPU
- /*
- * This resets the CPU cycle counter to zero, to make our
- * job easier in microtime(). Some fancy ifdefs could speed
- * this up for Pentium-only kernels.
- * We want this to be done as close as possible to the actual
- * timer incrementing in hardclock(), because there is a window
- * between the two where the value is no longer valid. Experimentation
- * may reveal a good precompensation to apply in microtime().
- */
+
+#define I586_CYCLECTR(x) \
+ __asm __volatile(".byte 0x0f, 0x31" : "=A" (x))
+
+/*
+ * When we update the clock, we also update this bias value which is
+ * automatically subtracted in microtime(). We assume that CPU_THISTICKLEN()
+ * has been called at some point in the past, so that an appropriate value is
+ * set up in i586_last_tick. (This works even if we are not being called
+ * from hardclock because hardclock will have run before and will made the
+ * call.)
+ */
#define CPU_CLOCKUPDATE(otime, ntime) \
do { \
if(pentium_mhz) { \
- __asm __volatile("cli\n" \
- "movl (%2),%%eax\n" \
- "movl %%eax,(%1)\n" \
- "movl 4(%2),%%eax\n" \
- "movl %%eax,4(%1)\n" \
- "movl $0x10,%%ecx\n" \
- "xorl %%eax,%%eax\n" \
- "movl %%eax,%%edx\n" \
- ".byte 0x0f, 0x30\n" \
- "sti\n" \
- "#%0%1%2" \
- : "=m"(*otime) /* no outputs */ \
- : "c"(otime), "b"(ntime) /* fake input */ \
- : "ax", "cx", "dx"); \
+ disable_intr(); \
+ i586_ctr_bias = i586_last_tick; \
+ *(otime) = *(ntime); \
+ enable_intr(); \
} else { \
*(otime) = *(ntime); \
} \
} while(0)
+#define CPU_THISTICKLEN(dflt) cpu_thisticklen(dflt)
#else
#define CPU_CLOCKUPDATE(otime, ntime) \
(*(otime) = *(ntime))
+#define CPU_THISTICKLEN(dflt) dflt
#endif
#if defined(KERNEL) && !defined(LOCORE)
@@ -57,6 +52,8 @@ extern int adjkerntz;
extern int disable_rtc_set;
#ifdef I586_CPU
extern int pentium_mhz;
+extern long long i586_last_tick;
+extern long long i586_ctr_bias;
#endif
extern int timer0_max_count;
extern u_int timer0_overflow_threshold;
@@ -68,6 +65,24 @@ void calibrate_cyclecounter __P((void));
void clkintr __P((struct clockframe frame));
void rtcintr __P((struct clockframe frame));
+#ifdef I586_CPU
+static __inline u_long
+cpu_thisticklen(u_long dflt)
+{
+ long long old;
+ long rv;
+
+ if (pentium_mhz) {
+ old = i586_last_tick;
+ I586_CYCLECTR(i586_last_tick);
+ rv = (i586_last_tick - old) / pentium_mhz;
+ } else {
+ rv = dflt;
+ }
+ return rv;
+}
+#endif
+
/*
* Driver to clock driver interface.
*/
diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c
index 188e25b..310972f 100644
--- a/sys/amd64/isa/clock.c
+++ b/sys/amd64/isa/clock.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
- * $Id: clock.c,v 1.35 1995/06/11 19:31:18 rgrimes Exp $
+ * $Id: clock.c,v 1.36 1995/08/25 19:24:56 bde Exp $
*/
/*
@@ -95,6 +95,8 @@ int disable_rtc_set = 0; /* disable resettodr() if != 0 */
u_int idelayed;
#ifdef I586_CPU
int pentium_mhz;
+long long i586_ctr_bias;
+long long i586_last_tick;
#endif
u_int stat_imask = SWI_CLOCK_MASK;
int timer0_max_count;
@@ -279,8 +281,6 @@ getit(void)
}
#ifdef I586_CPU
-static long long cycles_per_sec = 0;
-
/*
* Figure out how fast the cyclecounter runs. This must be run with
* clock interrupts disabled, but with the timer/counter programmed
@@ -293,15 +293,15 @@ calibrate_cyclecounter(void)
* Don't need volatile; should always use unsigned if 2's
* complement arithmetic is desired.
*/
- unsigned long long count, last_count;
+ unsigned long long count;
- __asm __volatile(".byte 0xf,0x31" : "=A" (last_count));
+ __asm __volatile(".byte 0x0f, 0x30" : : "A"(0LL), "c" (0x10));
DELAY(1000000);
__asm __volatile(".byte 0xf,0x31" : "=A" (count));
/*
* XX lose if the clock rate is not nearly a multiple of 1000000.
*/
- pentium_mhz = ((count - last_count) + 500000) / 1000000;
+ pentium_mhz = (count + 500000) / 1000000;
}
#endif
@@ -569,6 +569,15 @@ cpu_initclocks()
/* XXX */ (inthand2_t *)clkintr, &clk_imask,
/* unit */ 0);
INTREN(IRQ0);
+#ifdef I586_CPU
+ /*
+ * Finish setting up anti-jitter measures.
+ */
+ if (pentium_mhz) {
+ I586_CYCLECTR(i586_last_tick);
+ i586_ctr_bias = i586_last_tick;
+ }
+#endif
/* Initialize RTC. */
writertc(RTC_STATUSA, rtc_statusa);
diff --git a/sys/i386/i386/microtime.s b/sys/i386/i386/microtime.s
index 19031c7..2326856 100644
--- a/sys/i386/i386/microtime.s
+++ b/sys/i386/i386/microtime.s
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: Steve McCanne's microtime code
- * $Id: microtime.s,v 1.6 1994/08/13 17:45:09 wollman Exp $
+ * $Id: microtime.s,v 1.7 1994/11/05 23:53:46 bde Exp $
*/
#include <machine/asmacros.h>
@@ -46,8 +46,6 @@ ENTRY(microtime)
movl _pentium_mhz, %ecx
testl %ecx, %ecx
jne pentium_microtime
-#else
- xorl %ecx, %ecx # clear ecx
#endif
movb $TIMER_SEL0|TIMER_LATCH, %al # prepare to latch
@@ -173,9 +171,13 @@ common_microtime:
ret
+ .extern _i586_ctr_bias
+
ALIGN_TEXT
pentium_microtime:
cli
.byte 0x0f, 0x31 # RDTSC
+ subl _i586_ctr_bias, %eax
+ sbbl _i586_ctr_bias+4, %edx
divl %ecx # get value in usec
jmp common_microtime
diff --git a/sys/i386/i386/tsc.c b/sys/i386/i386/tsc.c
index 188e25b..310972f 100644
--- a/sys/i386/i386/tsc.c
+++ b/sys/i386/i386/tsc.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
- * $Id: clock.c,v 1.35 1995/06/11 19:31:18 rgrimes Exp $
+ * $Id: clock.c,v 1.36 1995/08/25 19:24:56 bde Exp $
*/
/*
@@ -95,6 +95,8 @@ int disable_rtc_set = 0; /* disable resettodr() if != 0 */
u_int idelayed;
#ifdef I586_CPU
int pentium_mhz;
+long long i586_ctr_bias;
+long long i586_last_tick;
#endif
u_int stat_imask = SWI_CLOCK_MASK;
int timer0_max_count;
@@ -279,8 +281,6 @@ getit(void)
}
#ifdef I586_CPU
-static long long cycles_per_sec = 0;
-
/*
* Figure out how fast the cyclecounter runs. This must be run with
* clock interrupts disabled, but with the timer/counter programmed
@@ -293,15 +293,15 @@ calibrate_cyclecounter(void)
* Don't need volatile; should always use unsigned if 2's
* complement arithmetic is desired.
*/
- unsigned long long count, last_count;
+ unsigned long long count;
- __asm __volatile(".byte 0xf,0x31" : "=A" (last_count));
+ __asm __volatile(".byte 0x0f, 0x30" : : "A"(0LL), "c" (0x10));
DELAY(1000000);
__asm __volatile(".byte 0xf,0x31" : "=A" (count));
/*
* XX lose if the clock rate is not nearly a multiple of 1000000.
*/
- pentium_mhz = ((count - last_count) + 500000) / 1000000;
+ pentium_mhz = (count + 500000) / 1000000;
}
#endif
@@ -569,6 +569,15 @@ cpu_initclocks()
/* XXX */ (inthand2_t *)clkintr, &clk_imask,
/* unit */ 0);
INTREN(IRQ0);
+#ifdef I586_CPU
+ /*
+ * Finish setting up anti-jitter measures.
+ */
+ if (pentium_mhz) {
+ I586_CYCLECTR(i586_last_tick);
+ i586_ctr_bias = i586_last_tick;
+ }
+#endif
/* Initialize RTC. */
writertc(RTC_STATUSA, rtc_statusa);
diff --git a/sys/i386/include/clock.h b/sys/i386/include/clock.h
index 3d87a07..96476a7 100644
--- a/sys/i386/include/clock.h
+++ b/sys/i386/include/clock.h
@@ -8,40 +8,35 @@
#define _MACHINE_CLOCK_H_
#ifdef I586_CPU
- /*
- * This resets the CPU cycle counter to zero, to make our
- * job easier in microtime(). Some fancy ifdefs could speed
- * this up for Pentium-only kernels.
- * We want this to be done as close as possible to the actual
- * timer incrementing in hardclock(), because there is a window
- * between the two where the value is no longer valid. Experimentation
- * may reveal a good precompensation to apply in microtime().
- */
+
+#define I586_CYCLECTR(x) \
+ __asm __volatile(".byte 0x0f, 0x31" : "=A" (x))
+
+/*
+ * When we update the clock, we also update this bias value which is
+ * automatically subtracted in microtime(). We assume that CPU_THISTICKLEN()
+ * has been called at some point in the past, so that an appropriate value is
+ * set up in i586_last_tick. (This works even if we are not being called
+ * from hardclock because hardclock will have run before and will made the
+ * call.)
+ */
#define CPU_CLOCKUPDATE(otime, ntime) \
do { \
if(pentium_mhz) { \
- __asm __volatile("cli\n" \
- "movl (%2),%%eax\n" \
- "movl %%eax,(%1)\n" \
- "movl 4(%2),%%eax\n" \
- "movl %%eax,4(%1)\n" \
- "movl $0x10,%%ecx\n" \
- "xorl %%eax,%%eax\n" \
- "movl %%eax,%%edx\n" \
- ".byte 0x0f, 0x30\n" \
- "sti\n" \
- "#%0%1%2" \
- : "=m"(*otime) /* no outputs */ \
- : "c"(otime), "b"(ntime) /* fake input */ \
- : "ax", "cx", "dx"); \
+ disable_intr(); \
+ i586_ctr_bias = i586_last_tick; \
+ *(otime) = *(ntime); \
+ enable_intr(); \
} else { \
*(otime) = *(ntime); \
} \
} while(0)
+#define CPU_THISTICKLEN(dflt) cpu_thisticklen(dflt)
#else
#define CPU_CLOCKUPDATE(otime, ntime) \
(*(otime) = *(ntime))
+#define CPU_THISTICKLEN(dflt) dflt
#endif
#if defined(KERNEL) && !defined(LOCORE)
@@ -57,6 +52,8 @@ extern int adjkerntz;
extern int disable_rtc_set;
#ifdef I586_CPU
extern int pentium_mhz;
+extern long long i586_last_tick;
+extern long long i586_ctr_bias;
#endif
extern int timer0_max_count;
extern u_int timer0_overflow_threshold;
@@ -68,6 +65,24 @@ void calibrate_cyclecounter __P((void));
void clkintr __P((struct clockframe frame));
void rtcintr __P((struct clockframe frame));
+#ifdef I586_CPU
+static __inline u_long
+cpu_thisticklen(u_long dflt)
+{
+ long long old;
+ long rv;
+
+ if (pentium_mhz) {
+ old = i586_last_tick;
+ I586_CYCLECTR(i586_last_tick);
+ rv = (i586_last_tick - old) / pentium_mhz;
+ } else {
+ rv = dflt;
+ }
+ return rv;
+}
+#endif
+
/*
* Driver to clock driver interface.
*/
diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c
index 188e25b..310972f 100644
--- a/sys/i386/isa/clock.c
+++ b/sys/i386/isa/clock.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
- * $Id: clock.c,v 1.35 1995/06/11 19:31:18 rgrimes Exp $
+ * $Id: clock.c,v 1.36 1995/08/25 19:24:56 bde Exp $
*/
/*
@@ -95,6 +95,8 @@ int disable_rtc_set = 0; /* disable resettodr() if != 0 */
u_int idelayed;
#ifdef I586_CPU
int pentium_mhz;
+long long i586_ctr_bias;
+long long i586_last_tick;
#endif
u_int stat_imask = SWI_CLOCK_MASK;
int timer0_max_count;
@@ -279,8 +281,6 @@ getit(void)
}
#ifdef I586_CPU
-static long long cycles_per_sec = 0;
-
/*
* Figure out how fast the cyclecounter runs. This must be run with
* clock interrupts disabled, but with the timer/counter programmed
@@ -293,15 +293,15 @@ calibrate_cyclecounter(void)
* Don't need volatile; should always use unsigned if 2's
* complement arithmetic is desired.
*/
- unsigned long long count, last_count;
+ unsigned long long count;
- __asm __volatile(".byte 0xf,0x31" : "=A" (last_count));
+ __asm __volatile(".byte 0x0f, 0x30" : : "A"(0LL), "c" (0x10));
DELAY(1000000);
__asm __volatile(".byte 0xf,0x31" : "=A" (count));
/*
* XX lose if the clock rate is not nearly a multiple of 1000000.
*/
- pentium_mhz = ((count - last_count) + 500000) / 1000000;
+ pentium_mhz = (count + 500000) / 1000000;
}
#endif
@@ -569,6 +569,15 @@ cpu_initclocks()
/* XXX */ (inthand2_t *)clkintr, &clk_imask,
/* unit */ 0);
INTREN(IRQ0);
+#ifdef I586_CPU
+ /*
+ * Finish setting up anti-jitter measures.
+ */
+ if (pentium_mhz) {
+ I586_CYCLECTR(i586_last_tick);
+ i586_ctr_bias = i586_last_tick;
+ }
+#endif
/* Initialize RTC. */
writertc(RTC_STATUSA, rtc_statusa);
diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c
index 188e25b..310972f 100644
--- a/sys/isa/atrtc.c
+++ b/sys/isa/atrtc.c
@@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
- * $Id: clock.c,v 1.35 1995/06/11 19:31:18 rgrimes Exp $
+ * $Id: clock.c,v 1.36 1995/08/25 19:24:56 bde Exp $
*/
/*
@@ -95,6 +95,8 @@ int disable_rtc_set = 0; /* disable resettodr() if != 0 */
u_int idelayed;
#ifdef I586_CPU
int pentium_mhz;
+long long i586_ctr_bias;
+long long i586_last_tick;
#endif
u_int stat_imask = SWI_CLOCK_MASK;
int timer0_max_count;
@@ -279,8 +281,6 @@ getit(void)
}
#ifdef I586_CPU
-static long long cycles_per_sec = 0;
-
/*
* Figure out how fast the cyclecounter runs. This must be run with
* clock interrupts disabled, but with the timer/counter programmed
@@ -293,15 +293,15 @@ calibrate_cyclecounter(void)
* Don't need volatile; should always use unsigned if 2's
* complement arithmetic is desired.
*/
- unsigned long long count, last_count;
+ unsigned long long count;
- __asm __volatile(".byte 0xf,0x31" : "=A" (last_count));
+ __asm __volatile(".byte 0x0f, 0x30" : : "A"(0LL), "c" (0x10));
DELAY(1000000);
__asm __volatile(".byte 0xf,0x31" : "=A" (count));
/*
* XX lose if the clock rate is not nearly a multiple of 1000000.
*/
- pentium_mhz = ((count - last_count) + 500000) / 1000000;
+ pentium_mhz = (count + 500000) / 1000000;
}
#endif
@@ -569,6 +569,15 @@ cpu_initclocks()
/* XXX */ (inthand2_t *)clkintr, &clk_imask,
/* unit */ 0);
INTREN(IRQ0);
+#ifdef I586_CPU
+ /*
+ * Finish setting up anti-jitter measures.
+ */
+ if (pentium_mhz) {
+ I586_CYCLECTR(i586_last_tick);
+ i586_ctr_bias = i586_last_tick;
+ }
+#endif
/* Initialize RTC. */
writertc(RTC_STATUSA, rtc_statusa);
OpenPOWER on IntegriCloud