]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - tools/tools/syscall_timing/syscall_timing.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / tools / tools / syscall_timing / syscall_timing.c
1 /*-
2  * Copyright (c) 2003-2004, 2010 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * Portions of this software were developed at the University of Cambridge
6  * Computer Laboratory with support from a grant from Google, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 #include <sys/types.h>
33 #include <sys/mman.h>
34 #include <sys/socket.h>
35 #include <sys/stat.h>
36 #include <sys/time.h>
37 #include <sys/wait.h>
38
39 #include <assert.h>
40 #include <err.h>
41 #include <fcntl.h>
42 #include <inttypes.h>
43 #include <limits.h>
44 #include <signal.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49
50 static struct timespec ts_start, ts_end;
51 static int alarm_timeout;
52 static volatile int alarm_fired;
53
54 #define timespecsub(vvp, uvp)                                           \
55         do {                                                            \
56                 (vvp)->tv_sec -= (uvp)->tv_sec;                         \
57                 (vvp)->tv_nsec -= (uvp)->tv_nsec;                       \
58                 if ((vvp)->tv_nsec < 0) {                               \
59                         (vvp)->tv_sec--;                                \
60                         (vvp)->tv_nsec += 1000000000;                   \
61                 }                                                       \
62         } while (0)
63
64 static void
65 alarm_handler(int signum)
66 {
67
68         alarm_fired = 1;
69 }
70
71 static void
72 benchmark_start(void)
73 {
74
75         alarm_fired = 0;
76         if (alarm_timeout) {
77                 signal(SIGALRM, alarm_handler);
78                 alarm(alarm_timeout);
79         }
80         assert(clock_gettime(CLOCK_REALTIME, &ts_start) == 0);
81 }
82
83 static void
84 benchmark_stop(void)
85 {
86
87         assert(clock_gettime(CLOCK_REALTIME, &ts_end) == 0);
88 }
89   
90 uintmax_t
91 test_getuid(uintmax_t num, uintmax_t int_arg, const char *path)
92 {
93         uintmax_t i;
94
95         /*
96          * Thread-local data should require no locking if system
97          * call is MPSAFE.
98          */
99         benchmark_start();
100         for (i = 0; i < num; i++) {
101                 if (alarm_fired)
102                         break;
103                 getuid();
104         }
105         benchmark_stop();
106         return (i);
107 }
108
109 uintmax_t
110 test_getppid(uintmax_t num, uintmax_t int_arg, const char *path)
111 {
112         uintmax_t i;
113
114         /*
115          * This is process-local, but can change, so will require a
116          * lock.
117          */
118         benchmark_start();
119         for (i = 0; i < num; i++) {
120                 if (alarm_fired)
121                         break;
122                 getppid();
123         }
124         benchmark_stop();
125         return (i);
126 }
127
128 uintmax_t
129 test_clock_gettime(uintmax_t num, uintmax_t int_arg, const char *path)
130 {
131         struct timespec ts;
132         uintmax_t i;
133
134         benchmark_start();
135         for (i = 0; i < num; i++) {
136                 if (alarm_fired)
137                         break;
138                 (void)clock_gettime(CLOCK_REALTIME, &ts);
139         }
140         benchmark_stop();
141         return (i);
142 }
143
144 uintmax_t
145 test_pipe(uintmax_t num, uintmax_t int_arg, const char *path)
146 {
147         int fd[2], i;
148
149         /*
150          * pipe creation is expensive, as it will allocate a new file
151          * descriptor, allocate a new pipe, hook it all up, and return.
152          * Destroying is also expensive, as we now have to free up
153          * the file descriptors and return the pipe.
154          */
155         if (pipe(fd) < 0)
156                 err(-1, "test_pipe: pipe");
157         close(fd[0]);
158         close(fd[1]);
159         benchmark_start();
160         for (i = 0; i < num; i++) {
161                 if (alarm_fired)
162                         break;
163                 if (pipe(fd) == -1)
164                         err(-1, "test_pipe: pipe");
165                 close(fd[0]);
166                 close(fd[1]);
167         }
168         benchmark_stop();
169         return (i);
170 }
171
172 uintmax_t
173 test_socket_stream(uintmax_t num, uintmax_t int_arg, const char *path)
174 {
175         uintmax_t i, so;
176
177         so = socket(int_arg, SOCK_STREAM, 0);
178         if (so < 0)
179                 err(-1, "test_socket_stream: socket");
180         close(so);
181         benchmark_start();
182         for (i = 0; i < num; i++) {
183                 if (alarm_fired)
184                         break;
185                 so = socket(int_arg, SOCK_STREAM, 0);
186                 if (so == -1)
187                         err(-1, "test_socket_stream: socket");
188                 close(so);
189         }
190         benchmark_stop();
191         return (i);
192 }
193
194 uintmax_t
195 test_socket_dgram(uintmax_t num, uintmax_t int_arg, const char *path)
196 {
197         uintmax_t i, so;
198
199         so = socket(int_arg, SOCK_DGRAM, 0);
200         if (so < 0)
201                 err(-1, "test_socket_dgram: socket");
202         close(so);
203         benchmark_start();
204         for (i = 0; i < num; i++) {
205                 if (alarm_fired)
206                         break;
207                 so = socket(int_arg, SOCK_DGRAM, 0);
208                 if (so == -1)
209                         err(-1, "test_socket_dgram: socket");
210                 close(so);
211         }
212         benchmark_stop();
213         return (i);
214 }
215
216 uintmax_t
217 test_socketpair_stream(uintmax_t num, uintmax_t int_arg, const char *path)
218 {
219         uintmax_t i;
220         int so[2];
221
222         if (socketpair(PF_LOCAL, SOCK_STREAM, 0, so) == -1)
223                 err(-1, "test_socketpair_stream: socketpair");
224         close(so[0]);
225         close(so[1]);
226         benchmark_start();
227         for (i = 0; i < num; i++) {
228                 if (alarm_fired)
229                         break;
230                 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, so) == -1)
231                         err(-1, "test_socketpair_stream: socketpair");
232                 close(so[0]);
233                 close(so[1]);
234         }
235         benchmark_stop();
236         return (i);
237 }
238
239 uintmax_t
240 test_socketpair_dgram(uintmax_t num, uintmax_t int_arg, const char *path)
241 {
242         uintmax_t i;
243         int so[2];
244
245         if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, so) == -1)
246                 err(-1, "test_socketpair_dgram: socketpair");
247         close(so[0]);
248         close(so[1]);
249         benchmark_start();
250         for (i = 0; i < num; i++) {
251                 if (alarm_fired)
252                         break;
253                 if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, so) == -1)
254                         err(-1, "test_socketpair_dgram: socketpair");
255                 close(so[0]);
256                 close(so[1]);
257         }
258         benchmark_stop();
259         return (i);
260 }
261
262 uintmax_t
263 test_create_unlink(uintmax_t num, uintmax_t int_arg, const char *path)
264 {
265         uintmax_t i;
266         int fd;
267
268         (void)unlink(path);
269         fd = open(path, O_RDWR | O_CREAT, 0600);
270         if (fd < 0)
271                 err(-1, "test_create_unlink: create: %s", path);
272         close(fd);
273         if (unlink(path) < 0)
274                 err(-1, "test_create_unlink: unlink: %s", path);
275         benchmark_start();
276         for (i = 0; i < num; i++) {
277                 if (alarm_fired)
278                         break;
279                 fd = open(path, O_RDWR | O_CREAT, 0600);
280                 if (fd < 0)
281                         err(-1, "test_create_unlink: create: %s", path);
282                 close(fd);
283                 if (unlink(path) < 0)
284                         err(-1, "test_create_unlink: unlink: %s", path);
285         }
286         benchmark_stop();
287         return (i);
288 }
289
290 uintmax_t
291 test_open_close(uintmax_t num, uintmax_t int_arg, const char *path)
292 {
293         uintmax_t i;
294         int fd;
295
296         fd = open(path, O_RDONLY);
297         if (fd < 0)
298                 err(-1, "test_open_close: %s", path);
299         close(fd);
300
301         benchmark_start();
302         for (i = 0; i < num; i++) {
303                 if (alarm_fired)
304                         break;
305                 fd = open(path, O_RDONLY);
306                 if (fd < 0)
307                         err(-1, "test_open_close: %s", path);
308                 close(fd);
309         }
310         benchmark_stop();
311         return (i);
312 }
313
314 uintmax_t
315 test_read(uintmax_t num, uintmax_t int_arg, const char *path)
316 {
317         char buf[int_arg];
318         uintmax_t i;
319         int fd;
320
321         fd = open(path, O_RDONLY);
322         if (fd < 0)
323                 err(-1, "test_open_read: %s", path);
324         (void)pread(fd, buf, int_arg, 0);
325
326         benchmark_start();
327         for (i = 0; i < num; i++) {
328                 if (alarm_fired)
329                         break;
330                 (void)pread(fd, buf, int_arg, 0);
331         }
332         benchmark_stop();
333         close(fd);
334         return (i);
335 }
336
337 uintmax_t
338 test_open_read_close(uintmax_t num, uintmax_t int_arg, const char *path)
339 {
340         char buf[int_arg];
341         uintmax_t i;
342         int fd;
343
344         fd = open(path, O_RDONLY);
345         if (fd < 0)
346                 err(-1, "test_open_read_close: %s", path);
347         (void)read(fd, buf, int_arg);
348         close(fd);
349
350         benchmark_start();
351         for (i = 0; i < num; i++) {
352                 if (alarm_fired)
353                         break;
354                 fd = open(path, O_RDONLY);
355                 if (fd < 0)
356                         err(-1, "test_open_read_close: %s", path);
357                 (void)read(fd, buf, int_arg);
358                 close(fd);
359         }
360         benchmark_stop();
361         return (i);
362 }
363
364 uintmax_t
365 test_dup(uintmax_t num, uintmax_t int_arg, const char *path)
366 {
367         int fd, i, shmfd;
368
369         shmfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600);
370         if (shmfd < 0)
371                 err(-1, "test_dup: shm_open");
372         fd = dup(shmfd);
373         if (fd >= 0)
374                 close(fd);
375         benchmark_start();
376         for (i = 0; i < num; i++) {
377                 if (alarm_fired)
378                         break;
379                 fd = dup(shmfd);
380                 if (fd >= 0)
381                         close(fd);
382         }
383         benchmark_stop();
384         close(shmfd);
385         return (i);
386 }
387
388 uintmax_t
389 test_shmfd(uintmax_t num, uintmax_t int_arg, const char *path)
390 {
391         uintmax_t i, shmfd;
392
393         shmfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600);
394         if (shmfd < 0)
395                 err(-1, "test_shmfd: shm_open");
396         close(shmfd);
397         benchmark_start();
398         for (i = 0; i < num; i++) {
399                 if (alarm_fired)
400                         break;
401                 shmfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600);
402                 if (shmfd < 0)
403                         err(-1, "test_shmfd: shm_open");
404                 close(shmfd);
405         }
406         benchmark_stop();
407         return (i);
408 }
409
410 uintmax_t
411 test_fstat_shmfd(uintmax_t num, uintmax_t int_arg, const char *path)
412 {
413         struct stat sb;
414         uintmax_t i, shmfd;
415
416         shmfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600);
417         if (shmfd < 0)
418                 err(-1, "test_fstat_shmfd: shm_open");
419         if (fstat(shmfd, &sb) < 0)
420                 err(-1, "test_fstat_shmfd: fstat");
421         benchmark_start();
422         for (i = 0; i < num; i++) {
423                 if (alarm_fired)
424                         break;
425                 (void)fstat(shmfd, &sb);
426         }
427         benchmark_stop();
428         close(shmfd);
429         return (i);
430 }
431
432 uintmax_t
433 test_fork(uintmax_t num, uintmax_t int_arg, const char *path)
434 {
435         pid_t pid;
436         uintmax_t i;
437
438         pid = fork();
439         if (pid < 0)
440                 err(-1, "test_fork: fork");
441         if (pid == 0)
442                 _exit(0);
443         if (waitpid(pid, NULL, 0) < 0)
444                 err(-1, "test_fork: waitpid");
445         benchmark_start();
446         for (i = 0; i < num; i++) {
447                 if (alarm_fired)
448                         break;
449                 pid = fork();
450                 if (pid < 0)
451                         err(-1, "test_fork: fork");
452                 if (pid == 0)
453                         _exit(0);
454                 if (waitpid(pid, NULL, 0) < 0)
455                         err(-1, "test_fork: waitpid");
456         }
457         benchmark_stop();
458         return (i);
459 }
460
461 uintmax_t
462 test_vfork(uintmax_t num, uintmax_t int_arg, const char *path)
463 {
464         pid_t pid;
465         uintmax_t i;
466
467         pid = vfork();
468         if (pid < 0)
469                 err(-1, "test_vfork: vfork");
470         if (pid == 0)
471                 _exit(0);
472         if (waitpid(pid, NULL, 0) < 0)
473                 err(-1, "test_vfork: waitpid");
474         benchmark_start();
475         for (i = 0; i < num; i++) {
476                 if (alarm_fired)
477                         break;
478                 pid = vfork();
479                 if (pid < 0)
480                         err(-1, "test_vfork: vfork");
481                 if (pid == 0)
482                         _exit(0);
483                 if (waitpid(pid, NULL, 0) < 0)
484                         err(-1, "test_vfork: waitpid");
485         }
486         benchmark_stop();
487         return (i);
488 }
489
490 #define USR_BIN_TRUE    "/usr/bin/true"
491 static char *execve_args[] = { USR_BIN_TRUE, NULL};
492 extern char **environ;
493
494 uintmax_t
495 test_fork_exec(uintmax_t num, uintmax_t int_arg, const char *path)
496 {
497         pid_t pid;
498         uintmax_t i;
499
500         pid = fork();
501         if (pid < 0)
502                 err(-1, "test_fork_exec: fork");
503         if (pid == 0) {
504                 (void)execve(USR_BIN_TRUE, execve_args, environ);
505                 err(-1, "execve");
506         }
507         if (waitpid(pid, NULL, 0) < 0)
508                 err(-1, "test_fork: waitpid");
509         benchmark_start();
510         for (i = 0; i < num; i++) {
511                 if (alarm_fired)
512                         break;
513                 pid = fork();
514                 if (pid < 0)
515                         err(-1, "test_fork_exec: fork");
516                 if (pid == 0) {
517                         (void)execve(USR_BIN_TRUE, execve_args, environ);
518                         err(-1, "test_fork_exec: execve");
519                 }
520                 if (waitpid(pid, NULL, 0) < 0)
521                         err(-1, "test_fork_exec: waitpid");
522         }
523         benchmark_stop();
524         return (i);
525 }
526
527 uintmax_t
528 test_vfork_exec(uintmax_t num, uintmax_t int_arg, const char *path)
529 {
530         pid_t pid;
531         uintmax_t i;
532
533         pid = vfork();
534         if (pid < 0)
535                 err(-1, "test_vfork_exec: vfork");
536         if (pid == 0) {
537                 (void)execve(USR_BIN_TRUE, execve_args, environ);
538                 err(-1, "test_vfork_exec: execve");
539         }
540         if (waitpid(pid, NULL, 0) < 0)
541                 err(-1, "test_vfork_exec: waitpid");
542         benchmark_start();
543         for (i = 0; i < num; i++) {
544                 if (alarm_fired)
545                         break;
546                 pid = vfork();
547                 if (pid < 0)
548                         err(-1, "test_vfork_exec: vfork");
549                 if (pid == 0) {
550                         (void)execve(USR_BIN_TRUE, execve_args, environ);
551                         err(-1, "execve");
552                 }
553                 if (waitpid(pid, NULL, 0) < 0)
554                         err(-1, "test_vfork_exec: waitpid");
555         }
556         benchmark_stop();
557         return (i);
558 }
559
560 uintmax_t
561 test_chroot(uintmax_t num, uintmax_t int_arg, const char *path)
562 {
563         uintmax_t i;
564
565         if (chroot("/") < 0)
566                 err(-1, "test_chroot: chroot");
567         benchmark_start();
568         for (i = 0; i < num; i++) {
569                 if (alarm_fired)
570                         break;
571                 if (chroot("/") < 0)
572                         err(-1, "test_chroot: chroot");
573         }
574         benchmark_stop();
575         return (i);
576 }
577
578 uintmax_t
579 test_setuid(uintmax_t num, uintmax_t int_arg, const char *path)
580 {
581         uid_t uid;
582         uintmax_t i;
583
584         uid = getuid();
585         if (setuid(uid) < 0)
586                 err(-1, "test_setuid: setuid");
587         benchmark_start();
588         for (i = 0; i < num; i++) {
589                 if (alarm_fired)
590                         break;
591                 if (setuid(uid) < 0)
592                         err(-1, "test_setuid: setuid");
593         }
594         benchmark_stop();
595         return (i);
596 }
597
598 struct test {
599         const char      *t_name;
600         uintmax_t       (*t_func)(uintmax_t, uintmax_t, const char *);
601         int              t_flags;
602         uintmax_t        t_int;
603 };
604
605 #define FLAG_PATH       0x00000001
606
607 static const struct test tests[] = {
608         { "getuid", test_getuid },
609         { "getppid", test_getppid },
610         { "clock_gettime", test_clock_gettime },
611         { "pipe", test_pipe },
612         { "socket_local_stream", test_socket_stream, .t_int = PF_LOCAL },
613         { "socket_local_dgram", test_socket_dgram, .t_int = PF_LOCAL },
614         { "socketpair_stream", test_socketpair_stream },
615         { "socketpair_dgram", test_socketpair_dgram },
616         { "socket_tcp", test_socket_stream, .t_int = PF_INET },
617         { "socket_udp", test_socket_dgram, .t_int = PF_INET },
618         { "create_unlink", test_create_unlink, .t_flags = FLAG_PATH },
619         { "open_close", test_open_close, .t_flags = FLAG_PATH },
620         { "open_read_close_1", test_open_read_close, .t_flags = FLAG_PATH,
621             .t_int = 1 },
622         { "open_read_close_10", test_open_read_close, .t_flags = FLAG_PATH,
623             .t_int = 10 },
624         { "open_read_close_100", test_open_read_close, .t_flags = FLAG_PATH,
625             .t_int = 100 },
626         { "open_read_close_1000", test_open_read_close, .t_flags = FLAG_PATH,
627             .t_int = 1000 },
628         { "open_read_close_10000", test_open_read_close,
629             .t_flags = FLAG_PATH, .t_int = 10000 },
630         { "open_read_close_100000", test_open_read_close,
631             .t_flags = FLAG_PATH, .t_int = 100000 },
632         { "open_read_close_1000000", test_open_read_close,
633             .t_flags = FLAG_PATH, .t_int = 1000000 },
634         { "read_1", test_read, .t_flags = FLAG_PATH, .t_int = 1 },
635         { "read_10", test_read, .t_flags = FLAG_PATH, .t_int = 10 },
636         { "read_100", test_read, .t_flags = FLAG_PATH, .t_int = 100 },
637         { "read_1000", test_read, .t_flags = FLAG_PATH, .t_int = 1000 },
638         { "read_10000", test_read, .t_flags = FLAG_PATH, .t_int = 10000 },
639         { "read_100000", test_read, .t_flags = FLAG_PATH, .t_int = 100000 },
640         { "read_1000000", test_read, .t_flags = FLAG_PATH, .t_int = 1000000 },
641         { "dup", test_dup },
642         { "shmfd", test_shmfd },
643         { "fstat_shmfd", test_fstat_shmfd },
644         { "fork", test_fork },
645         { "vfork", test_vfork },
646         { "fork_exec", test_fork_exec },
647         { "vfork_exec", test_vfork_exec },
648         { "chroot", test_chroot },
649         { "setuid", test_setuid },
650 };
651 static const int tests_count = sizeof(tests) / sizeof(tests[0]);
652
653 static void
654 usage(void)
655 {
656         int i;
657
658         fprintf(stderr, "syscall_timing [-i iterations] [-l loops] "
659             "[-p path] [-s seconds] test\n");
660         for (i = 0; i < tests_count; i++)
661                 fprintf(stderr, "  %s\n", tests[i].t_name);
662         exit(-1);
663 }
664
665 int
666 main(int argc, char *argv[])
667 {
668         struct timespec ts_res;
669         const struct test *the_test;
670         const char *path;
671         long long ll;
672         char *endp;
673         int ch, i, j, k;
674         uintmax_t iterations, loops;
675
676         alarm_timeout = 1;
677         iterations = 0;
678         loops = 10;
679         path = NULL;
680         while ((ch = getopt(argc, argv, "i:l:p:s:")) != -1) {
681                 switch (ch) {
682                 case 'i':
683                         ll = strtol(optarg, &endp, 10);
684                         if (*endp != 0 || ll < 1 || ll > 100000)
685                                 usage();
686                         iterations = ll;
687                         break;
688
689                 case 'l':
690                         ll = strtol(optarg, &endp, 10);
691                         if (*endp != 0 || ll < 1 || ll > 100000)
692                                 usage();
693                         loops = ll;
694                         break;
695
696                 case 'p':
697                         path = optarg;
698                         break;
699
700                 case 's':
701                         ll = strtol(optarg, &endp, 10);
702                         if (*endp != 0 || ll < 1 || ll > 60*60)
703                                 usage();
704                         alarm_timeout = ll;
705                         break;
706
707                 case '?':
708                 default:
709                         usage();
710                 }
711         }
712         argc -= optind;
713         argv += optind;
714
715         if (iterations < 1 && alarm_timeout < 1)
716                 usage();
717         if (iterations < 1)
718                 iterations = UINT64_MAX;
719         if (loops < 1)
720                 loops = 1;
721
722         if (argc < 1)
723                 usage();
724
725         /*
726          * Validate test list and that, if a path is required, it is
727          * defined.
728          */
729         for (j = 0; j < argc; j++) {
730                 the_test = NULL;
731                 for (i = 0; i < tests_count; i++) {
732                         if (strcmp(argv[j], tests[i].t_name) == 0)
733                                 the_test = &tests[i];
734                 }
735                 if (the_test == NULL)
736                         usage();
737                 if ((the_test->t_flags & FLAG_PATH) && (path == NULL)) {
738                         errx(-1, "%s requires -p", the_test->t_name);
739                 }
740         }
741
742         assert(clock_getres(CLOCK_REALTIME, &ts_res) == 0);
743         printf("Clock resolution: %ju.%09ju\n", (uintmax_t)ts_res.tv_sec,
744             (uintmax_t)ts_res.tv_nsec);
745         printf("test\tloop\ttime\titerations\tperiteration\n");
746
747         for (j = 0; j < argc; j++) {
748                 uintmax_t calls, nsecsperit;
749
750                 the_test = NULL;
751                 for (i = 0; i < tests_count; i++) {
752                         if (strcmp(argv[j], tests[i].t_name) == 0)
753                                 the_test = &tests[i];
754                 }
755
756                 /*
757                  * Run one warmup, then do the real thing (loops) times.
758                  */
759                 the_test->t_func(iterations, the_test->t_int, path);
760                 calls = 0;
761                 for (k = 0; k < loops; k++) {
762                         calls = the_test->t_func(iterations, the_test->t_int,
763                             path);
764                         timespecsub(&ts_end, &ts_start);
765                         printf("%s\t%d\t", the_test->t_name, k);
766                         printf("%ju.%09ju\t%d\t", (uintmax_t)ts_end.tv_sec,
767                             (uintmax_t)ts_end.tv_nsec, calls);
768
769                 /*
770                  * Note.  This assumes that each iteration takes less than
771                  * a second, and that our total nanoseconds doesn't exceed
772                  * the room in our arithmetic unit.  Fine for system calls,
773                  * but not for long things.
774                  */
775                         nsecsperit = ts_end.tv_sec * 1000000000;
776                         nsecsperit += ts_end.tv_nsec;
777                         nsecsperit /= calls;
778                         printf("0.%09ju\n", (uintmax_t)nsecsperit);
779                 }
780         }
781         return (0);
782 }