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"
 | 
			
		||||
 | 
			
		||||
#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 MICROSPERTICK(h)	(MICROHZ/(h))	/* number of micros per HZ tick */
 | 
			
		||||
 | 
			
		||||
@ -21,42 +24,28 @@
 | 
			
		||||
			panic("calibrate failed: %d", r); \
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
static u32_t calib_tsc, Hz = 0;
 | 
			
		||||
static u32_t calib_mhz, Hz = 0;
 | 
			
		||||
static int calibrated = 0;
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
tsc_calibrate(void)
 | 
			
		||||
{
 | 
			
		||||
	u64_t start, end, diff;
 | 
			
		||||
	struct tms tms;
 | 
			
		||||
	unsigned long t = 0;
 | 
			
		||||
	struct cpu_info cpu_info[CONFIG_MAX_CPUS];
 | 
			
		||||
 | 
			
		||||
	/* Get HZ. */
 | 
			
		||||
	Hz = sys_hz();
 | 
			
		||||
 | 
			
		||||
	/* Wait for clock to tick. */
 | 
			
		||||
	while(!t || (t == times(&tms)))
 | 
			
		||||
		t = times(&tms);
 | 
			
		||||
	/* Obtain CPU frequency from kernel */
 | 
			
		||||
	if (sys_getcpuinfo(&cpu_info)) {
 | 
			
		||||
		printf("tsc_calibrate: cannot get cpu info\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	t++;
 | 
			
		||||
 | 
			
		||||
	/* Wait for clock to tick CALIBRATE_TICKS times, and time
 | 
			
		||||
	 * this using the TSC.
 | 
			
		||||
	/* For now, use the frequency of the first CPU; everything here will 
 | 
			
		||||
	 * break down in case we get scheduled on multiple CPUs with different 
 | 
			
		||||
	 * frequencies regardless
 | 
			
		||||
	 */
 | 
			
		||||
	read_tsc_64(&start);
 | 
			
		||||
	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
 | 
			
		||||
	calib_mhz = cpu_info[0].freq;
 | 
			
		||||
	calibrated = 1;
 | 
			
		||||
 | 
			
		||||
	return OK;
 | 
			
		||||
@ -73,8 +62,7 @@ micro_delay(u32_t micros)
 | 
			
		||||
	CALIBRATE;
 | 
			
		||||
 | 
			
		||||
	/* We have to know when to end the delay. */
 | 
			
		||||
	end = add64u(now, div64u(mul64u(calib_tsc,
 | 
			
		||||
		micros * Hz / CALIBRATE_TICKS(Hz)), MICROHZ));
 | 
			
		||||
	end = add64(now, mul64u(micros, calib_mhz * 1000));
 | 
			
		||||
 | 
			
		||||
	/* If we have to wait for at least one HZ tick, use the regular
 | 
			
		||||
	 * tickdelay first. Round downwards on purpose, so the average
 | 
			
		||||
@ -95,38 +83,16 @@ micro_delay(u32_t micros)
 | 
			
		||||
u32_t tsc_64_to_micros(u64_t tsc)
 | 
			
		||||
{
 | 
			
		||||
	u64_t tmp;
 | 
			
		||||
	u32_t imv;
 | 
			
		||||
 | 
			
		||||
	CALIBRATE;
 | 
			
		||||
 | 
			
		||||
	/* Various formulas provide various levels of accuracy depending on
 | 
			
		||||
	 * what still fits in a 64-bit number.
 | 
			
		||||
	 */
 | 
			
		||||
	if (ex64hi(tsc) != 0) {
 | 
			
		||||
		if (ex64hi(tsc) < ULONG_MAX) {
 | 
			
		||||
			tmp = mul64u(ex64hi(tsc) + 1, MICROHZ);
 | 
			
		||||
 | 
			
		||||
			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);
 | 
			
		||||
	tmp = div64u64(tsc, calib_mhz);
 | 
			
		||||
	if (ex64hi(tmp)) {
 | 
			
		||||
		printf("tsc_64_to_micros: more than 2^32ms\n");
 | 
			
		||||
		return ~0UL;
 | 
			
		||||
	} else {
 | 
			
		||||
		return ex64lo(tmp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* 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)
 | 
			
		||||
@ -138,5 +104,5 @@ u32_t tsc_get_khz(void)
 | 
			
		||||
{
 | 
			
		||||
	CALIBRATE;
 | 
			
		||||
 | 
			
		||||
	return calib_tsc / (CALIBRATE_TICKS(Hz) * MICROSPERTICK(Hz)) * 1000;
 | 
			
		||||
	return calib_mhz * 1000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user