2 * Precise timer routines using Mach kernel-space timing.
4 * It reports to be accurate by ~20us, unless the task is preempted.
6 * (C) 2003 Dan Christiansen
8 * Released into the public domain.
15 #include <mach/mach_time.h>
16 #include <mach/mach.h>
17 #include <mach/clock.h>
19 #include "../config.h"
20 #include "../mp_msg.h"
23 /* Utility macros for mach_timespec_t - it uses nsec rather than usec */
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)
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)
35 /* returns float value of t, in seconds */
36 #define time_to_float(t) \
37 ((t).tv_sec + (t).tv_nsec / 1e9)
39 /* returns integer value of t, in microseconds */
40 #define time_to_usec(t) \
41 ((t).tv_sec * 1000000 + (t).tv_nsec / 1000)
43 /* sets ts to the value of f, in seconds */
44 #define float_to_time(f, ts) \
46 (ts).tv_sec = (unsigned int)(f); \
47 (ts).tv_nsec = (int)(((f) - (ts).sec) / 1000000000.0); \
50 /* sets ts to the value of i, in microseconds */
51 #define usec_to_time(i, ts) \
53 (ts).tv_sec = (i) / 1000000; \
54 (ts).tv_nsec = (i) % 1000000 * 1000; \
57 #define time_uadd(i, ts) \
59 (ts).tv_sec += (i) / 1000000; \
60 (ts).tv_nsec += (i) % 1000000 * 1000; \
61 while ((ts).tv_nsec > 1000000000) { \
63 (ts).tv_nsec -= 1000000000; \
68 /* global variables */
69 static double relative_time
, startup_time
;
70 static double timebase_ratio
;
71 static mach_port_t clock_port
;
74 /* sleep usec_delay microseconds */
75 int usec_sleep(int usec_delay
)
77 mach_timespec_t start_time
, end_time
;
79 clock_get_time(clock_port
, &start_time
);
81 end_time
= start_time
;
82 time_uadd(usec_delay
, end_time
);
84 clock_sleep(clock_port
, TIME_ABSOLUTE
, end_time
, NULL
);
86 clock_get_time(clock_port
, &end_time
);
88 return usec_delay
- udiff_time(start_time
, end_time
);
92 /* Returns current time in microseconds */
93 unsigned int GetTimer()
95 return (unsigned int)((mach_absolute_time() * timebase_ratio
- startup_time
)
99 /* Returns current time in milliseconds */
100 unsigned int GetTimerMS()
102 return (unsigned int)(GetTimer() / 1000);
105 /* Returns time spent between now and last call in seconds */
106 float GetRelativeTime()
110 last_time
= relative_time
;
112 relative_time
= mach_absolute_time() * timebase_ratio
;
114 return (float)(relative_time
-last_time
);
117 /* Initialize timer, must be called at least once at start */
120 struct mach_timebase_info timebase
;
122 /* get base for mach_absolute_time() */
123 mach_timebase_info(&timebase
);
124 timebase_ratio
= (double)timebase
.numer
/ (double)timebase
.denom
127 /* get mach port for the clock */
128 host_get_clock_service(mach_host_self(), REALTIME_CLOCK
, &clock_port
);
130 /* prepare for GetRelativeTime() */
131 relative_time
= startup_time
=
132 (double)(mach_absolute_time() * timebase_ratio
);
139 const long delay
= 0.001*1e6
;
140 const unsigned short attempts
= 100;
141 int i
,j
[attempts
],t
[attempts
],r
[attempts
];
147 for (i
= 0; i
< attempts
; i
++) {
148 t
[i
] = j
[i
] = GetTimer();
149 r
[i
] = usec_sleep(delay
);
150 j
[i
] = delay
-(GetTimer() - j
[i
]);
154 for (i
= 0; i
< attempts
; i
++) {
155 sqtotal
+= j
[i
]*j
[i
];
157 printf("%2i=%0.06g \tr: %9i\tj: %9i\tr - j:%9i\n",
158 i
, t
[i
] / 1e6
, r
[i
], j
[i
], r
[i
] - j
[i
]);
161 printf("attempts: %i\ttotal=%g\trms=%g\tavg=%g\n", attempts
, total
,
162 sqrt(sqtotal
/attempts
),total
/attempts
);