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