minix/lib/libsys/tsc_util.c
Ben Gras 35a108b911 panic() cleanup.
this change
   - makes panic() variadic, doing full printf() formatting -
     no more NO_NUM, and no more separate printf() statements
     needed to print extra info (or something in hex) before panicing
   - unifies panic() - same panic() name and usage for everyone -
     vm, kernel and rest have different names/syntax currently
     in order to implement their own luxuries, but no longer
   - throws out the 1st argument, to make source less noisy.
     the panic() in syslib retrieves the server name from the kernel
     so it should be clear enough who is panicing; e.g.
         panic("sigaction failed: %d", errno);
     looks like:
         at_wini(73130): panic: sigaction failed: 0
         syslib:panic.c: stacktrace: 0x74dc 0x2025 0x100a
   - throws out report() - printf() is more convenient and powerful
   - harmonizes/fixes the use of panic() - there were a few places
     that used printf-style formatting (didn't work) and newlines
     (messes up the formatting) in panic()
   - throws out a few per-server panic() functions
   - cleans up a tie-in of tty with panic()

merging printf() and panic() statements to be done incrementally.
2010-03-05 15:05:11 +00:00

114 lines
2.3 KiB
C

#include <stdio.h>
#include <time.h>
#include <sys/times.h>
#include <sys/types.h>
#include <minix/u64.h>
#include <minix/config.h>
#include <minix/const.h>
#include "sysutil.h"
#define CALIBRATE_TICKS(h) ((h)/5)
#define MICROHZ 1000000 /* number of micros per second */
#define MICROSPERTICK(h) (MICROHZ/(h)) /* number of micros per HZ tick */
#define CALIBRATE \
if(!calibrated) { \
int r; \
if((r=tsc_calibrate()) != OK) \
panic("calibrate failed: %d", r); \
}
static u32_t calib_tsc, Hz = 0;
static int calibrated = 0;
int
tsc_calibrate(void)
{
u64_t start, end, diff;
struct tms tms;
unsigned long t = 0;
/* Get HZ. */
Hz = sys_hz();
/* Wait for clock to tick. */
while(!t || (t == times(&tms)))
t = times(&tms);
t++;
/* Wait for clock to tick CALIBRATE_TICKS times, and time
* this using the TSC.
*/
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
calibrated = 1;
return OK;
}
int
micro_delay(u32_t micros)
{
u64_t now, end;
/* Start of delay. */
read_tsc_64(&now);
CALIBRATE;
/* We have to know when to end the delay. */
end = add64u(now, div64u(mul64u(calib_tsc,
micros * Hz / CALIBRATE_TICKS(Hz)), MICROHZ));
/* If we have to wait for at least one HZ tick, use the regular
* tickdelay first. Round downwards on purpose, so the average
* half-tick we wait short (depending on where in the current tick
* we call tickdelay). We can correct for both overhead of tickdelay
* itself and the short wait in the busywait later.
*/
if(micros >= MICROSPERTICK(Hz))
tickdelay(micros*Hz/MICROHZ);
/* Wait (the rest) of the delay time using busywait. */
while(cmp64(now, end) < 0)
read_tsc_64(&now);
return OK;
}
u32_t tsc_64_to_micros(u64_t tsc)
{
return tsc_to_micros(ex64lo(tsc), ex64hi(tsc));
}
u32_t tsc_to_micros(u32_t low, u32_t high)
{
u32_t micros;
if(high) {
return 0;
}
CALIBRATE;
micros = (div64u(mul64u(low, MICROHZ * CALIBRATE_TICKS(Hz)),
calib_tsc)/Hz);
return micros;
}