2 * Copyright (c) 2003-2004, 2010 Robert N. M. Watson
5 * Portions of this software were developed at the University of Cambridge
6 * Computer Laboratory with support from a grant from Google, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
32 #include <sys/param.h>
33 #include <sys/types.h>
35 #include <sys/procdesc.h>
36 #include <sys/resource.h>
37 #include <sys/socket.h>
51 #include <semaphore.h>
58 static struct timespec ts_start, ts_end;
59 static int alarm_timeout;
60 static volatile int alarm_fired;
62 #define BENCHMARK_FOREACH(I, NUM) for (I = 0; I < NUM && alarm_fired == 0; I++)
65 alarm_handler(int signum __unused)
78 signal(SIGALRM, alarm_handler);
81 error = clock_gettime(CLOCK_REALTIME, &ts_start);
90 error = clock_gettime(CLOCK_REALTIME, &ts_end);
95 test_access(uintmax_t num, uintmax_t int_arg __unused, const char *path)
100 fd = access(path, O_RDONLY);
102 err(-1, "test_access: %s", path);
106 BENCHMARK_FOREACH(i, num) {
107 access(path, O_RDONLY);
115 test_bad_open(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
120 BENCHMARK_FOREACH(i, num) {
128 test_chroot(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
133 err(-1, "test_chroot: chroot");
135 BENCHMARK_FOREACH(i, num) {
137 err(-1, "test_chroot: chroot");
144 test_clock_gettime(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
150 BENCHMARK_FOREACH(i, num) {
151 (void)clock_gettime(CLOCK_REALTIME, &ts);
158 test_create_unlink(uintmax_t num, uintmax_t int_arg __unused, const char *path)
164 fd = open(path, O_RDWR | O_CREAT, 0600);
166 err(-1, "test_create_unlink: create: %s", path);
168 if (unlink(path) < 0)
169 err(-1, "test_create_unlink: unlink: %s", path);
171 BENCHMARK_FOREACH(i, num) {
172 fd = open(path, O_RDWR | O_CREAT, 0600);
174 err(-1, "test_create_unlink: create: %s", path);
176 if (unlink(path) < 0)
177 err(-1, "test_create_unlink: unlink: %s", path);
184 test_fork(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
191 err(-1, "test_fork: fork");
194 if (waitpid(pid, NULL, 0) < 0)
195 err(-1, "test_fork: waitpid");
197 BENCHMARK_FOREACH(i, num) {
200 err(-1, "test_fork: fork");
203 if (waitpid(pid, NULL, 0) < 0)
204 err(-1, "test_fork: waitpid");
210 #define USR_BIN_TRUE "/usr/bin/true"
211 static char *execve_args[] = { __DECONST(char *, USR_BIN_TRUE), NULL};
212 extern char **environ;
215 test_fork_exec(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
222 err(-1, "test_fork_exec: fork");
224 (void)execve(USR_BIN_TRUE, execve_args, environ);
227 if (waitpid(pid, NULL, 0) < 0)
228 err(-1, "test_fork: waitpid");
230 BENCHMARK_FOREACH(i, num) {
233 err(-1, "test_fork_exec: fork");
235 (void)execve(USR_BIN_TRUE, execve_args, environ);
236 err(-1, "test_fork_exec: execve");
238 if (waitpid(pid, NULL, 0) < 0)
239 err(-1, "test_fork_exec: waitpid");
246 test_getppid(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
251 * This is process-local, but can change, so will require a
255 BENCHMARK_FOREACH(i, num) {
263 test_getpriority(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
268 BENCHMARK_FOREACH(i, num) {
269 (void)getpriority(PRIO_PROCESS, 0);
276 * The point of this one is to figure out the cost of a call into libc,
277 * through PLT, and back.
280 test_getprogname(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
285 BENCHMARK_FOREACH(i, num) {
293 test_getresuid(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
295 uid_t ruid, euid, suid;
299 BENCHMARK_FOREACH(i, num) {
300 (void)getresuid(&ruid, &euid, &suid);
307 test_gettimeofday(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
313 BENCHMARK_FOREACH(i, num) {
314 (void)gettimeofday(&tv, NULL);
321 test_getuid(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
326 * Thread-local data should require no locking if system
330 BENCHMARK_FOREACH(i, num) {
338 test_lstat(uintmax_t num, uintmax_t int_arg __unused, const char *path)
345 BENCHMARK_FOREACH(i, num) {
346 error = lstat(path, &sb);
355 test_memcpy(uintmax_t num, uintmax_t int_arg, const char *path __unused)
357 char buf[int_arg], buf2[int_arg];
361 BENCHMARK_FOREACH(i, num) {
363 * Copy the memory there and back, to match the total amount
364 * moved by pipeping/pipepingtd tests.
366 memcpy(buf2, buf, int_arg);
367 memcpy(buf, buf2, int_arg);
375 test_open_close(uintmax_t num, uintmax_t int_arg __unused, const char *path)
380 fd = open(path, O_RDONLY);
382 err(-1, "test_open_close: %s", path);
386 BENCHMARK_FOREACH(i, num) {
387 fd = open(path, O_RDONLY);
389 err(-1, "test_open_close: %s", path);
397 test_open_read_close(uintmax_t num, uintmax_t int_arg, const char *path)
403 fd = open(path, O_RDONLY);
405 err(-1, "test_open_read_close: %s", path);
406 (void)read(fd, buf, int_arg);
410 BENCHMARK_FOREACH(i, num) {
411 fd = open(path, O_RDONLY);
413 err(-1, "test_open_read_close: %s", path);
414 (void)read(fd, buf, int_arg);
422 test_pipe(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
428 * pipe creation is expensive, as it will allocate a new file
429 * descriptor, allocate a new pipe, hook it all up, and return.
430 * Destroying is also expensive, as we now have to free up
431 * the file descriptors and return the pipe.
434 err(-1, "test_pipe: pipe");
438 BENCHMARK_FOREACH(i, num) {
440 err(-1, "test_pipe: pipe");
449 readx(int fd, char *buf, size_t size)
454 ret = read(fd, buf, size);
457 assert((size_t)ret <= size);
464 writex(int fd, const char *buf, size_t size)
469 ret = write(fd, buf, size);
472 assert((size_t)ret <= size);
479 test_pipeping(uintmax_t num, uintmax_t int_arg, const char *path __unused)
489 pid = pdfork(&procfd, 0);
497 readx(fd[1], buf, int_arg);
498 writex(fd[1], buf, int_arg);
505 BENCHMARK_FOREACH(i, num) {
506 writex(fd[0], buf, int_arg);
507 readx(fd[0], buf, int_arg);
516 struct pipepingtd_ctx {
522 pipepingtd_proc(void *arg)
524 struct pipepingtd_ctx *ctxp;
531 int_arg = ctxp->int_arg;
533 buf = malloc(int_arg);
538 readx(fd, buf, int_arg);
539 writex(fd, buf, int_arg);
544 test_pipepingtd(uintmax_t num, uintmax_t int_arg, const char *path __unused)
546 struct pipepingtd_ctx ctx;
556 ctx.int_arg = int_arg;
558 error = pthread_create(&td, NULL, pipepingtd_proc, &ctx);
560 err(1, "pthread_create");
563 BENCHMARK_FOREACH(i, num) {
564 writex(fd[0], buf, int_arg);
565 readx(fd[0], buf, int_arg);
572 #endif /* WITH_PTHREAD */
575 test_read(uintmax_t num, uintmax_t int_arg, const char *path)
581 fd = open(path, O_RDONLY);
583 err(-1, "test_open_read: %s", path);
584 (void)pread(fd, buf, int_arg, 0);
587 BENCHMARK_FOREACH(i, num) {
588 (void)pread(fd, buf, int_arg, 0);
596 test_select(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
598 fd_set readfds, writefds, exceptfds;
610 BENCHMARK_FOREACH(i, num) {
611 (void)select(0, &readfds, &writefds, &exceptfds, &tv);
618 test_semaping(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
623 int error, j, procfd;
625 buf = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
626 if (buf == MAP_FAILED)
629 for (j = 0; j < 2; j++) {
630 error = sem_init(&buf[j], 1, 0);
635 pid = pdfork(&procfd, 0);
641 error = sem_wait(&buf[0]);
644 error = sem_post(&buf[1]);
651 BENCHMARK_FOREACH(i, num) {
652 error = sem_post(&buf[0]);
655 error = sem_wait(&buf[1]);
663 for (j = 0; j < 2; j++) {
664 error = sem_destroy(&buf[j]);
666 err(1, "sem_destroy");
669 error = munmap(buf, PAGE_SIZE);
677 test_setuid(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
684 err(-1, "test_setuid: setuid");
686 BENCHMARK_FOREACH(i, num) {
688 err(-1, "test_setuid: setuid");
695 test_shmfd(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
700 shmfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600);
702 err(-1, "test_shmfd: shm_open");
705 BENCHMARK_FOREACH(i, num) {
706 shmfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600);
708 err(-1, "test_shmfd: shm_open");
716 test_shmfd_dup(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
721 shmfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600);
723 err(-1, "test_shmfd_dup: shm_open");
728 BENCHMARK_FOREACH(i, num) {
739 test_shmfd_fstat(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
745 shmfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600);
747 err(-1, "test_shmfd_fstat: shm_open");
748 if (fstat(shmfd, &sb) < 0)
749 err(-1, "test_shmfd_fstat: fstat");
751 BENCHMARK_FOREACH(i, num) {
752 (void)fstat(shmfd, &sb);
760 test_socket_stream(uintmax_t num, uintmax_t int_arg, const char *path __unused)
765 so = socket(int_arg, SOCK_STREAM, 0);
767 err(-1, "test_socket_stream: socket");
770 BENCHMARK_FOREACH(i, num) {
771 so = socket(int_arg, SOCK_STREAM, 0);
773 err(-1, "test_socket_stream: socket");
781 test_socket_dgram(uintmax_t num, uintmax_t int_arg, const char *path __unused)
786 so = socket(int_arg, SOCK_DGRAM, 0);
788 err(-1, "test_socket_dgram: socket");
791 BENCHMARK_FOREACH(i, num) {
792 so = socket(int_arg, SOCK_DGRAM, 0);
794 err(-1, "test_socket_dgram: socket");
802 test_socketpair_stream(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
807 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, so) == -1)
808 err(-1, "test_socketpair_stream: socketpair");
812 BENCHMARK_FOREACH(i, num) {
813 if (socketpair(PF_LOCAL, SOCK_STREAM, 0, so) == -1)
814 err(-1, "test_socketpair_stream: socketpair");
823 test_socketpair_dgram(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
828 if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, so) == -1)
829 err(-1, "test_socketpair_dgram: socketpair");
833 BENCHMARK_FOREACH(i, num) {
834 if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, so) == -1)
835 err(-1, "test_socketpair_dgram: socketpair");
844 test_readlink(uintmax_t num, uintmax_t int_arg __unused, const char *path)
851 BENCHMARK_FOREACH(i, num) {
852 rv = readlink(path, buf, sizeof(buf));
853 if (rv < 0 && errno != EINVAL)
861 test_vfork(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
868 err(-1, "test_vfork: vfork");
871 if (waitpid(pid, NULL, 0) < 0)
872 err(-1, "test_vfork: waitpid");
874 BENCHMARK_FOREACH(i, num) {
877 err(-1, "test_vfork: vfork");
880 if (waitpid(pid, NULL, 0) < 0)
881 err(-1, "test_vfork: waitpid");
888 test_vfork_exec(uintmax_t num, uintmax_t int_arg __unused, const char *path __unused)
895 err(-1, "test_vfork_exec: vfork");
897 (void)execve(USR_BIN_TRUE, execve_args, environ);
898 err(-1, "test_vfork_exec: execve");
900 if (waitpid(pid, NULL, 0) < 0)
901 err(-1, "test_vfork_exec: waitpid");
903 BENCHMARK_FOREACH(i, num) {
906 err(-1, "test_vfork_exec: vfork");
908 (void)execve(USR_BIN_TRUE, execve_args, environ);
911 if (waitpid(pid, NULL, 0) < 0)
912 err(-1, "test_vfork_exec: waitpid");
920 uintmax_t (*t_func)(uintmax_t, uintmax_t, const char *);
925 #define FLAG_PATH 0x00000001
927 static const struct test tests[] = {
928 { "access", test_access, .t_flags = FLAG_PATH },
929 { "bad_open", test_bad_open, .t_flags = 0 },
930 { "chroot", test_chroot, .t_flags = 0 },
931 { "clock_gettime", test_clock_gettime, .t_flags = 0 },
932 { "create_unlink", test_create_unlink, .t_flags = FLAG_PATH },
933 { "fork", test_fork, .t_flags = 0 },
934 { "fork_exec", test_fork_exec, .t_flags = 0 },
935 { "getppid", test_getppid, .t_flags = 0 },
936 { "getpriority", test_getpriority, .t_flags = 0 },
937 { "getprogname", test_getprogname, .t_flags = 0 },
938 { "getresuid", test_getresuid, .t_flags = 0 },
939 { "gettimeofday", test_gettimeofday, .t_flags = 0 },
940 { "getuid", test_getuid, .t_flags = 0 },
941 { "lstat", test_lstat, .t_flags = FLAG_PATH },
942 { "memcpy_1", test_memcpy, .t_flags = 0, .t_int = 1 },
943 { "memcpy_10", test_memcpy, .t_flags = 0, .t_int = 10 },
944 { "memcpy_100", test_memcpy, .t_flags = 0, .t_int = 100 },
945 { "memcpy_1000", test_memcpy, .t_flags = 0, .t_int = 1000 },
946 { "memcpy_10000", test_memcpy, .t_flags = 0, .t_int = 10000 },
947 { "memcpy_100000", test_memcpy, .t_flags = 0, .t_int = 100000 },
948 { "memcpy_1000000", test_memcpy, .t_flags = 0, .t_int = 1000000 },
949 { "open_close", test_open_close, .t_flags = FLAG_PATH },
950 { "open_read_close_1", test_open_read_close, .t_flags = FLAG_PATH,
952 { "open_read_close_10", test_open_read_close, .t_flags = FLAG_PATH,
954 { "open_read_close_100", test_open_read_close, .t_flags = FLAG_PATH,
956 { "open_read_close_1000", test_open_read_close, .t_flags = FLAG_PATH,
958 { "open_read_close_10000", test_open_read_close,
959 .t_flags = FLAG_PATH, .t_int = 10000 },
960 { "open_read_close_100000", test_open_read_close,
961 .t_flags = FLAG_PATH, .t_int = 100000 },
962 { "open_read_close_1000000", test_open_read_close,
963 .t_flags = FLAG_PATH, .t_int = 1000000 },
964 { "pipe", test_pipe, .t_flags = 0 },
965 { "pipeping_1", test_pipeping, .t_flags = 0, .t_int = 1 },
966 { "pipeping_10", test_pipeping, .t_flags = 0, .t_int = 10 },
967 { "pipeping_100", test_pipeping, .t_flags = 0, .t_int = 100 },
968 { "pipeping_1000", test_pipeping, .t_flags = 0, .t_int = 1000 },
969 { "pipeping_10000", test_pipeping, .t_flags = 0, .t_int = 10000 },
970 { "pipeping_100000", test_pipeping, .t_flags = 0, .t_int = 100000 },
971 { "pipeping_1000000", test_pipeping, .t_flags = 0, .t_int = 1000000 },
973 { "pipepingtd_1", test_pipepingtd, .t_flags = 0, .t_int = 1 },
974 { "pipepingtd_10", test_pipepingtd, .t_flags = 0, .t_int = 10 },
975 { "pipepingtd_100", test_pipepingtd, .t_flags = 0, .t_int = 100 },
976 { "pipepingtd_1000", test_pipepingtd, .t_flags = 0, .t_int = 1000 },
977 { "pipepingtd_10000", test_pipepingtd, .t_flags = 0, .t_int = 10000 },
978 { "pipepingtd_100000", test_pipepingtd, .t_flags = 0, .t_int = 100000 },
979 { "pipepingtd_1000000", test_pipepingtd, .t_flags = 0, .t_int = 1000000 },
981 { "read_1", test_read, .t_flags = FLAG_PATH, .t_int = 1 },
982 { "read_10", test_read, .t_flags = FLAG_PATH, .t_int = 10 },
983 { "read_100", test_read, .t_flags = FLAG_PATH, .t_int = 100 },
984 { "read_1000", test_read, .t_flags = FLAG_PATH, .t_int = 1000 },
985 { "read_10000", test_read, .t_flags = FLAG_PATH, .t_int = 10000 },
986 { "read_100000", test_read, .t_flags = FLAG_PATH, .t_int = 100000 },
987 { "read_1000000", test_read, .t_flags = FLAG_PATH, .t_int = 1000000 },
988 { "select", test_select, .t_flags = 0 },
989 { "semaping", test_semaping, .t_flags = 0 },
990 { "setuid", test_setuid, .t_flags = 0 },
991 { "shmfd", test_shmfd, .t_flags = 0 },
992 { "shmfd_dup", test_shmfd_dup, .t_flags = 0 },
993 { "shmfd_fstat", test_shmfd_fstat, .t_flags = 0 },
994 { "socket_local_stream", test_socket_stream, .t_int = PF_LOCAL },
995 { "socket_local_dgram", test_socket_dgram, .t_int = PF_LOCAL },
996 { "socketpair_stream", test_socketpair_stream, .t_flags = 0 },
997 { "socketpair_dgram", test_socketpair_dgram, .t_flags = 0 },
998 { "socket_tcp", test_socket_stream, .t_int = PF_INET },
999 { "socket_udp", test_socket_dgram, .t_int = PF_INET },
1000 { "readlink", test_readlink, .t_flags = FLAG_PATH },
1001 { "vfork", test_vfork, .t_flags = 0 },
1002 { "vfork_exec", test_vfork_exec, .t_flags = 0 },
1004 static const int tests_count = sizeof(tests) / sizeof(tests[0]);
1011 fprintf(stderr, "syscall_timing [-i iterations] [-l loops] "
1012 "[-p path] [-s seconds] test\n");
1013 for (i = 0; i < tests_count; i++)
1014 fprintf(stderr, " %s\n", tests[i].t_name);
1019 main(int argc, char *argv[])
1021 struct timespec ts_res;
1022 const struct test *the_test;
1024 char *tmp_dir, *tmp_path;
1027 int ch, fd, error, i, j, rv;
1028 uintmax_t iterations, k, loops;
1035 while ((ch = getopt(argc, argv, "i:l:p:s:")) != -1) {
1038 ll = strtol(optarg, &endp, 10);
1039 if (*endp != 0 || ll < 1)
1045 ll = strtol(optarg, &endp, 10);
1046 if (*endp != 0 || ll < 1 || ll > 100000)
1056 ll = strtol(optarg, &endp, 10);
1057 if (*endp != 0 || ll < 1 || ll > 60*60)
1070 if (iterations < 1 && alarm_timeout < 1)
1073 iterations = UINT64_MAX;
1081 * Validate test list and that, if a path is required, it is
1084 for (j = 0; j < argc; j++) {
1086 for (i = 0; i < tests_count; i++) {
1087 if (strcmp(argv[j], tests[i].t_name) == 0)
1088 the_test = &tests[i];
1090 if (the_test == NULL)
1092 if ((the_test->t_flags & FLAG_PATH) && (path == NULL)) {
1093 tmp_dir = strdup("/tmp/syscall_timing.XXXXXXXX");
1094 if (tmp_dir == NULL)
1096 tmp_dir = mkdtemp(tmp_dir);
1097 if (tmp_dir == NULL)
1099 rv = asprintf(&tmp_path, "%s/testfile", tmp_dir);
1105 error = clock_getres(CLOCK_REALTIME, &ts_res);
1107 printf("Clock resolution: %ju.%09ju\n", (uintmax_t)ts_res.tv_sec,
1108 (uintmax_t)ts_res.tv_nsec);
1109 printf("test\tloop\ttime\titerations\tperiteration\n");
1111 for (j = 0; j < argc; j++) {
1112 uintmax_t calls, nsecsperit;
1115 for (i = 0; i < tests_count; i++) {
1116 if (strcmp(argv[j], tests[i].t_name) == 0)
1117 the_test = &tests[i];
1120 if (tmp_path != NULL) {
1121 fd = open(tmp_path, O_WRONLY | O_CREAT, 0700);
1123 err(1, "cannot open %s", tmp_path);
1124 error = ftruncate(fd, 1000000);
1126 err(1, "ftruncate");
1134 * Run one warmup, then do the real thing (loops) times.
1136 the_test->t_func(iterations, the_test->t_int, path);
1138 for (k = 0; k < loops; k++) {
1139 calls = the_test->t_func(iterations, the_test->t_int,
1141 timespecsub(&ts_end, &ts_start, &ts_end);
1142 printf("%s\t%ju\t", the_test->t_name, k);
1143 printf("%ju.%09ju\t%ju\t", (uintmax_t)ts_end.tv_sec,
1144 (uintmax_t)ts_end.tv_nsec, calls);
1147 * Note. This assumes that each iteration takes less than
1148 * a second, and that our total nanoseconds doesn't exceed
1149 * the room in our arithmetic unit. Fine for system calls,
1150 * but not for long things.
1152 nsecsperit = ts_end.tv_sec * 1000000000;
1153 nsecsperit += ts_end.tv_nsec;
1154 nsecsperit /= calls;
1155 printf("0.%09ju\n", (uintmax_t)nsecsperit);
1159 if (tmp_path != NULL) {
1160 error = unlink(tmp_path);
1161 if (error != 0 && errno != ENOENT)
1162 warn("cannot unlink %s", tmp_path);
1163 error = rmdir(tmp_dir);
1165 warn("cannot rmdir %s", tmp_dir);