/* * Precise timer routines using CoreFoundation * * (C) 2003 Dan Christiansen * * Released into the public domain. * * Changelog: * 07/05/2003 sleep_accurate() merged from timer-lx.c * updated to mplayer-g2 * 11/05/2003 rewritten using mach timing * * * TODO: * - figure out how to get a mach port w/o CoreFoundation * - use the run loop for long intervals */ /* About CFRunLoop: * * Being a run loop, it can be up to several seconds (or more) late if * another task runs. CFRunLoop offers interruptable sleep, but does not * deploy busy waiting; it uses the system even manager. It does seem to * use more CPU than blocking sleep, and is less accurate. * * About mach timing: * * These are kernel space timers, and appear to be the most accurate timers * available on Darwin. clock_sleep() is always a bit late, but never early. */ #include #include #include "../config.h" #include "timer.h" /* global variables */ static uint64_t relative_time, startup_time; static struct mach_timebase_info timebase; static mach_port_t mach_port; /* inaccurate timing with CFRunLoop */ int usec_sleep(int usec_delay) { float start, end; start = CFAbsoluteTimeGetCurrent(); CFRunLoopRunInMode(kCFRunLoopDefaultMode, usec_delay/1000000.0, false); end = CFAbsoluteTimeGetCurrent(); return (usec_delay-(end-start))*1000000; } /* accurate kernel-based timing */ float sleep_accurate(float time_frame) { mach_timespec_t ts; /* clock_sleep is always a little late */ ts.tv_sec = (long)time_frame; ts.tv_nsec = (long)((time_frame - 0.010) * 1000000000.0); GetRelativeTime(); clock_sleep(NULL, TIME_RELATIVE, ts, NULL); time_frame -= GetRelativeTime(); if (time_frame < -0.005 || time_frame > 0.010) mp_msg(MSGT_AVSYNC,MSGL_V, "time_frame=%f out of bounds! \n", time_frame); } return time_frame; } /* Returns current time in microseconds */ unsigned int GetTimer() { return (unsigned int)((double)(mach_absolute_time() - startup_time) / timebase.denom * timebase.numer / 1000); } /* Returns current time in milliseconds */ unsigned int GetTimerMS() { return (unsigned int)(GetTimer() / 1000); } /* Returns time spent between now and last call in seconds */ float GetRelativeTime() { uint64_t last_time = relative_time; if (!relative_time) InitTimer(); relative_time = mach_absolute_time(); return (float)(relative_time-last_time) / timebase.denom * timebase.numer / 1000000000; } /* dummy callback function */ static void mach_callback(CFMachPortRef port, void *msg, CFIndex size, void *info) { } /* Initialize timer, must be called at least once at start */ void InitTimer() { mach_port = CFMachPortGetPort(CFMachPortCreate(NULL, mach_callback, NULL, NULL)); mach_timebase_info(&timebase); relative_time = startup_time = mach_absolute_time(); } #if 0 int main() { int i; InitTimer(); for (i = 1; i < 20; i++) { printf("Time: %u sleep_accurate(): %lf\n", GetTimerMS(), sleep_accurate(0.1)); } } #endif