Beispiel #1
0
/*
 * DFE: Measures the TSC frequency in Hz (64-bit) using the ACPI PM timer
 */
static uint64_t measure_tsc_frequency(void)
{
	uint64_t tscStart;
	uint64_t tscEnd;
	uint64_t tscDelta = 0xffffffffffffffffULL;
	unsigned long pollCount;
	uint64_t retval = 0;
	int i;
	
	/* Time how many TSC ticks elapse in 30 msec using the 8254 PIT
	 * counter 2. We run this loop 3 times to make sure the cache
	 * is hot and we take the minimum delta from all of the runs.
	 * That is to say that we're biased towards measuring the minimum
	 * number of TSC ticks that occur while waiting for the timer to
	 * expire. That theoretically helps avoid inconsistencies when
	 * running under a VM if the TSC is not virtualized and the host
	 * steals time.	 The TSC is normally virtualized for VMware.
	 */
	for(i = 0; i < 10; ++i)
	{
		enable_PIT2();
		set_PIT2_mode0(CALIBRATE_LATCH);
		tscStart = rdtsc64();
		pollCount = poll_PIT2_gate();
		tscEnd = rdtsc64();
		/* The poll loop must have run at least a few times for accuracy */
		if (pollCount <= 1)
			continue;
		/* The TSC must increment at LEAST once every millisecond.
		 * We should have waited exactly 30 msec so the TSC delta should
		 * be >= 30. Anything less and the processor is way too slow.
		 */
		if ((tscEnd - tscStart) <= CALIBRATE_TIME_MSEC)
			continue;
		// tscDelta = MIN(tscDelta, (tscEnd - tscStart))
		if ( (tscEnd - tscStart) < tscDelta )
			tscDelta = tscEnd - tscStart;
	}
	/* tscDelta is now the least number of TSC ticks the processor made in
	 * a timespan of 0.03 s (e.g. 30 milliseconds)
	 * Linux thus divides by 30 which gives the answer in kiloHertz because
	 * 1 / ms = kHz. But we're xnu and most of the rest of the code uses
	 * Hz so we need to convert our milliseconds to seconds. Since we're
	 * dividing by the milliseconds, we simply multiply by 1000.
	 */
	
	/* Unlike linux, we're not limited to 32-bit, but we do need to take care
	 * that we're going to multiply by 1000 first so we do need at least some
	 * arithmetic headroom. For now, 32-bit should be enough.
	 * Also unlike Linux, our compiler can do 64-bit integer arithmetic.
	 */
	if (tscDelta > (1ULL<<32))
		retval = 0;
	else
	{
		retval = tscDelta * 1000 / 30;
	}
	disable_PIT2();
	return retval;
}
Beispiel #2
0
void
cpu_exit_wait(
	int cpu)
{
    	cpu_data_t	*cdp = cpu_datap(cpu);
	boolean_t	intrs_enabled;
	uint64_t	tsc_timeout;

	/*
	 * Wait until the CPU indicates that it has stopped.
	 * Disable interrupts while the topo lock is held -- arguably
	 * this should always be done but in this instance it can lead to
	 * a timeout if long-running interrupt were to occur here.
	 */
	intrs_enabled = ml_set_interrupts_enabled(FALSE);
	simple_lock(&x86_topo_lock);
	/* Set a generous timeout of several seconds (in TSC ticks) */
	tsc_timeout = rdtsc64() + (10ULL * 1000 * 1000 * 1000);
	while ((cdp->lcpu.state != LCPU_HALT)
	       && (cdp->lcpu.state != LCPU_OFF)
	       && !cdp->lcpu.stopped) {
	    simple_unlock(&x86_topo_lock);
	    ml_set_interrupts_enabled(intrs_enabled);
	    cpu_pause();
	    if (rdtsc64() > tsc_timeout)
		panic("cpu_exit_wait(%d) timeout", cpu);
	    ml_set_interrupts_enabled(FALSE);
	    simple_lock(&x86_topo_lock);
	}
	simple_unlock(&x86_topo_lock);
	ml_set_interrupts_enabled(intrs_enabled);
}
Beispiel #3
0
/*
 * rtc_nanotime_init:
 *
 * Intialize the nanotime info from the base time.
 */
static inline void
_rtc_nanotime_init(pal_rtc_nanotime_t *rntp, uint64_t base)
{
	uint64_t	tsc = rdtsc64();

	_pal_rtc_nanotime_store(tsc, base, rntp->scale, rntp->shift, rntp);
}
Beispiel #4
0
static uint64_t
rtc_lapic_set_tsc_deadline_timer(uint64_t deadline, uint64_t now)
{
	uint64_t delta;
	uint64_t delta_tsc;
	uint64_t tsc = rdtsc64();
	uint64_t set = 0;

	if (deadline > 0) {
		/*
		 * Convert to TSC
		 */
		delta = deadline_to_decrementer(deadline, now);
		set = now + delta;
		delta_tsc = tmrCvt(delta, tscFCvtn2t);
		lapic_set_tsc_deadline_timer(tsc + delta_tsc);
	} else {
		lapic_set_tsc_deadline_timer(0);
	}
	
	KERNEL_DEBUG_CONSTANT(
		DECR_SET_TSC_DEADLINE | DBG_FUNC_NONE,
		now, deadline,
		tsc, lapic_get_tsc_deadline_timer(),
		0);

	return set;
} 
Beispiel #5
0
uint64_t calc_rdtsc_overhead() {
  uint32_t TRIALS = 1000000;
  uint64_t* times = (uint64_t*) calloc(TRIALS,sizeof(uint64_t));
 
  uint64_t start=0, end=0;
  for(uint32_t i = 0; i < TRIALS; i++){
    start = rdtsc64();
    end = rdtsc64();
    times[i] = (end -start)>0?(end - start):0;
  }
  gsl_sort_ulong((unsigned long*)times,1,TRIALS);
  uint64_t median = gsl_stats_ulong_median_from_sorted_data ((unsigned long*)times,1,TRIALS);
#ifdef DEBUG
  double mean = gsl_stats_ulong_mean(times, 1, TRIALS);
  double sd = gsl_stats_ulong_sd(times, 1, TRIALS);
  uint64_t max = times[TRIALS-1];
  uint64_t min = times[0];
#endif
  free(times);
#ifdef DEBUG
  printf("| Median: %lu | Mean: %6.3f | Std Deviation: %6.3f | Min: %lu | Max: %lu |\n",median,mean,sd,min,max);
#endif
  return median; 
}
Beispiel #6
0
static void update_clock(void)
{
	uint64_t delta = rdtsc64() - private_clock.ticks;
	int secs;

	private_clock.ticks += delta;

	secs = (int) (delta / TICKS_PER_SEC);
	private_clock.secs += secs;
	delta -= (secs * TICKS_PER_SEC);
	private_clock.usecs += (int) (delta / TICKS_PER_USEC);

	if (private_clock.usecs > 1000000) {
		private_clock.usecs -= 1000000;
		private_clock.secs++;
	}
}
Beispiel #7
0
/*
 * rtc_clock_napped:
 *
 * Invoked from power management when we exit from a low C-State (>= C4)
 * and the TSC has stopped counting.  The nanotime data is updated according
 * to the provided value which represents the new value for nanotime.
 */
void
rtc_clock_napped(uint64_t base, uint64_t tsc_base)
{
	pal_rtc_nanotime_t	*rntp = &pal_rtc_nanotime_info;
	uint64_t	oldnsecs;
	uint64_t	newnsecs;
	uint64_t	tsc;

	assert(!ml_get_interrupts_enabled());
	tsc = rdtsc64();
	oldnsecs = rntp->ns_base + _rtc_tsc_to_nanoseconds(tsc - rntp->tsc_base, rntp);
	newnsecs = base + _rtc_tsc_to_nanoseconds(tsc - tsc_base, rntp);
	
	/*
	 * Only update the base values if time using the new base values
	 * is later than the time using the old base values.
	 */
	if (oldnsecs < newnsecs) {
	    _pal_rtc_nanotime_store(tsc_base, base, rntp->scale, rntp->shift, rntp);
	    rtc_nanotime_set_commpage(rntp);
	}
}
Beispiel #8
0
static void gettimeofday_init(void)
{
	int days, delta;
	struct tm tm;

	rtc_read_clock(&tm);
	private_clock.ticks = rdtsc64();

	/* Calculate the number of days in the year so far */
	days = day_of_year(tm.tm_mon, tm.tm_mday, tm.tm_year + 1900);

	delta = tm.tm_year - 70;

	days += (delta * 365);

	/* Figure leap years */

	if (delta > 2)
	  days += (delta - 2) / 4;

	private_clock.secs = (days * 86400) + (tm.tm_hour * 3600) +
		(tm.tm_min * 60) + tm.tm_sec;
}
Beispiel #9
0
/*
 * timeRDTSC()
 * This routine sets up PIT counter 2 to count down 1/20 of a second.
 * It pauses until the value is latched in the counter
 * and then reads the time stamp counter to return to the caller.
 */
uint64_t timeRDTSC(void)
{
    int		attempts = 0;
    uint64_t    latchTime;
    uint64_t	saveTime,intermediate;
    unsigned int timerValue, lastValue;
    //boolean_t	int_enabled;
    /*
     * Table of correction factors to account for
     *	 - timer counter quantization errors, and
     *	 - undercounts 0..5
     */
#define SAMPLE_CLKS_EXACT	(((double) CLKNUM) / 20.0)
#define SAMPLE_CLKS_INT		((int) CLKNUM / 20)
#define SAMPLE_NSECS		(2000000000LL)
#define SAMPLE_MULTIPLIER	(((double)SAMPLE_NSECS)*SAMPLE_CLKS_EXACT)
#define ROUND64(x)		((uint64_t)((x) + 0.5))
    uint64_t	scale[6] = {
		ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-0)), 
		ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-1)), 
		ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-2)), 
		ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-3)), 
		ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-4)), 
		ROUND64(SAMPLE_MULTIPLIER/(double)(SAMPLE_CLKS_INT-5))
    };
    
    //int_enabled = ml_set_interrupts_enabled(FALSE);
    
restart:
    if (attempts >= 9) // increase to up to 9 attempts.
    {
        // This will flash-reboot. TODO: Use tscPanic instead.
        printf("Timestamp counter calibation failed with %d attempts\n", attempts);
    }
    attempts++;
    enable_PIT2();		// turn on PIT2
    set_PIT2(0);		// reset timer 2 to be zero
    latchTime = rdtsc64();	// get the time stamp to time 
    latchTime = get_PIT2(&timerValue) - latchTime; // time how long this takes
    set_PIT2(SAMPLE_CLKS_INT);	// set up the timer for (almost) 1/20th a second
    saveTime = rdtsc64();	// now time how long a 20th a second is...
    get_PIT2(&lastValue);
    get_PIT2(&lastValue);	// read twice, first value may be unreliable
    do {
		intermediate = get_PIT2(&timerValue);
		if (timerValue > lastValue)
        {
			// Timer wrapped
			set_PIT2(0);
			disable_PIT2();
			goto restart;
		}
		lastValue = timerValue;
    } while (timerValue > 5);
    printf("timerValue	  %d\n",timerValue);
    printf("intermediate 0x%016llx\n",intermediate);
    printf("saveTime	  0x%016llx\n",saveTime);
    
    intermediate -= saveTime;		// raw count for about 1/20 second
    intermediate *= scale[timerValue];	// rescale measured time spent
    intermediate /= SAMPLE_NSECS;	// so its exactly 1/20 a second
    intermediate += latchTime;		// add on our save fudge
    
    set_PIT2(0);			// reset timer 2 to be zero
    disable_PIT2();			// turn off PIT 2

    //ml_set_interrupts_enabled(int_enabled);
    return intermediate;
}