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