From 81439c5f35e604174408a2aaf4e4dec11b81ac39 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 17 May 2013 19:54:37 +0200 Subject: timer: refactor, add 64 bit timer function Make OS specific timer code export a mp_raw_time_us() function, and add generic implementations of GetTimer()/GetTimerMS() using this function. New mpv code is supposed to call mp_time_us() in situations where precision is absolutely needed, or mp_time_s() otherwise. Make it so that mp_time_us() will return a value near program start. We don't set it to 0 though to avoid confusion with relative vs. absolute time. Instead, pick an arbitrary offset. Move the test program in timer-darwin.c to timer.c, and modify it to work with the generic timer functions. --- osdep/timer-darwin.c | 66 ++++++------------------------------------ osdep/timer-linux.c | 32 ++++++++------------ osdep/timer-win2.c | 30 +++++++++---------- osdep/timer.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ osdep/timer.h | 24 +++++++++++++-- 5 files changed, 138 insertions(+), 96 deletions(-) create mode 100644 osdep/timer.c (limited to 'osdep') diff --git a/osdep/timer-darwin.c b/osdep/timer-darwin.c index 1ce9cd584b..e5f751915e 100644 --- a/osdep/timer-darwin.c +++ b/osdep/timer-darwin.c @@ -27,72 +27,24 @@ #include "core/mp_msg.h" #include "timer.h" -/* global variables */ static double timebase_ratio; - -/* the core sleep function, uses floats and is used in MPlayer G2 */ -static float sleep_accurate(float time_frame) +void mp_sleep_us(int64_t us) { - uint64_t deadline = time_frame / timebase_ratio + mach_absolute_time(); - - mach_wait_until(deadline); - - return (mach_absolute_time() - deadline) * timebase_ratio; -} + uint64_t deadline = us / 1e6 / timebase_ratio + mach_absolute_time(); -/* wrapper for MPlayer G1 */ -int usec_sleep(int usec_delay) -{ - return sleep_accurate(usec_delay / 1e6) * 1e6; + mach_wait_until(deadline); } - -/* current time in microseconds */ -unsigned int GetTimer(void) +uint64_t mp_raw_time_us(void) { - return (unsigned int)(uint64_t)(mach_absolute_time() * timebase_ratio * 1e6); + return mach_absolute_time() * timebase_ratio * 1e6; } -/* current time in milliseconds */ -unsigned int GetTimerMS(void) +void mp_raw_time_init(void) { - return (unsigned int)(uint64_t)(mach_absolute_time() * timebase_ratio * 1e3); -} - -/* initialize timer, must be called at least once at start */ -void InitTimer(void) -{ - struct mach_timebase_info timebase; - - mach_timebase_info(&timebase); - timebase_ratio = (double)timebase.numer / (double)timebase.denom - * (double)1e-9; -} - -#if 0 -#include - -int main(void) { - int i,j, r, c = 200; - long long t = 0; - - InitTimer(); - - for (i = 0; i < c; i++) { - const int delay = rand() / (RAND_MAX / 1e5); - j = GetTimer(); -#if 1 - r = usec_sleep(delay); -#else - r = sleep_accurate(delay / 1e6) * 1e6; -#endif - j = (GetTimer() - j) - delay; - printf("sleep time:%8i %5i (%i)\n", delay, j, j - r); - t += j - r; - } - fprintf(stderr, "average error:\t%lli\n", t / c); + struct mach_timebase_info timebase; - return 0; + mach_timebase_info(&timebase); + timebase_ratio = (double)timebase.numer / (double)timebase.denom * 1e-9; } -#endif diff --git a/osdep/timer-linux.c b/osdep/timer-linux.c index 63f7ad913f..314aa47b27 100644 --- a/osdep/timer-linux.c +++ b/osdep/timer-linux.c @@ -26,35 +26,27 @@ #include "config.h" #include "timer.h" -int usec_sleep(int usec_delay) +void mp_sleep_us(int64_t us) { + if (us < 0) + return; #ifdef HAVE_NANOSLEEP struct timespec ts; - ts.tv_sec = usec_delay / 1000000; - ts.tv_nsec = (usec_delay % 1000000) * 1000; - return nanosleep(&ts, NULL); + ts.tv_sec = us / 1000000; + ts.tv_nsec = (us % 1000000) * 1000; + nanosleep(&ts, NULL); #else - return usleep(usec_delay); + usleep(us); #endif } -// Returns current time in microseconds -unsigned int GetTimer(void) +uint64_t mp_raw_time_us(void) { - struct timeval tv; - gettimeofday(&tv,NULL); - return tv.tv_sec * 1000000 + tv.tv_usec; + struct timeval tv; + gettimeofday(&tv,NULL); + return tv.tv_sec * 1000000LL + tv.tv_usec; } -// Returns current time in milliseconds -unsigned int GetTimerMS(void) -{ - struct timeval tv; - gettimeofday(&tv,NULL); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -} - -// Initialize timer, must be called at least once at start -void InitTimer(void) +void mp_raw_time_init(void) { } diff --git a/osdep/timer-win2.c b/osdep/timer-win2.c index 88a047410d..99980d76bc 100644 --- a/osdep/timer-win2.c +++ b/osdep/timer-win2.c @@ -22,27 +22,25 @@ #include #include "timer.h" -// Returns current time in microseconds -unsigned int GetTimer(void) +void mp_sleep_us(int64_t us) { - return timeGetTime() * 1000; + if (us < 0) + return; + // Sleep(0) won't sleep for one clocktick as the unix usleep + // instead it will only make the thread ready + // it may take some time until it actually starts to run again + if (us < 1000) + us = 1000; + Sleep(us / 1000); } -// Returns current time in milliseconds -unsigned int GetTimerMS(void) +uint64_t mp_raw_time_us(void) { - return timeGetTime() ; + return timeGetTime() * 1000; } -int usec_sleep(int usec_delay){ - // Sleep(0) won't sleep for one clocktick as the unix usleep - // instead it will only make the thread ready - // it may take some time until it actually starts to run again - if(usec_delay<1000)usec_delay=1000; - Sleep( usec_delay/1000); - return 0; -} - -void InitTimer(void) +void mp_raw_time_init(void) { + // request 1ms timer resolution + timeBeginPeriod(1); } diff --git a/osdep/timer.c b/osdep/timer.c new file mode 100644 index 0000000000..2304bb1297 --- /dev/null +++ b/osdep/timer.c @@ -0,0 +1,82 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with mpv. If not, see . + */ + +#include + +#include "timer.h" + +static uint64_t raw_time_offset; + +void mp_time_init(void) +{ + mp_raw_time_init(); + srand(mp_raw_time_us()); + raw_time_offset = mp_raw_time_us(); + // Arbitrary additional offset to avoid confusing relative/absolute times. + // Also,we rule that the timer never returns 0 (so default-initialized + // time values will be always in the past). + raw_time_offset -= 10000000; +} + +int64_t mp_time_us(void) +{ + return mp_raw_time_us() - raw_time_offset; +} + +double mp_time_sec(void) +{ + return mp_time_us() / (double)(1000 * 1000); +} + +unsigned int GetTimer(void) +{ + return mp_time_us(); +} + +unsigned int GetTimerMS(void) +{ + return (mp_time_us() + 500) / 1000; +} + +int usec_sleep(int usec_delay) +{ + mp_sleep_us(usec_delay); + return 0; +} + +#if 0 +#include + +int main(void) { + int c = 200; + int64_t j, r, t = 0; + + mp_time_init(); + + for (int i = 0; i < c; i++) { + const int delay = rand() / (RAND_MAX / 1e5); + r = mp_time_us(); + mp_sleep_us(delay); + j = (mp_time_us() - r) - delay; + printf("sleep time: sleep=%8i err=%5i\n", delay, (int)j); + t += j; + } + fprintf(stderr, "average error:\t%i\n", (int)(t / c)); + + return 0; +} +#endif diff --git a/osdep/timer.h b/osdep/timer.h index fe04663781..033b366750 100644 --- a/osdep/timer.h +++ b/osdep/timer.h @@ -19,10 +19,28 @@ #ifndef MPLAYER_TIMER_H #define MPLAYER_TIMER_H -void InitTimer(void); -unsigned int GetTimer(void); -unsigned int GetTimerMS(void); +#include +// Initialize timer, must be called at least once at start. +void mp_time_init(void); + +// Return time in microseconds. Never wraps. Never returns 0 or negative values. +int64_t mp_time_us(void); + +// Return time in seconds. Can have down to 1 microsecond resolution, but will +// be much worse when casted to float. +double mp_time_sec(void); + +// Provided by OS specific functions (timer-linux.c) +void mp_raw_time_init(void); +uint64_t mp_raw_time_us(void); + +// Sleep in microseconds. +void mp_sleep_us(int64_t us); + +// Legacy timer functions. These can wrap. +unsigned int GetTimer(void); // in us +unsigned int GetTimerMS(void); // in ms int usec_sleep(int usec_delay); #endif /* MPLAYER_TIMER_H */ -- cgit v1.2.3