comparison osdep/timer-darwin.c @ 12954:f9755d9c479a

Native darwin timer update. Patch by Dan Christiansen <danchr@daimi.au.dk>
author wight
date Wed, 04 Aug 2004 15:48:43 +0000
parents d12758db79aa
children 3029f9e4f2ac
comparison
equal deleted inserted replaced
12953:27e983508347 12954:f9755d9c479a
1 /* 1 /*
2 * Precise timer routines using Mach kernel-space timing. 2 * Precise timer routines using Mach timing
3 * 3 *
4 * It reports to be accurate by ~20us, unless the task is preempted. 4 * Copyright (c) 2003-2004, Dan Villiom Podlaski Christiansen
5 * 5 *
6 * (C) 2003 Dan Christiansen 6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use, copy,
10 * modify, merge, publish, distribute, sublicense, and/or sell copies
11 * of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
7 * 13 *
8 * Released into the public domain. 14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
9 */ 16 */
10 17
11 #include <unistd.h> 18 #include <unistd.h>
12 #include <stdlib.h> 19 #include <stdlib.h>
13 #include <stdio.h> 20 #include <time.h>
14 21 #include <math.h>
22 #include <sys/time.h>
15 #include <mach/mach_time.h> 23 #include <mach/mach_time.h>
16 #include <mach/mach.h>
17 #include <mach/clock.h>
18 24
19 #include "../config.h" 25 #include "../config.h"
20 #include "../mp_msg.h" 26 #include "../mp_msg.h"
21 #include "timer.h" 27 #include "timer.h"
22 28
23 /* Utility macros for mach_timespec_t - it uses nsec rather than usec */
24
25 /* returns time from t1 to t2, in seconds (as float) */
26 #define diff_time(t1, t2) \
27 (((t2).tv_sec - (t1).tv_sec) + \
28 ((t2).tv_nsec - (t1).tv_nsec) / 1e9)
29
30 /* returns time from t1 to t2, in microseconds (as integer) */
31 #define udiff_time(t1, t2) \
32 (((t2).tv_sec - (t1).tv_sec) * 1000000 + \
33 ((t2).tv_nsec - (t1).tv_nsec) / 1000)
34
35 /* returns float value of t, in seconds */
36 #define time_to_float(t) \
37 ((t).tv_sec + (t).tv_nsec / 1e9)
38
39 /* returns integer value of t, in microseconds */
40 #define time_to_usec(t) \
41 ((t).tv_sec * 1000000 + (t).tv_nsec / 1000)
42
43 /* sets ts to the value of f, in seconds */
44 #define float_to_time(f, ts) \
45 do { \
46 (ts).tv_sec = (unsigned int)(f); \
47 (ts).tv_nsec = (int)(((f) - (ts).sec) / 1000000000.0); \
48 } while (0)
49
50 /* sets ts to the value of i, in microseconds */
51 #define usec_to_time(i, ts) \
52 do { \
53 (ts).tv_sec = (i) / 1000000; \
54 (ts).tv_nsec = (i) % 1000000 * 1000; \
55 } while (0)
56
57 #define time_uadd(i, ts) \
58 do { \
59 (ts).tv_sec += (i) / 1000000; \
60 (ts).tv_nsec += (i) % 1000000 * 1000; \
61 while ((ts).tv_nsec > 1000000000) { \
62 (ts).tv_sec++; \
63 (ts).tv_nsec -= 1000000000; \
64 } \
65 } while (0)
66
67
68 /* global variables */ 29 /* global variables */
69 static double relative_time, startup_time; 30 static double relative_time, startup_time;
70 static double timebase_ratio; 31 static double timebase_ratio;
71 static mach_port_t clock_port;
72 32
33 const char *timer_name = "Darwin accurate";
73 34
74 /* sleep usec_delay microseconds */ 35 /* the core sleep function, uses floats and is used in MPlayer G2 */
36 float sleep_accurate(float time_frame)
37 {
38 uint64_t deadline = time_frame / timebase_ratio + mach_absolute_time();
39
40 mach_wait_until(deadline);
41
42 return (mach_absolute_time() - deadline) * timebase_ratio;
43 }
44
45 /* wrapper for MPlayer G1 */
75 int usec_sleep(int usec_delay) 46 int usec_sleep(int usec_delay)
76 { 47 {
77 #if 0 48 return sleep_accurate(usec_delay / 1e6) * 1e6;
78 mach_timespec_t start_time, end_time;
79
80 clock_get_time(clock_port, &start_time);
81
82 end_time = start_time;
83 time_uadd(usec_delay, end_time);
84
85 clock_sleep(clock_port, TIME_ABSOLUTE, end_time, NULL);
86
87 clock_get_time(clock_port, &end_time);
88
89 return usec_delay - udiff_time(start_time, end_time);
90 #else
91 usleep(usec_delay);
92 #endif
93 } 49 }
94 50
95 51
96 /* Returns current time in microseconds */ 52 /* current time in microseconds */
97 unsigned int GetTimer() 53 unsigned int GetTimer()
98 { 54 {
99 return (unsigned int)((mach_absolute_time() * timebase_ratio - startup_time) 55 return (unsigned int)((mach_absolute_time() * timebase_ratio - startup_time)
100 * 1e6); 56 * 1e6);
101 } 57 }
102 58
103 /* Returns current time in milliseconds */ 59 /* current time in milliseconds */
104 unsigned int GetTimerMS() 60 unsigned int GetTimerMS()
105 { 61 {
106 return (unsigned int)(GetTimer() / 1000); 62 return (unsigned int)(GetTimer() / 1000);
107 } 63 }
108 64
109 /* Returns time spent between now and last call in seconds */ 65 /* time spent between now and last call in seconds */
110 float GetRelativeTime() 66 float GetRelativeTime()
111 { 67 {
112 double last_time; 68 double last_time = relative_time;
113 69
114 last_time = relative_time; 70 if (!relative_time)
71 InitTimer();
115 72
116 relative_time = mach_absolute_time() * timebase_ratio; 73 relative_time = mach_absolute_time() * timebase_ratio;
117 74
118 return (float)(relative_time-last_time); 75 return (float)(relative_time-last_time);
119 } 76 }
120 77
121 /* Initialize timer, must be called at least once at start */ 78 /* initialize timer, must be called at least once at start */
122 void InitTimer() 79 void InitTimer()
123 { 80 {
124 struct mach_timebase_info timebase; 81 struct mach_timebase_info timebase;
125 82
126 /* get base for mach_absolute_time() */
127 mach_timebase_info(&timebase); 83 mach_timebase_info(&timebase);
128 timebase_ratio = (double)timebase.numer / (double)timebase.denom 84 timebase_ratio = (double)timebase.numer / (double)timebase.denom
129 * (double)1e-9; 85 * (double)1e-9;
130 86
131 /* get mach port for the clock */
132 host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &clock_port);
133
134 /* prepare for GetRelativeTime() */
135 relative_time = startup_time = 87 relative_time = startup_time =
136 (double)(mach_absolute_time() * timebase_ratio); 88 (double)(mach_absolute_time() * timebase_ratio);
137 } 89 }
138 90
91 #if 0
92 #include <stdio.h>
139 93
140 #if 0 94 int main() {
141 int main() 95 int i,j, r, c = 200;
142 { 96 long long t = 0;
143 const long delay = 0.001*1e6;
144 const unsigned short attempts = 100;
145 int i,j[attempts],t[attempts],r[attempts];
146 double sqtotal;
147 double total;
148 97
149 InitTimer(); 98 InitTimer();
150 99
151 for (i = 0; i < attempts; i++) { 100 for (i = 0; i < c; i++) {
152 t[i] = j[i] = GetTimer(); 101 const int delay = rand() / (RAND_MAX / 1e5);
153 r[i] = usec_sleep(delay); 102 j = GetTimer();
154 j[i] = delay-(GetTimer() - j[i]); 103 #if 1
155 fflush(stdout); 104 r = usec_sleep(delay);
105 #else
106 r = sleep_accurate(delay / 1e6) * 1e6;
107 #endif
108 j = (GetTimer() - j) - delay;
109 printf("sleep time:%8i %5i (%i)\n", delay, j, j - r);
110 t += j - r;
156 } 111 }
112 fprintf(stderr, "average error:\t%lli\n", t / c);
157 113
158 for (i = 0; i < attempts; i++) {
159 sqtotal += j[i]*j[i];
160 total += j[i];
161 printf("%2i=%0.06g \tr: %9i\tj: %9i\tr - j:%9i\n",
162 i, t[i] / 1e6, r[i], j[i], r[i] - j[i]);
163 }
164
165 printf("attempts: %i\ttotal=%g\trms=%g\tavg=%g\n", attempts, total,
166 sqrt(sqtotal/attempts),total/attempts);
167
168 return 0; 114 return 0;
169 } 115 }
170 #endif 116 #endif