2 * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
12 #include <sys/types.h>
16 #include "native_client/src/trusted/service_runtime/include/machine/_types.h"
17 #include "native_client/src/trusted/service_runtime/include/sys/nacl_syscalls.h"
20 * Newlib's time.h not working right: getting the nanosleep
21 * declaration from the newlib time.h file requires defining
22 * _POSIX_TIMERS, but we don't implement any of the clock_settime,
23 * clock_gettime, clock_getres, timer_create, timer_delete,
24 * timer_settime, timer_gettime, and timer_getoverrun functions. In
25 * glibc's time.h, these function declarations are obtained by
26 * ensuring _POSIX_C_SOURCE >= 199309L.
31 #define NANOS_PER_MICRO (1000)
32 #define MICROS_PER_MILLI (1000)
33 #define NANOS_PER_MILLI (NANOS_PER_MICRO * MICROS_PER_MILLI)
34 #define MICROS_PER_UNIT (1000 * 1000)
37 * We don't convert to floating point, so a precondition is that
38 * tv_usec is within range, i.e., the timeval has been normalized.
40 void PrintTimeval(FILE *iob, struct timeval const *tv) {
41 fprintf(iob, "%"PRId64".%06ld", (int64_t) tv->tv_sec, tv->tv_usec);
44 /* timespec fields should have been ts_nsec etc */
45 void PrintTimespec(FILE *iob, struct timespec const *ts) {
46 fprintf(iob, "%"PRId64".%09ld", (uint64_t) ts->tv_sec, ts->tv_nsec);
49 void NormalizeTimeval(struct timeval *tv) {
51 while (tv->tv_usec < 0) {
52 tv->tv_usec += MICROS_PER_UNIT;
55 fprintf(stderr, "NormalizedTimeval: usec too small, 2x normalize!\n");
56 PrintTimeval(stderr, tv); putc('\n', stderr);
61 while (tv->tv_usec >= MICROS_PER_UNIT) {
62 tv->tv_usec -= MICROS_PER_UNIT;
65 fprintf(stderr, "NormalizedTimeval: usec too large, 2x normalize!\n");
66 PrintTimeval(stderr, tv); putc('\n', stderr);
73 * Returns failure count. t_suspend should not be shorter than 1us,
74 * since elapsed time measurement cannot possibly be any finer in
75 * granularity. In practice, 1ms is probably the best we can hope for
76 * in timer resolution, so even if nanosleep suspends for 1us, the
77 * gettimeofday resolution may cause a false failure report.
79 int TestNanoSleep(struct timespec *t_suspend,
81 struct timespec t_remain;
82 struct timeval t_start;
85 struct timeval t_elapsed;
87 printf("%40s: ", "Requesting nanosleep duration");
88 PrintTimespec(stdout, t_suspend);
90 t_remain = *t_suspend;
92 * BUG: ntp or other time adjustments can mess up timing.
93 * BUG: time-of-day clock resolution may be not be fine enough to
94 * measure nanosleep duration.
96 if (-1 == gettimeofday(&t_start, NULL)) {
97 printf("gettimeofday for start time failed\n");
100 while (-1 == (rv = nanosleep(&t_remain, &t_remain)) &&
104 printf("nanosleep failed, errno = %d\n", errno);
107 if (-1 == gettimeofday(&t_end, NULL)) {
108 printf("gettimeofday for end time failed\n");
113 * We add a microsecond in case of rounding/synchronization issues
114 * between the nanosleep/scheduler clock and the time-of-day clock,
115 * where the time-of-day clock doesn't _quite_ get incremented in
116 * time even though the entire nanosleep duration had passed.
117 * (We've seen this occur on the mac.)
120 t_elapsed.tv_sec = t_end.tv_sec - t_start.tv_sec;
121 t_elapsed.tv_usec = t_end.tv_usec - t_start.tv_usec + 1;
123 NormalizeTimeval(&t_elapsed);
124 printf("%40s: ", "Actual nanosleep duration");
125 PrintTimeval(stdout, &t_elapsed);
126 printf(" seconds\n");
129 * On WinXP, Sleep(num_ms) sometimes -- though rarely -- return
130 * earlier than it is supposed to. This may be due to gettimeofday
131 * issues when running on VMs, rather than actual insomnia. In any
132 * case, We permit adding in some slop here to the elapsed time so
133 * that we can ignore the sporadic random test failures that would
136 t_elapsed.tv_usec += slop_ms * MICROS_PER_MILLI;
137 NormalizeTimeval(&t_elapsed);
138 printf("%40s: ", "Slop adjusted duration");
139 PrintTimeval(stdout, &t_elapsed);
140 printf(" seconds\n");
142 if (t_elapsed.tv_sec < t_suspend->tv_sec ||
143 (t_elapsed.tv_sec == t_suspend->tv_sec &&
144 (NANOS_PER_MICRO * t_elapsed.tv_usec < t_suspend->tv_nsec))) {
145 printf("Elapsed time too short!\n");
154 int main(int argc, char **argv) {
158 uint64_t slop_ms = 0;
160 static struct timespec t_suspend[] = {
161 { 0, 1 * NANOS_PER_MILLI, },
162 { 0, 2 * NANOS_PER_MILLI, },
163 { 0, 5 * NANOS_PER_MILLI, },
164 { 0, 10 * NANOS_PER_MILLI, },
165 { 0, 25 * NANOS_PER_MILLI, },
166 { 0, 50 * NANOS_PER_MILLI, },
167 { 0, 100 * NANOS_PER_MILLI, },
168 { 0, 250 * NANOS_PER_MILLI, },
169 { 0, 500 * NANOS_PER_MILLI, },
170 { 1, 0 * NANOS_PER_MILLI, },
171 { 1, 500 * NANOS_PER_MILLI, },
174 while (EOF != (opt = getopt(argc, argv, "s:"))) {
177 slop_ms = strtoull(optarg, (char **) NULL, 0);
181 "Usage: nanosleep_test [-s slop_for_time_compare_in_ms]\n");
186 for (ix = 0; ix < sizeof t_suspend/sizeof t_suspend[0]; ++ix) {
187 num_errors += TestNanoSleep(&t_suspend[ix], slop_ms);
190 if (0 != num_errors) {