OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2013 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 <pthread.h> | |
10 #include <stdio.h> | |
11 #include <string.h> | |
12 #include <sys/types.h> | |
13 #include <sys/time.h> | |
14 #include <time.h> | |
15 #include <unistd.h> | |
16 | |
17 #include "native_client/src/include/nacl_macros.h" | |
18 | |
19 /* | |
20 * This test resembles the trusted version which can be found in | |
21 * src/shared/platform/nacl_clock_test.c, but uses the stable ABI | |
22 * to test the integration correctness. When making changes, please | |
23 * keep both tests in sync if possible. | |
24 */ | |
25 | |
26 | |
27 /* | |
28 * On an unloaded i7, 1ms with a 1.25 fuzziness factor and a 100,000 | |
Roland McGrath
2013/08/28 19:54:34
This comment belongs down a paragraph, right befor
Petr Hosek
2013/08/28 22:48:57
Moved down.
| |
29 * ns constant syscall overhead works fine. On bots, we have to be | |
30 * much more generous. (This is especially true for qemu-based | |
31 * testing.) | |
32 */ | |
33 #define NANOS_PER_MICRO (1000) | |
34 #define MICROS_PER_MILLI (1000) | |
35 #define NANOS_PER_MILLI (NANOS_PER_MICRO * MICROS_PER_MILLI) | |
36 #define MICROS_PER_UNIT (1000 * 1000) | |
37 #define NANOS_PER_UNIT (NANOS_PER_MICRO * MICROS_PER_UNIT) | |
38 | |
39 #define DEFAULT_NANOSLEEP_EXTRA_OVERHEAD (10 * NANOS_PER_MILLI) | |
40 #define DEFAULT_NANOSLEEP_EXTRA_FACTOR (100.0) | |
41 #define DEFAULT_NANOSLEEP_TIME (10 * NANOS_PER_MILLI) | |
42 | |
43 /* | |
44 * Global testing parameters -- fuzziness coefficients in determining | |
45 * what is considered accurate. | |
Roland McGrath
2013/08/28 19:54:34
Make these static.
Petr Hosek
2013/08/28 22:48:57
Done.
| |
46 */ | |
47 int g_cputime = 1; | |
48 double g_fuzzy_factor = DEFAULT_NANOSLEEP_EXTRA_FACTOR; | |
49 uint64_t g_syscall_overhead = DEFAULT_NANOSLEEP_EXTRA_OVERHEAD; | |
50 uint64_t g_slop_ms = 0; | |
51 | |
52 /* | |
53 * ClockMonotonicAccuracyTest samples the CLOCK_MONOTONIC | |
54 * clock before and after invoking NaClNanosleep and computes the time | |
55 * delta. The test is considered to pass if the time delta is close | |
56 * to the requested value. "Close" is a per-host-OS attribute, thus | |
57 * the above testing parameters. | |
58 */ | |
59 int ClockMonotonicAccuracyTest(uint64_t sleep_nanos) { | |
Roland McGrath
2013/08/28 19:54:34
Make the local functions static.
Petr Hosek
2013/08/28 22:48:57
Done.
| |
60 int num_failures = 0; | |
61 | |
62 struct timespec t_start; | |
63 struct timespec t_sleep; | |
64 struct timespec t_end; | |
65 | |
66 uint64_t elapsed_nanos; | |
67 uint64_t elapsed_lower_bound; | |
68 uint64_t elapsed_upper_bound; | |
69 | |
70 t_sleep.tv_sec = sleep_nanos / NANOS_PER_UNIT; | |
71 t_sleep.tv_nsec = sleep_nanos % NANOS_PER_UNIT; | |
72 | |
73 printf("\nCLOCK_MONOTONIC accuracy test:\n"); | |
74 | |
75 if (0 != clock_gettime(CLOCK_MONOTONIC, &t_start)) { | |
76 fprintf(stderr, "clock_test: clock_gettime (start) failed, error %d\n", | |
77 errno); | |
78 ++num_failures; | |
79 goto done; | |
80 } | |
81 for (;;) { | |
82 if (0 == nanosleep(&t_sleep, &t_sleep)) { | |
83 break; | |
84 } | |
85 if (EINTR == errno) { | |
86 /* interrupted syscall: sleep some more */ | |
87 continue; | |
88 } | |
89 fprintf(stderr, "clock_test: nanosleep failed, error %d\n", | |
90 errno); | |
91 num_failures++; | |
92 goto done; | |
93 } | |
94 if (0 != clock_gettime(CLOCK_MONOTONIC, &t_end)) { | |
95 fprintf(stderr, "clock_test: clock_gettime (end) failed, error %d\n", | |
96 errno); | |
97 return 1; | |
98 } | |
99 | |
100 elapsed_nanos = (t_end.tv_sec - t_start.tv_sec) * NANOS_PER_UNIT | |
Roland McGrath
2013/08/28 19:54:34
Style guide says operator at eol, not next bol.
Petr Hosek
2013/08/28 22:48:57
Fixed.
| |
101 + (t_end.tv_nsec - t_start.tv_nsec) + g_slop_ms * NANOS_PER_MILLI; | |
102 | |
103 elapsed_lower_bound = sleep_nanos; | |
104 elapsed_upper_bound = (uint64_t) (sleep_nanos * g_fuzzy_factor | |
105 + g_syscall_overhead); | |
106 | |
107 printf("requested sleep: %20"PRIu64" nS\n", sleep_nanos); | |
108 printf("actual elapsed sleep: %20"PRIu64" nS\n", elapsed_nanos); | |
Roland McGrath
2013/08/28 19:54:34
This shouldn't report as "actual" a value that inc
Petr Hosek
2013/08/28 22:48:57
Removed the "actual".
| |
109 printf("sleep lower bound: %20"PRIu64" nS\n", elapsed_lower_bound); | |
110 printf("sleep upper bound: %20"PRIu64" nS\n", elapsed_upper_bound); | |
111 | |
112 if (elapsed_nanos < elapsed_lower_bound | |
113 || elapsed_upper_bound < elapsed_nanos) { | |
Roland McGrath
2013/08/28 19:54:34
operator line break again
Petr Hosek
2013/08/28 22:48:57
Fixed.
| |
114 printf("discrepancy too large\n"); | |
115 num_failures++; | |
116 } | |
117 done: | |
118 printf((0 == num_failures) ? "PASSED\n" : "FAILED\n"); | |
119 return num_failures; | |
120 } | |
121 | |
122 /* | |
123 * ClockRealtimeAccuracyTest compares the time returned by | |
124 * CLOCK_REALTIME against that returned by gettimeofday. | |
125 */ | |
126 int ClockRealtimeAccuracyTest(void) { | |
127 int num_failures = 0; | |
128 | |
129 struct timespec t_now_ts; | |
130 struct timeval t_now_tv; | |
131 | |
132 uint64_t t_now_ts_nanos; | |
133 uint64_t t_now_tv_nanos; | |
134 int64_t t_now_diff_nanos; | |
135 | |
136 printf("\nCLOCK_REALTIME accuracy test:\n"); | |
137 | |
138 if (0 != clock_gettime(CLOCK_REALTIME, &t_now_ts)) { | |
139 fprintf(stderr, "clock_test: clock_gettime (now) failed, error %d\n", | |
140 errno); | |
141 num_failures++; | |
142 goto done; | |
143 } | |
144 if (0 != gettimeofday(&t_now_tv, NULL)) { | |
145 fprintf(stderr, "clock_test: gettimeofday (now) failed, error %d\n", | |
146 errno); | |
147 num_failures++; | |
148 goto done; | |
149 } | |
150 | |
151 t_now_ts_nanos = t_now_ts.tv_sec * NANOS_PER_UNIT + t_now_ts.tv_nsec; | |
152 t_now_tv_nanos = t_now_tv.tv_sec * NANOS_PER_UNIT | |
153 + t_now_tv.tv_usec * NANOS_PER_MICRO; | |
Roland McGrath
2013/08/28 19:54:34
operator line break again
Petr Hosek
2013/08/28 22:48:57
Fixed.
| |
154 | |
155 printf("clock_gettime: %20"PRIu64" nS\n", t_now_ts_nanos); | |
156 printf("gettimeofday: %20"PRIu64" nS\n", t_now_tv_nanos); | |
157 | |
158 t_now_diff_nanos = t_now_ts_nanos - t_now_tv_nanos; | |
159 if (t_now_diff_nanos < 0) { | |
160 t_now_diff_nanos = -t_now_diff_nanos; | |
161 } | |
162 printf("time difference: %20"PRId64" nS\n", t_now_diff_nanos); | |
163 | |
164 if (t_now_ts_nanos < g_syscall_overhead) { | |
165 printf("discrepancy too large\n"); | |
166 num_failures++; | |
167 } | |
168 done: | |
169 printf((0 == num_failures) ? "PASSED\n" : "FAILED\n"); | |
170 return num_failures; | |
171 } | |
172 | |
173 struct ThreadInfo { | |
174 size_t cycles; | |
175 struct timespec thread_time; | |
176 struct timespec process_time; | |
177 int num_failures; | |
178 }; | |
179 | |
180 void *ThreadFunction(void *ptr) { | |
181 size_t i; | |
182 struct ThreadInfo *info = (struct ThreadInfo *) ptr; | |
183 | |
184 for (i = 1; i < info->cycles; i++) { | |
Roland McGrath
2013/08/28 19:54:34
This should have a comment on its intent.
Petr Hosek
2013/08/28 22:48:57
Added.
| |
185 __sync_synchronize(); | |
186 } | |
187 | |
188 if (0 != clock_gettime(CLOCK_THREAD_CPUTIME_ID, &info->thread_time)) { | |
189 fprintf(stderr, "clock_test: clock_gettime (now) failed, error %d\n", | |
190 errno); | |
191 info->num_failures++; | |
192 return NULL; | |
193 } | |
194 | |
195 if (0 != clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &info->process_time)) { | |
196 fprintf(stderr, "clock_test: clock_gettime (now) failed, error %d\n", | |
197 errno); | |
198 info->num_failures++; | |
199 return NULL; | |
200 } | |
201 | |
202 return NULL; | |
203 } | |
204 | |
205 int ClockCpuTimeAccuracyTest(void) { | |
206 int num_failures = 0; | |
207 | |
208 int err; | |
209 struct timespec t_process_start; | |
210 struct timespec t_process_end; | |
211 struct timespec t_thread_start; | |
212 struct timespec t_thread_end; | |
213 | |
214 uint64_t thread_elapsed = 0; | |
215 uint64_t process_elapsed = 0; | |
216 uint64_t child_thread_elapsed = 0; | |
217 uint64_t elapsed_lower_bound; | |
218 uint64_t elapsed_upper_bound; | |
219 | |
220 size_t i; | |
221 struct ThreadInfo info[10]; | |
222 pthread_t thread[10]; | |
223 | |
224 printf("\nCLOCK_PROCESS/THREAD_CPUTIME_ID accuracy test:\n"); | |
225 | |
226 if (0 != clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_thread_start)) { | |
227 fprintf(stderr, "clock_test: clock_gettime (now) failed, error %d\n", | |
228 errno); | |
229 num_failures++; | |
230 goto done; | |
231 } | |
232 | |
233 if (0 != clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t_process_start)) { | |
234 fprintf(stderr, "clock_test: clock_gettime (now) failed, error %d\n", | |
235 errno); | |
236 num_failures++; | |
237 goto done; | |
238 } | |
239 | |
240 for (i = 0; i < NACL_ARRAY_SIZE(thread); i++) { | |
241 memset(&info[i], 0, sizeof info[i]); | |
242 info[i].cycles = i * 10000000; | |
243 if (0 != (err = pthread_create(&thread[i], NULL, | |
244 ThreadFunction, &info[i]))) { | |
245 fprintf(stderr, "clock_test: pthread_create failed, error %d\n", | |
246 err); | |
247 num_failures++; | |
248 goto done; | |
249 } | |
250 } | |
251 | |
252 for (i = 0; i < NACL_ARRAY_SIZE(thread); i++) { | |
253 if (0 != (err = pthread_join(thread[i], NULL))) { | |
254 fprintf(stderr, "clock_test: pthread_join failed, error %d\n", | |
255 err); | |
256 num_failures++; | |
257 goto done; | |
258 } | |
259 } | |
260 | |
261 if (0 != clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t_process_end)) { | |
262 fprintf(stderr, "clock_test: clock_gettime (now) failed, error %d\n", | |
263 errno); | |
264 num_failures++; | |
265 goto done; | |
266 } | |
267 | |
268 if (0 != clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t_thread_end)) { | |
269 fprintf(stderr, "clock_test: clock_gettime (now) failed, error %d\n", | |
270 errno); | |
271 num_failures++; | |
272 goto done; | |
273 } | |
274 | |
275 thread_elapsed = | |
276 (t_thread_end.tv_sec - t_thread_start.tv_sec) * NANOS_PER_UNIT | |
277 + (t_thread_end.tv_nsec - t_thread_start.tv_nsec); | |
Roland McGrath
2013/08/28 19:54:34
again
Petr Hosek
2013/08/28 22:48:57
Fixed.
| |
278 | |
279 process_elapsed = | |
280 (t_process_end.tv_sec - t_process_start.tv_sec) * NANOS_PER_UNIT | |
281 + (t_process_end.tv_nsec - t_process_start.tv_nsec); | |
Roland McGrath
2013/08/28 19:54:34
again
Petr Hosek
2013/08/28 22:48:57
Fixed.
| |
282 | |
283 for (i = 0; i < NACL_ARRAY_SIZE(thread); i++) { | |
284 uint64_t thread_elapsed_nanos; | |
285 uint64_t process_elapsed_nanos; | |
286 | |
287 if (info[i].num_failures > 0) { | |
288 num_failures += info[i].num_failures; | |
289 goto done; | |
290 } | |
291 | |
292 thread_elapsed_nanos = info[i].thread_time.tv_sec * NANOS_PER_UNIT | |
293 + info[i].thread_time.tv_nsec; | |
Roland McGrath
2013/08/28 19:54:34
again
Petr Hosek
2013/08/28 22:48:57
Fixed.
| |
294 process_elapsed_nanos = info[i].process_time.tv_sec * NANOS_PER_UNIT | |
295 + info[i].process_time.tv_nsec; | |
Roland McGrath
2013/08/28 19:54:34
again
Petr Hosek
2013/08/28 22:48:57
Fixed.
| |
296 printf("%zd: thread=%20"PRIu64" nS, process=%20"PRIu64" nS\n", | |
297 i, thread_elapsed_nanos, process_elapsed_nanos); | |
298 child_thread_elapsed += thread_elapsed_nanos; | |
299 } | |
300 | |
301 elapsed_lower_bound = thread_elapsed + child_thread_elapsed; | |
302 elapsed_upper_bound = (uint64_t) (thread_elapsed | |
303 + child_thread_elapsed * g_fuzzy_factor + g_syscall_overhead); | |
Roland McGrath
2013/08/28 19:54:34
again
Petr Hosek
2013/08/28 22:48:57
Fixed.
| |
304 | |
305 printf("thread time: %20"PRIu64" nS\n", thread_elapsed); | |
306 printf("process time: %20"PRIu64" nS\n", process_elapsed); | |
307 printf("child thread time: %20"PRIu64" nS\n", child_thread_elapsed); | |
308 printf("elapsed lower bound: %20"PRIu64" nS\n", elapsed_lower_bound); | |
309 printf("elapsed upper bound: %20"PRIu64" nS\n", elapsed_upper_bound); | |
310 | |
311 if (process_elapsed < elapsed_lower_bound | |
312 || elapsed_upper_bound < process_elapsed) { | |
Roland McGrath
2013/08/28 19:54:34
again
Petr Hosek
2013/08/28 22:48:57
Fixed.
| |
313 printf("discrepancy too large\n"); | |
314 num_failures++; | |
315 } | |
316 done: | |
317 printf((0 == num_failures) ? "PASSED\n" : "FAILED\n"); | |
318 return num_failures; | |
319 } | |
320 | |
321 int main(int ac, char **av) { | |
322 uint64_t sleep_nanos = DEFAULT_NANOSLEEP_TIME; | |
323 int opt; | |
324 uint32_t num_failures = 0; | |
325 | |
326 while (-1 != (opt = getopt(ac, av, "cf:o:s:S:"))) { | |
327 switch (opt) { | |
328 case 'c': | |
329 g_cputime = 0; | |
330 break; | |
331 case 'f': | |
332 g_fuzzy_factor = strtod(optarg, (char **) NULL); | |
333 break; | |
334 case 'o': | |
335 g_syscall_overhead = strtoul(optarg, (char **) NULL, 0); | |
336 break; | |
337 case 's': | |
338 g_slop_ms = strtoul(optarg, (char **) NULL, 0); | |
339 break; | |
340 case 'S': | |
341 sleep_nanos = strtoul(optarg, (char **) NULL, 0); | |
342 break; | |
343 default: | |
344 fprintf(stderr, "clock_test: unrecognized option `%c'.\n", | |
345 opt); | |
346 fprintf(stderr, | |
347 "Usage: clock_test [-f fuzz_factor] [-s sleep_nanos]\n" | |
348 " [-o syscall_overhead_nanos]\n"); | |
349 return -1; | |
350 } | |
351 } | |
352 | |
353 num_failures += ClockMonotonicAccuracyTest(sleep_nanos); | |
354 num_failures += ClockRealtimeAccuracyTest(); | |
355 if (g_cputime) { | |
356 num_failures += ClockCpuTimeAccuracyTest(); | |
357 } | |
358 | |
359 return num_failures; | |
360 } | |
OLD | NEW |