Servers request TSC freq from kernel rather than each one measuring it individually
This commit is contained in:
parent
9b8f37bb27
commit
04229f0581
|
@ -10,7 +10,10 @@
|
||||||
|
|
||||||
#include "sysutil.h"
|
#include "sysutil.h"
|
||||||
|
|
||||||
#define CALIBRATE_TICKS(h) ((h)/5)
|
#ifndef CONFIG_MAX_CPUS
|
||||||
|
#define CONFIG_MAX_CPUS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MICROHZ 1000000 /* number of micros per second */
|
#define MICROHZ 1000000 /* number of micros per second */
|
||||||
#define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */
|
#define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */
|
||||||
|
|
||||||
|
@ -21,42 +24,28 @@
|
||||||
panic("calibrate failed: %d", r); \
|
panic("calibrate failed: %d", r); \
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32_t calib_tsc, Hz = 0;
|
static u32_t calib_mhz, Hz = 0;
|
||||||
static int calibrated = 0;
|
static int calibrated = 0;
|
||||||
|
|
||||||
int
|
int
|
||||||
tsc_calibrate(void)
|
tsc_calibrate(void)
|
||||||
{
|
{
|
||||||
u64_t start, end, diff;
|
struct cpu_info cpu_info[CONFIG_MAX_CPUS];
|
||||||
struct tms tms;
|
|
||||||
unsigned long t = 0;
|
|
||||||
|
|
||||||
/* Get HZ. */
|
/* Get HZ. */
|
||||||
Hz = sys_hz();
|
Hz = sys_hz();
|
||||||
|
|
||||||
/* Wait for clock to tick. */
|
/* Obtain CPU frequency from kernel */
|
||||||
while(!t || (t == times(&tms)))
|
if (sys_getcpuinfo(&cpu_info)) {
|
||||||
t = times(&tms);
|
printf("tsc_calibrate: cannot get cpu info\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
t++;
|
/* For now, use the frequency of the first CPU; everything here will
|
||||||
|
* break down in case we get scheduled on multiple CPUs with different
|
||||||
/* Wait for clock to tick CALIBRATE_TICKS times, and time
|
* frequencies regardless
|
||||||
* this using the TSC.
|
|
||||||
*/
|
*/
|
||||||
read_tsc_64(&start);
|
calib_mhz = cpu_info[0].freq;
|
||||||
while(times(&tms) < t+CALIBRATE_TICKS(Hz)) ;
|
|
||||||
read_tsc_64(&end);
|
|
||||||
|
|
||||||
diff = sub64(end, start);
|
|
||||||
if(ex64hi(diff) != 0)
|
|
||||||
panic("tsc_calibrate: CALIBRATE_TICKS too high for TSC frequency");
|
|
||||||
calib_tsc = ex64lo(diff);
|
|
||||||
#if 0
|
|
||||||
printf("tsc_calibrate: "
|
|
||||||
"%lu cycles/%d ticks of %d Hz; %lu cycles/s\n",
|
|
||||||
calib_tsc, CALIBRATE_TICKS(Hz), Hz,
|
|
||||||
div64u(mul64u(calib_tsc, Hz), CALIBRATE_TICKS(Hz)));
|
|
||||||
#endif
|
|
||||||
calibrated = 1;
|
calibrated = 1;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -73,8 +62,7 @@ micro_delay(u32_t micros)
|
||||||
CALIBRATE;
|
CALIBRATE;
|
||||||
|
|
||||||
/* We have to know when to end the delay. */
|
/* We have to know when to end the delay. */
|
||||||
end = add64u(now, div64u(mul64u(calib_tsc,
|
end = add64(now, mul64u(micros, calib_mhz * 1000));
|
||||||
micros * Hz / CALIBRATE_TICKS(Hz)), MICROHZ));
|
|
||||||
|
|
||||||
/* If we have to wait for at least one HZ tick, use the regular
|
/* If we have to wait for at least one HZ tick, use the regular
|
||||||
* tickdelay first. Round downwards on purpose, so the average
|
* tickdelay first. Round downwards on purpose, so the average
|
||||||
|
@ -95,39 +83,17 @@ micro_delay(u32_t micros)
|
||||||
u32_t tsc_64_to_micros(u64_t tsc)
|
u32_t tsc_64_to_micros(u64_t tsc)
|
||||||
{
|
{
|
||||||
u64_t tmp;
|
u64_t tmp;
|
||||||
u32_t imv;
|
|
||||||
|
|
||||||
CALIBRATE;
|
CALIBRATE;
|
||||||
|
|
||||||
/* Various formulas provide various levels of accuracy depending on
|
tmp = div64u64(tsc, calib_mhz);
|
||||||
* what still fits in a 64-bit number.
|
if (ex64hi(tmp)) {
|
||||||
*/
|
printf("tsc_64_to_micros: more than 2^32ms\n");
|
||||||
if (ex64hi(tsc) != 0) {
|
return ~0UL;
|
||||||
if (ex64hi(tsc) < ULONG_MAX) {
|
} else {
|
||||||
tmp = mul64u(ex64hi(tsc) + 1, MICROHZ);
|
return ex64lo(tmp);
|
||||||
|
|
||||||
if (ex64hi(tmp) == 0) {
|
|
||||||
imv = div64u(mul64(tsc, cvu64(MICROHZ)),
|
|
||||||
calib_tsc);
|
|
||||||
|
|
||||||
tmp = mul64u(imv, CALIBRATE_TICKS(Hz));
|
|
||||||
|
|
||||||
if (ex64hi(tmp) == 0) {
|
|
||||||
/* Mid accuracy. */
|
|
||||||
return ex64lo(tmp) / Hz;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Low accuracy for large numbers. */
|
|
||||||
return div64u(mul64u(div64u(tsc, calib_tsc),
|
|
||||||
MICROHZ * CALIBRATE_TICKS(Hz)), Hz);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* High accuracy for small numbers (the common case). */
|
|
||||||
return div64u(mul64u(ex64lo(tsc), MICROHZ * CALIBRATE_TICKS(Hz)),
|
|
||||||
calib_tsc) / Hz;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32_t tsc_to_micros(u32_t low, u32_t high)
|
u32_t tsc_to_micros(u32_t low, u32_t high)
|
||||||
{
|
{
|
||||||
|
@ -138,5 +104,5 @@ u32_t tsc_get_khz(void)
|
||||||
{
|
{
|
||||||
CALIBRATE;
|
CALIBRATE;
|
||||||
|
|
||||||
return calib_tsc / (CALIBRATE_TICKS(Hz) * MICROSPERTICK(Hz)) * 1000;
|
return calib_mhz * 1000;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue