2 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <CoreFoundation/CoreFoundation.h>
31 #include <mach/mach.h>
32 #include <mach/mach_time.h>
34 /* These externs can be removed once the prototypes make it to the SDK */
35 extern mach_port_name_t
mk_timer_create(void);
36 extern kern_return_t
mk_timer_arm(mach_port_name_t name
, uint64_t expire_time
);
38 #define MK_TIMER_CRITICAL (1)
39 extern kern_return_t
mk_timer_arm_leeway(mach_port_name_t name
,
40 uint64_t mk_timer_flags
,
41 uint64_t mk_timer_expire_time
,
42 uint64_t mk_timer_leeway
);
44 struct mach_timebase_info tbinfo
;
47 mach_port_t timerPort
;
49 uint64_t interval_abs
= 1000000000;
51 uint32_t use_leeway
= 0;
52 uint32_t report
= 1000;
54 uint64_t on
, lastfire
= 0, totaljitter
= 0, max_jitter
= 0, min_jitter
= ~0ULL, jiterations
= 0, leeway_ns
= 0, leeway_abs
= 0;
57 void cfmcb(CFMachPortRef port
, void *msg
, CFIndex size
, void *msginfo
) {
58 uint64_t ctime
= mach_absolute_time();
62 jitter
= (ctime
- deadline
);
63 if (jitter
> max_jitter
) {
67 if (jitter
< min_jitter
) {
71 totaljitter
+= jitter
;
72 if ((++jiterations
% report
) == 0) {
73 printf("max_jitter: %g (ns), min_jitter: %g (ns), average_jitter: %g (ns)\n", max_jitter
* conversion
, min_jitter
* conversion
, ((double)totaljitter
/(double)jiterations
) * conversion
);
74 max_jitter
= 0; min_jitter
= ~0ULL; jiterations
= 0; totaljitter
= 0;
78 deadline
= mach_absolute_time() + interval_abs
;
81 mk_timer_arm_leeway(timerPort
, MK_TIMER_CRITICAL
, deadline
, leeway_abs
);
83 mk_timer_arm(timerPort
, deadline
);
87 int main(int argc
, char **argv
) {
89 printf("Usage: mktimer_test <interval_ns> <use leeway trap> <leeway_ns>\n");
93 on
= strtoul(argv
[1], NULL
, 0);
94 use_leeway
= strtoul(argv
[2], NULL
, 0);
96 mach_timebase_info(&tbinfo
);
97 conversion
= ((double)tbinfo
.numer
/ (double) tbinfo
.denom
);
99 leeway_ns
= strtoul(argv
[3], NULL
, 0);
101 leeway_abs
= leeway_ns
/ conversion
;
102 printf("Interval in ns: %llu, timebase conversion: %g, use leeway syscall: %d, leeway_ns: %llu\n", on
, conversion
, !!use_leeway
, leeway_ns
);
104 interval_abs
= on
/ conversion
;
107 CFMachPortContext context
= (CFMachPortContext
){
115 timerPort
= mk_timer_create();
116 CFMachPortRef port
= CFMachPortCreateWithPort(NULL
, timerPort
, cfmcb
, &context
, NULL
);
117 CFRunLoopSourceRef eventSource
= CFMachPortCreateRunLoopSource(NULL
, port
, -1);
118 CFRunLoopAddSource(CFRunLoopGetCurrent(), eventSource
, kCFRunLoopDefaultMode
);
119 CFRelease(eventSource
);
122 mk_timer_arm_leeway(timerPort
, MK_TIMER_CRITICAL
, mach_absolute_time() + interval_abs
, leeway_abs
);
124 mk_timer_arm(timerPort
, mach_absolute_time() + interval_abs
);