Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / native_client / tests / nanosleep / nanosleep_test.c
1 /*
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.
5  */
6
7 #include <errno.h>
8 #include <inttypes.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/time.h>
12 #include <sys/types.h>
13 #include <time.h>
14 #include <unistd.h>
15
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"
18
19 /*
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.
27  *
28  * Sigh.
29  */
30
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)
35
36 /*
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.
39  */
40 void PrintTimeval(FILE *iob, struct timeval const *tv) {
41   fprintf(iob, "%"PRId64".%06ld", (int64_t) tv->tv_sec, tv->tv_usec);
42 }
43
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);
47 }
48
49 void NormalizeTimeval(struct timeval *tv) {
50   int first = 1;
51   while (tv->tv_usec < 0) {
52     tv->tv_usec += MICROS_PER_UNIT;
53     tv->tv_sec -= 1;
54     if (!first) {
55       fprintf(stderr, "NormalizedTimeval: usec too small, 2x normalize!\n");
56       PrintTimeval(stderr, tv); putc('\n', stderr);
57     }
58     first = 0;
59   }
60   first = 1;
61   while (tv->tv_usec >= MICROS_PER_UNIT) {
62     tv->tv_usec -= MICROS_PER_UNIT;
63     tv->tv_sec += 1;
64     if (!first) {
65       fprintf(stderr, "NormalizedTimeval: usec too large, 2x normalize!\n");
66       PrintTimeval(stderr, tv); putc('\n', stderr);
67     }
68     first = 0;
69   }
70 }
71
72 /*
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.
78  */
79 int TestNanoSleep(struct timespec *t_suspend,
80                   uint64_t        slop_ms) {
81   struct timespec t_remain;
82   struct timeval  t_start;
83   int             rv;
84   struct timeval  t_end;
85   struct timeval  t_elapsed;
86
87   printf("%40s: ", "Requesting nanosleep duration");
88   PrintTimespec(stdout, t_suspend);
89   printf(" seconds\n");
90   t_remain = *t_suspend;
91   /*
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.
95    */
96   if (-1 == gettimeofday(&t_start, NULL)) {
97     printf("gettimeofday for start time failed\n");
98     return 1;
99   }
100   while (-1 == (rv = nanosleep(&t_remain, &t_remain)) &&
101          EINTR == errno) {
102   }
103   if (-1 == rv) {
104     printf("nanosleep failed, errno = %d\n", errno);
105     return 1;
106   }
107   if (-1 == gettimeofday(&t_end, NULL)) {
108     printf("gettimeofday for end time failed\n");
109     return 1;
110   }
111
112   /*
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.)
118    */
119
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;
122
123   NormalizeTimeval(&t_elapsed);
124   printf("%40s: ", "Actual nanosleep duration");
125   PrintTimeval(stdout, &t_elapsed);
126   printf(" seconds\n");
127
128   /*
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
134    * occur.
135    */
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");
141
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");
146     printf("Error\n");
147     return 1;
148   } else {
149     printf("OK\n");
150     return 0;
151   }
152 }
153
154 int main(int argc, char **argv) {
155   int                     num_errors = 0;
156   int                     ix;
157   int                     opt;
158   uint64_t                slop_ms = 0;
159
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, },
172   };
173
174   while (EOF != (opt = getopt(argc, argv, "s:"))) {
175     switch (opt) {
176       case 's':
177         slop_ms = strtoull(optarg, (char **) NULL, 0);
178         break;
179       default:
180         fprintf(stderr,
181                 "Usage: nanosleep_test [-s slop_for_time_compare_in_ms]\n");
182         return 1;
183     }
184   }
185
186   for (ix = 0; ix < sizeof t_suspend/sizeof t_suspend[0]; ++ix) {
187     num_errors += TestNanoSleep(&t_suspend[ix], slop_ms);
188   }
189
190   if (0 != num_errors) {
191     printf("FAILED\n");
192     return 1;
193   } else {
194     printf("PASSED\n");
195     return 0;
196   }
197 }