diff options
author | njl <njl@FreeBSD.org> | 2005-02-05 23:16:27 +0000 |
---|---|---|
committer | njl <njl@FreeBSD.org> | 2005-02-05 23:16:27 +0000 |
commit | e0147243eb2cc8d8993b55f6439c404904806710 (patch) | |
tree | 0e1f039adcdea95909bcd77418b2001d569179ae | |
parent | 0138510ffdc9c9b9484b92c467ffcd5ecac8fa8d (diff) | |
download | FreeBSD-src-e0147243eb2cc8d8993b55f6439c404904806710.zip FreeBSD-src-e0147243eb2cc8d8993b55f6439c404904806710.tar.gz |
Make cpu_est_clockrate() more accurate by disabling interrupts for the
millisecond it is calibrating. Suggested by jhb@ and bde@. Don't clobber
the tsc_freq with the new value since it isn't accurate enough for
timecounters and the timecounter system as a whole needs support for
changing rates before we do this. Subtract 0.5% from our measurement
to account for overhead in DELAY. Note that this interface is for
estimating the clockrate and needs to work well at runtime so doing a full
calibration including disabling interrupts for a second is not feasible.
-rw-r--r-- | sys/amd64/amd64/machdep.c | 12 | ||||
-rw-r--r-- | sys/i386/i386/machdep.c | 12 |
2 files changed, 20 insertions, 4 deletions
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 527c61b..422c0fb 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -456,6 +456,7 @@ cpu_boot(int howto) int cpu_est_clockrate(int cpu_id, uint64_t *rate) { + register_t reg; uint64_t tsc1, tsc2; if (pcpu_find(cpu_id) == NULL || rate == NULL) @@ -475,9 +476,11 @@ cpu_est_clockrate(int cpu_id, uint64_t *rate) #endif /* Calibrate by measuring a short delay. */ + reg = intr_disable(); tsc1 = rdtsc(); DELAY(1000); tsc2 = rdtsc(); + intr_restore(reg); #ifdef SMP mtx_lock_spin(&sched_lock); @@ -485,8 +488,13 @@ cpu_est_clockrate(int cpu_id, uint64_t *rate) mtx_unlock_spin(&sched_lock); #endif - tsc_freq = (tsc2 - tsc1) * 1000; - *rate = tsc_freq; + /* + * Calculate the difference in readings, convert to Mhz, and + * subtract 0.5% of the total. Empirical testing has shown that + * overhead in DELAY() works out to approximately this value. + */ + tsc2 -= tsc1; + *rate = tsc2 * 1000 - tsc2 * 5; return (0); } diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index ef82b80..2c60c00 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -1028,6 +1028,7 @@ cpu_boot(int howto) int cpu_est_clockrate(int cpu_id, uint64_t *rate) { + register_t reg; uint64_t tsc1, tsc2; if (pcpu_find(cpu_id) == NULL || rate == NULL) @@ -1049,9 +1050,11 @@ cpu_est_clockrate(int cpu_id, uint64_t *rate) #endif /* Calibrate by measuring a short delay. */ + reg = intr_disable(); tsc1 = rdtsc(); DELAY(1000); tsc2 = rdtsc(); + intr_restore(reg); #ifdef SMP mtx_lock_spin(&sched_lock); @@ -1059,8 +1062,13 @@ cpu_est_clockrate(int cpu_id, uint64_t *rate) mtx_unlock_spin(&sched_lock); #endif - tsc_freq = (tsc2 - tsc1) * 1000; - *rate = tsc_freq; + /* + * Calculate the difference in readings, convert to Mhz, and + * subtract 0.5% of the total. Empirical testing has shown that + * overhead in DELAY() works out to approximately this value. + */ + tsc2 -= tsc1; + *rate = tsc2 * 1000 - tsc2 * 5; return (0); } |