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 } 783