mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-03 10:29:15 +00:00
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.
This commit is contained in:
parent
07e3b0c25b
commit
e2d4b1f051
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=11452
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user