2 #include <mach/mach_time.h>
3 #include <mach/clock_types.h>
13 #include <darwintest.h>
15 extern char **environ
;
17 static const int64_t one_mil
= 1000*1000;
19 #define to_ns(ticks) ((ticks * tb_info.numer) / (tb_info.denom))
20 #define to_ms(ticks) (to_ns(ticks)/one_mil)
22 static mach_timebase_info_data_t tb_info
;
25 update(uint64_t *a
, uint64_t *c
) {
26 mach_get_times(a
,c
,NULL
);
29 T_DECL(mct_monotonic
, "Testing mach_continuous_time returns sane, monotonic values",
30 T_META_ALL_VALID_ARCHS(true))
32 mach_timebase_info(&tb_info
);
34 volatile uint64_t multiple_test
= to_ms(mach_continuous_time());
35 for(int i
= 0; i
< 10; i
++) {
36 uint64_t tmp
= to_ms(mach_continuous_time());
37 T_ASSERT_GE(tmp
, multiple_test
, "mach_continuous_time must be monotonic");
39 // each successive call shouldn't be more than 50ms in the future
40 T_ASSERT_LE(tmp
- multiple_test
, 50ULL, "mach_continuous_time should not jump forward too fast");
46 T_DECL(mct_pause
, "Testing mach_continuous_time and mach_absolute_time don't diverge")
48 mach_timebase_info(&tb_info
);
52 int before_diff
, after_diff
;
54 update(&abs_now
, &cnt_now
);
55 before_diff
= (int)(to_ms(cnt_now
) - to_ms(abs_now
));
59 update(&abs_now
, &cnt_now
);
60 after_diff
= (int)(to_ms(cnt_now
) - to_ms(abs_now
));
62 T_ASSERT_LE(abs(after_diff
- before_diff
), 1, "mach_continuous_time and mach_absolute_time should not diverge");
65 T_DECL(mct_sleep
, "Testing mach_continuous_time behavior over system sleep"){
66 #ifndef MCT_SLEEP_TEST
67 T_SKIP("Skipping test that sleeps the device; compile with MCT_SLEEP_TEST define to enable.");
70 mach_timebase_info(&tb_info
);
74 int before_diff
, after_diff
= 0;
76 T_LOG("Testing mach_continuous_time is ~5 seconds ahead of mach_absolute_time after 5 second sleep");
77 update(&abs_now
, &cnt_now
);
78 before_diff
= (int)(to_ms(cnt_now
) - to_ms(abs_now
));
81 // pmset relative wake 5
86 time_t before_sleep
= time(NULL
);
87 int ct_ms_before_sleep
= (int)to_ms(cnt_now
);
88 int ab_ms_before_sleep
= (int)to_ms(abs_now
);
90 char *const pmset1_args
[] = {"/usr/bin/pmset", "relative", "wake", "5", NULL
};
91 T_ASSERT_POSIX_ZERO((spawn_ret
= posix_spawn(&pid
, pmset1_args
[0], NULL
, NULL
, pmset1_args
, environ
)), NULL
);
93 T_ASSERT_EQ(waitpid(pid
, &spawn_ret
, 0), pid
, "waitpid failed");
94 T_ASSERT_EQ(spawn_ret
, 0, "pmset relative wait 5 failed");
96 char *const pmset2_args
[] = {"/usr/bin/pmset", "sleepnow", NULL
};
97 T_ASSERT_POSIX_ZERO((spawn_ret
= posix_spawn(&pid
, pmset2_args
[0], NULL
, NULL
, pmset2_args
, environ
)), NULL
);
99 T_ASSERT_EQ(waitpid(pid
, &spawn_ret
, 0), pid
, "waitpid failed");
100 T_ASSERT_EQ(spawn_ret
, 0, "pmset relative wait 5 failed");
102 // wait for device to sleep (up to 30 seconds)
103 for(int i
= 0; i
< 30; i
++) {
104 update(&abs_now
, &cnt_now
);
105 after_diff
= (int)(to_ms(cnt_now
) - to_ms(abs_now
));
107 // on OSX, there's enough latency between calls to MCT and MAT
108 // when the system is going down for sleep for values to diverge a few ms
109 if(abs(before_diff
- after_diff
) > 2) {
114 T_LOG("waited %d seconds for sleep...", i
+1);
117 if((after_diff
- before_diff
) < 4000) {
118 T_LOG("Device slept for less than 4 seconds, did it really sleep? (%d ms change between abs and cont)",
119 after_diff
- before_diff
);
122 time_t after_sleep
= time(NULL
);
124 int cal_sleep_diff
= (int)(double)difftime(after_sleep
, before_sleep
);
125 int ct_sleep_diff
= ((int)to_ms(cnt_now
) - ct_ms_before_sleep
)/1000;
126 int ab_sleep_diff
= ((int)to_ms(abs_now
) - ab_ms_before_sleep
)/1000;
128 T_LOG("Calendar progressed: %d sec; continuous time progressed: %d sec; absolute time progressed %d sec",
129 cal_sleep_diff
, ct_sleep_diff
, ab_sleep_diff
);
131 T_ASSERT_LE(abs(ct_sleep_diff
- cal_sleep_diff
), 2,
132 "continuous time should progress at ~ same rate as calendar");
135 T_DECL(mct_settimeofday
, "Testing mach_continuous_time behavior over settimeofday"){
137 T_SKIP("The settimeofday() test requires root privileges to run.");
139 mach_timebase_info(&tb_info
);
141 struct timeval saved_tv
;
142 struct timezone saved_tz
;
145 T_ASSERT_POSIX_ZERO(gettimeofday(&saved_tv
, &saved_tz
), NULL
);
147 struct timeval forward_tv
= saved_tv
;
148 // move time forward by two minutes, ensure mach_continuous_time keeps
149 // chugging along with mach_absolute_time
150 forward_tv
.tv_sec
+= 2*60;
152 before
= (int)to_ms(mach_continuous_time());
153 T_ASSERT_POSIX_ZERO(settimeofday(&forward_tv
, &saved_tz
), NULL
);
155 after
= (int)to_ms(mach_continuous_time());
156 T_ASSERT_POSIX_ZERO(settimeofday(&saved_tv
, &saved_tz
), NULL
);
158 T_ASSERT_LT(abs(before
- after
), 1000, "mach_continuous_time should not jump more than 1s");
161 T_DECL(mct_aproximate
, "Testing mach_continuous_approximate_time()",
162 T_META_ALL_VALID_ARCHS(true))
164 mach_timebase_info(&tb_info
);
166 uint64_t absolute
= to_ns(mach_continuous_time());
167 uint64_t approximate
= to_ns(mach_continuous_approximate_time());
169 T_EXPECT_LE(llabs((long long)absolute
- (long long)approximate
), (long long)(25*NSEC_PER_MSEC
), NULL
);