1145519Sdarrenr/*- 2145510Sdarrenr * Copyright (c) 2003-2004, 2010 Robert N. M. Watson 3170268Sdarrenr * All rights reserved. 4255332Scy * 5170268Sdarrenr * Portions of this software were developed at the University of Cambridge 6170268Sdarrenr * Computer Laboratory with support from a grant from Google, Inc. 7170268Sdarrenr * 8145510Sdarrenr * Redistribution and use in source and binary forms, with or without 9145510Sdarrenr * modification, are permitted provided that the following conditions 10145510Sdarrenr * are met: 11145510Sdarrenr * 1. Redistributions of source code must retain the above copyright 12145510Sdarrenr * notice, this list of conditions and the following disclaimer. 13145510Sdarrenr * 2. Redistributions in binary form must reproduce the above copyright 14145510Sdarrenr * notice, this list of conditions and the following disclaimer in the 15145510Sdarrenr * documentation and/or other materials provided with the distribution. 16145510Sdarrenr * 17145510Sdarrenr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18145510Sdarrenr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19145510Sdarrenr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20145510Sdarrenr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21145510Sdarrenr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22145510Sdarrenr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23145510Sdarrenr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24145510Sdarrenr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25145510Sdarrenr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26145510Sdarrenr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27145510Sdarrenr * SUCH DAMAGE. 28145510Sdarrenr * 29145510Sdarrenr * $FreeBSD$ 30145510Sdarrenr */ 31145510Sdarrenr 32145510Sdarrenr#include <sys/types.h> 33145510Sdarrenr#include <sys/mman.h> 34145510Sdarrenr#include <sys/socket.h> 35145510Sdarrenr#include <sys/stat.h> 36145510Sdarrenr#include <sys/time.h> 37145510Sdarrenr#include <sys/wait.h> 38255332Scy 39145510Sdarrenr#include <assert.h> 40145510Sdarrenr#include <err.h> 41145510Sdarrenr#include <fcntl.h> 42145510Sdarrenr#include <inttypes.h> 43170268Sdarrenr#include <limits.h> 44145510Sdarrenr#include <signal.h> 45145510Sdarrenr#include <stdio.h> 46145510Sdarrenr#include <stdlib.h> 47145510Sdarrenr#include <string.h> 48145510Sdarrenr#include <unistd.h> 49145510Sdarrenr 50145510Sdarrenrstatic struct timespec ts_start, ts_end; 51145510Sdarrenrstatic int alarm_timeout; 52255332Scystatic volatile int alarm_fired; 53145510Sdarrenr 54145510Sdarrenr#define timespecsub(vvp, uvp) \ 55145510Sdarrenr do { \ 56170268Sdarrenr (vvp)->tv_sec -= (uvp)->tv_sec; \ 57170268Sdarrenr (vvp)->tv_nsec -= (uvp)->tv_nsec; \ 58255332Scy if ((vvp)->tv_nsec < 0) { \ 59255332Scy (vvp)->tv_sec--; \ 60170268Sdarrenr (vvp)->tv_nsec += 1000000000; \ 61145510Sdarrenr } \ 62145510Sdarrenr } while (0) 63145510Sdarrenr 64145510Sdarrenrstatic void 65145510Sdarrenralarm_handler(int signum) 66255332Scy{ 67145510Sdarrenr 68255332Scy alarm_fired = 1; 69145510Sdarrenr} 70145510Sdarrenr 71255332Scystatic void 72255332Scybenchmark_start(void) 73255332Scy{ 74145510Sdarrenr int error; 75145510Sdarrenr 76255332Scy alarm_fired = 0; 77255332Scy if (alarm_timeout) { 78255332Scy signal(SIGALRM, alarm_handler); 79255332Scy alarm(alarm_timeout); 80255332Scy } 81255332Scy error = clock_gettime(CLOCK_REALTIME, &ts_start); 82255332Scy assert(error == 0); 83255332Scy} 84145510Sdarrenr 85255332Scystatic void 86255332Scybenchmark_stop(void) 87255332Scy{ 88255332Scy int error; 89255332Scy 90145510Sdarrenr error = clock_gettime(CLOCK_REALTIME, &ts_end); 91145510Sdarrenr assert(error == 0); 92145510Sdarrenr} 93145510Sdarrenr 94255332Scyuintmax_t 95255332Scytest_getuid(uintmax_t num, uintmax_t int_arg, const char *path) 96255332Scy{ 97255332Scy uintmax_t i; 98145510Sdarrenr 99145510Sdarrenr /* 100145510Sdarrenr * Thread-local data should require no locking if system 101145510Sdarrenr * call is MPSAFE. 102145510Sdarrenr */ 103145510Sdarrenr benchmark_start(); 104145510Sdarrenr for (i = 0; i < num; i++) { 105145510Sdarrenr if (alarm_fired) 106255332Scy break; 107255332Scy getuid(); 108145510Sdarrenr } 109145510Sdarrenr benchmark_stop(); 110255332Scy return (i); 111255332Scy} 112255332Scy 113255332Scyuintmax_t 114145510Sdarrenrtest_getppid(uintmax_t num, uintmax_t int_arg, const char *path) 115255332Scy{ 116145510Sdarrenr uintmax_t i; 117255332Scy 118255332Scy /* 119145510Sdarrenr * This is process-local, but can change, so will require a 120145510Sdarrenr * lock. 121255332Scy */ 122255332Scy benchmark_start(); 123255332Scy for (i = 0; i < num; i++) { 124255332Scy if (alarm_fired) 125145510Sdarrenr break; 126255332Scy getppid(); 127145510Sdarrenr } 128145510Sdarrenr benchmark_stop(); 129255332Scy return (i); 130255332Scy} 131145510Sdarrenr 132145510Sdarrenruintmax_t 133145510Sdarrenrtest_clock_gettime(uintmax_t num, uintmax_t int_arg, const char *path) 134145510Sdarrenr{ 135255332Scy struct timespec ts; 136255332Scy uintmax_t i; 137255332Scy 138255332Scy benchmark_start(); 139145510Sdarrenr for (i = 0; i < num; i++) { 140255332Scy if (alarm_fired) 141145510Sdarrenr break; 142145510Sdarrenr (void)clock_gettime(CLOCK_REALTIME, &ts); 143255332Scy } 144145510Sdarrenr benchmark_stop(); 145145510Sdarrenr return (i); 146145510Sdarrenr} 147145510Sdarrenr 148145510Sdarrenruintmax_t 149145510Sdarrenrtest_gettimeofday(uintmax_t num, uintmax_t int_arg, const char *path) 150145510Sdarrenr{ 151145510Sdarrenr struct timeval tv; 152145510Sdarrenr uintmax_t i; 153170268Sdarrenr 154145510Sdarrenr benchmark_start(); 155145510Sdarrenr for (i = 0; i < num; i++) { 156145510Sdarrenr if (alarm_fired) 157145510Sdarrenr break; 158145510Sdarrenr (void)gettimeofday(&tv, NULL); 159145510Sdarrenr } 160145510Sdarrenr benchmark_stop(); 161145510Sdarrenr return (i); 162145510Sdarrenr} 163145510Sdarrenr 164255332Scyuintmax_t 165145510Sdarrenrtest_pipe(uintmax_t num, uintmax_t int_arg, const char *path) 166145510Sdarrenr{ 167145510Sdarrenr int fd[2], i; 168145510Sdarrenr 169145510Sdarrenr /* 170145510Sdarrenr * pipe creation is expensive, as it will allocate a new file 171145510Sdarrenr * descriptor, allocate a new pipe, hook it all up, and return. 172145510Sdarrenr * Destroying is also expensive, as we now have to free up 173145510Sdarrenr * the file descriptors and return the pipe. 174145510Sdarrenr */ 175145510Sdarrenr if (pipe(fd) < 0) 176145510Sdarrenr err(-1, "test_pipe: pipe"); 177145510Sdarrenr close(fd[0]); 178145510Sdarrenr close(fd[1]); 179145510Sdarrenr benchmark_start(); 180145510Sdarrenr for (i = 0; i < num; i++) { 181145510Sdarrenr if (alarm_fired) 182145510Sdarrenr break; 183255332Scy if (pipe(fd) == -1) 184255332Scy err(-1, "test_pipe: pipe"); 185145510Sdarrenr close(fd[0]); 186145510Sdarrenr close(fd[1]); 187255332Scy } 188255332Scy benchmark_stop(); 189255332Scy return (i); 190255332Scy} 191255332Scy 192255332Scyuintmax_t 193255332Scytest_socket_stream(uintmax_t num, uintmax_t int_arg, const char *path) 194145510Sdarrenr{ 195145510Sdarrenr uintmax_t i; 196145510Sdarrenr int so; 197145510Sdarrenr 198145510Sdarrenr so = socket(int_arg, SOCK_STREAM, 0); 199145510Sdarrenr if (so < 0) 200145510Sdarrenr err(-1, "test_socket_stream: socket"); 201145510Sdarrenr close(so); 202145510Sdarrenr benchmark_start(); 203145510Sdarrenr for (i = 0; i < num; i++) { 204145510Sdarrenr if (alarm_fired) 205145510Sdarrenr break; 206145510Sdarrenr so = socket(int_arg, SOCK_STREAM, 0); 207145510Sdarrenr if (so == -1) 208145510Sdarrenr err(-1, "test_socket_stream: socket"); 209145510Sdarrenr close(so); 210145510Sdarrenr } 211145510Sdarrenr benchmark_stop(); 212145510Sdarrenr return (i); 213145510Sdarrenr} 214145510Sdarrenr 215145510Sdarrenruintmax_t 216145510Sdarrenrtest_socket_dgram(uintmax_t num, uintmax_t int_arg, const char *path) 217145510Sdarrenr{ 218145510Sdarrenr uintmax_t i; 219145510Sdarrenr int so; 220255332Scy 221145510Sdarrenr so = socket(int_arg, SOCK_DGRAM, 0); 222255332Scy if (so < 0) 223255332Scy err(-1, "test_socket_dgram: socket"); 224145510Sdarrenr close(so); 225145510Sdarrenr benchmark_start(); 226145510Sdarrenr for (i = 0; i < num; i++) { 227145510Sdarrenr if (alarm_fired) 228145510Sdarrenr break; 229255332Scy so = socket(int_arg, SOCK_DGRAM, 0); 230255332Scy if (so == -1) 231255332Scy err(-1, "test_socket_dgram: socket"); 232255332Scy close(so); 233255332Scy } 234255332Scy benchmark_stop(); 235145510Sdarrenr return (i); 236145510Sdarrenr} 237145510Sdarrenr 238145510Sdarrenruintmax_t 239145510Sdarrenrtest_socketpair_stream(uintmax_t num, uintmax_t int_arg, const char *path) 240145510Sdarrenr{ 241145510Sdarrenr uintmax_t i; 242255332Scy int so[2]; 243145510Sdarrenr 244145510Sdarrenr if (socketpair(PF_LOCAL, SOCK_STREAM, 0, so) == -1) 245145510Sdarrenr err(-1, "test_socketpair_stream: socketpair"); 246145510Sdarrenr close(so[0]); 247145510Sdarrenr close(so[1]); 248145510Sdarrenr benchmark_start(); 249145510Sdarrenr for (i = 0; i < num; i++) { 250145510Sdarrenr if (alarm_fired) 251145510Sdarrenr break; 252145510Sdarrenr if (socketpair(PF_LOCAL, SOCK_STREAM, 0, so) == -1) 253145510Sdarrenr err(-1, "test_socketpair_stream: socketpair"); 254145510Sdarrenr close(so[0]); 255145510Sdarrenr close(so[1]); 256145510Sdarrenr } 257255332Scy benchmark_stop(); 258255332Scy return (i); 259255332Scy} 260255332Scy 261255332Scyuintmax_t 262255332Scytest_socketpair_dgram(uintmax_t num, uintmax_t int_arg, const char *path) 263145510Sdarrenr{ 264145510Sdarrenr uintmax_t i; 265145510Sdarrenr int so[2]; 266145510Sdarrenr 267255332Scy if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, so) == -1) 268145510Sdarrenr err(-1, "test_socketpair_dgram: socketpair"); 269145510Sdarrenr close(so[0]); 270255332Scy close(so[1]); 271255332Scy benchmark_start(); 272255332Scy for (i = 0; i < num; i++) { 273145510Sdarrenr if (alarm_fired) 274145510Sdarrenr break; 275145510Sdarrenr if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, so) == -1) 276145510Sdarrenr err(-1, "test_socketpair_dgram: socketpair"); 277255332Scy close(so[0]); 278255332Scy close(so[1]); 279255332Scy } 280255332Scy benchmark_stop(); 281255332Scy return (i); 282255332Scy} 283255332Scy 284255332Scyuintmax_t 285145510Sdarrenrtest_create_unlink(uintmax_t num, uintmax_t int_arg, const char *path) 286255332Scy{ 287255332Scy uintmax_t i; 288255332Scy int fd; 289145510Sdarrenr 290145510Sdarrenr (void)unlink(path); 291145510Sdarrenr fd = open(path, O_RDWR | O_CREAT, 0600); 292255332Scy if (fd < 0) 293145510Sdarrenr err(-1, "test_create_unlink: create: %s", path); 294145510Sdarrenr close(fd); 295145510Sdarrenr if (unlink(path) < 0) 296145510Sdarrenr err(-1, "test_create_unlink: unlink: %s", path); 297145510Sdarrenr benchmark_start(); 298145510Sdarrenr for (i = 0; i < num; i++) { 299255332Scy if (alarm_fired) 300255332Scy break; 301145510Sdarrenr fd = open(path, O_RDWR | O_CREAT, 0600); 302145510Sdarrenr if (fd < 0) 303255332Scy err(-1, "test_create_unlink: create: %s", path); 304255332Scy close(fd); 305255332Scy if (unlink(path) < 0) 306255332Scy err(-1, "test_create_unlink: unlink: %s", path); 307255332Scy } 308255332Scy benchmark_stop(); 309145510Sdarrenr return (i); 310145510Sdarrenr} 311145510Sdarrenr 312145510Sdarrenruintmax_t 313255332Scytest_open_close(uintmax_t num, uintmax_t int_arg, const char *path) 314255332Scy{ 315255332Scy uintmax_t i; 316255332Scy int fd; 317255332Scy 318255332Scy fd = open(path, O_RDONLY); 319255332Scy if (fd < 0) 320255332Scy err(-1, "test_open_close: %s", path); 321255332Scy close(fd); 322255332Scy 323255332Scy benchmark_start(); 324255332Scy for (i = 0; i < num; i++) { 325255332Scy if (alarm_fired) 326255332Scy break; 327255332Scy fd = open(path, O_RDONLY); 328255332Scy if (fd < 0) 329255332Scy err(-1, "test_open_close: %s", path); 330145510Sdarrenr close(fd); 331145510Sdarrenr } 332255332Scy benchmark_stop(); 333145510Sdarrenr return (i); 334145510Sdarrenr} 335145510Sdarrenr 336145510Sdarrenruintmax_t 337145510Sdarrenrtest_read(uintmax_t num, uintmax_t int_arg, const char *path) 338255332Scy{ 339255332Scy char buf[int_arg]; 340255332Scy uintmax_t i; 341255332Scy int fd; 342255332Scy 343255332Scy fd = open(path, O_RDONLY); 344255332Scy if (fd < 0) 345255332Scy err(-1, "test_open_read: %s", path); 346255332Scy (void)pread(fd, buf, int_arg, 0); 347255332Scy 348255332Scy benchmark_start(); 349255332Scy for (i = 0; i < num; i++) { 350255332Scy if (alarm_fired) 351145510Sdarrenr break; 352145510Sdarrenr (void)pread(fd, buf, int_arg, 0); 353145510Sdarrenr } 354255332Scy benchmark_stop(); 355255332Scy close(fd); 356255332Scy return (i); 357255332Scy} 358145510Sdarrenr 359255332Scyuintmax_t 360255332Scytest_open_read_close(uintmax_t num, uintmax_t int_arg, const char *path) 361255332Scy{ 362255332Scy char buf[int_arg]; 363255332Scy uintmax_t i; 364255332Scy int fd; 365255332Scy 366255332Scy fd = open(path, O_RDONLY); 367255332Scy if (fd < 0) 368255332Scy err(-1, "test_open_read_close: %s", path); 369255332Scy (void)read(fd, buf, int_arg); 370145510Sdarrenr close(fd); 371145510Sdarrenr 372145510Sdarrenr benchmark_start(); 373255332Scy for (i = 0; i < num; i++) { 374255332Scy if (alarm_fired) 375255332Scy break; 376255332Scy fd = open(path, O_RDONLY); 377255332Scy if (fd < 0) 378255332Scy err(-1, "test_open_read_close: %s", path); 379255332Scy (void)read(fd, buf, int_arg); 380255332Scy close(fd); 381255332Scy } 382255332Scy benchmark_stop(); 383255332Scy return (i); 384255332Scy} 385255332Scy 386255332Scyuintmax_t 387255332Scytest_dup(uintmax_t num, uintmax_t int_arg, const char *path) 388145510Sdarrenr{ 389145510Sdarrenr int fd, i, shmfd; 390255332Scy 391255332Scy shmfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600); 392255332Scy if (shmfd < 0) 393255332Scy err(-1, "test_dup: shm_open"); 394255332Scy fd = dup(shmfd); 395255332Scy if (fd >= 0) 396255332Scy close(fd); 397255332Scy benchmark_start(); 398255332Scy for (i = 0; i < num; i++) { 399255332Scy if (alarm_fired) 400255332Scy break; 401255332Scy fd = dup(shmfd); 402255332Scy if (fd >= 0) 403255332Scy close(fd); 404255332Scy } 405255332Scy benchmark_stop(); 406255332Scy close(shmfd); 407145510Sdarrenr return (i); 408145510Sdarrenr} 409255332Scy 410145510Sdarrenruintmax_t 411145510Sdarrenrtest_shmfd(uintmax_t num, uintmax_t int_arg, const char *path) 412255332Scy{ 413145510Sdarrenr uintmax_t i; 414145510Sdarrenr int shmfd; 415145510Sdarrenr 416145510Sdarrenr shmfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600); 417145510Sdarrenr if (shmfd < 0) 418145510Sdarrenr err(-1, "test_shmfd: shm_open"); 419145510Sdarrenr close(shmfd); 420145510Sdarrenr benchmark_start(); 421145510Sdarrenr for (i = 0; i < num; i++) { 422145510Sdarrenr if (alarm_fired) 423145510Sdarrenr break; 424255332Scy shmfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600); 425255332Scy if (shmfd < 0) 426255332Scy err(-1, "test_shmfd: shm_open"); 427255332Scy close(shmfd); 428255332Scy } 429255332Scy benchmark_stop(); 430255332Scy return (i); 431255332Scy} 432255332Scy 433255332Scyuintmax_t 434255332Scytest_fstat_shmfd(uintmax_t num, uintmax_t int_arg, const char *path) 435255332Scy{ 436255332Scy struct stat sb; 437255332Scy uintmax_t i; 438255332Scy int shmfd; 439255332Scy 440255332Scy shmfd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600); 441255332Scy if (shmfd < 0) 442255332Scy err(-1, "test_fstat_shmfd: shm_open"); 443255332Scy if (fstat(shmfd, &sb) < 0) 444255332Scy err(-1, "test_fstat_shmfd: fstat"); 445255332Scy benchmark_start(); 446255332Scy for (i = 0; i < num; i++) { 447255332Scy if (alarm_fired) 448255332Scy break; 449255332Scy (void)fstat(shmfd, &sb); 450255332Scy } 451255332Scy benchmark_stop(); 452255332Scy close(shmfd); 453255332Scy return (i); 454255332Scy} 455255332Scy 456255332Scyuintmax_t 457255332Scytest_fork(uintmax_t num, uintmax_t int_arg, const char *path) 458255332Scy{ 459255332Scy pid_t pid; 460255332Scy uintmax_t i; 461255332Scy 462255332Scy pid = fork(); 463255332Scy if (pid < 0) 464255332Scy err(-1, "test_fork: fork"); 465255332Scy if (pid == 0) 466255332Scy _exit(0); 467255332Scy if (waitpid(pid, NULL, 0) < 0) 468255332Scy err(-1, "test_fork: waitpid"); 469255332Scy benchmark_start(); 470255332Scy for (i = 0; i < num; i++) { 471255332Scy if (alarm_fired) 472255332Scy break; 473255332Scy pid = fork(); 474255332Scy if (pid < 0) 475255332Scy err(-1, "test_fork: fork"); 476255332Scy if (pid == 0) 477255332Scy _exit(0); 478255332Scy if (waitpid(pid, NULL, 0) < 0) 479255332Scy err(-1, "test_fork: waitpid"); 480255332Scy } 481255332Scy benchmark_stop(); 482255332Scy return (i); 483255332Scy} 484255332Scy 485255332Scyuintmax_t 486255332Scytest_vfork(uintmax_t num, uintmax_t int_arg, const char *path) 487255332Scy{ 488255332Scy pid_t pid; 489255332Scy uintmax_t i; 490255332Scy 491255332Scy pid = vfork(); 492255332Scy if (pid < 0) 493255332Scy err(-1, "test_vfork: vfork"); 494255332Scy if (pid == 0) 495255332Scy _exit(0); 496255332Scy if (waitpid(pid, NULL, 0) < 0) 497255332Scy err(-1, "test_vfork: waitpid"); 498255332Scy benchmark_start(); 499255332Scy for (i = 0; i < num; i++) { 500255332Scy if (alarm_fired) 501255332Scy break; 502255332Scy pid = vfork(); 503255332Scy if (pid < 0) 504255332Scy err(-1, "test_vfork: vfork"); 505255332Scy if (pid == 0) 506255332Scy _exit(0); 507255332Scy if (waitpid(pid, NULL, 0) < 0) 508255332Scy err(-1, "test_vfork: waitpid"); 509255332Scy } 510255332Scy benchmark_stop(); 511255332Scy return (i); 512255332Scy} 513255332Scy 514255332Scy#define USR_BIN_TRUE "/usr/bin/true" 515255332Scystatic char *execve_args[] = { USR_BIN_TRUE, NULL}; 516255332Scyextern char **environ; 517255332Scy 518255332Scyuintmax_t 519255332Scytest_fork_exec(uintmax_t num, uintmax_t int_arg, const char *path) 520255332Scy{ 521255332Scy pid_t pid; 522255332Scy uintmax_t i; 523255332Scy 524255332Scy pid = fork(); 525255332Scy if (pid < 0) 526255332Scy err(-1, "test_fork_exec: fork"); 527255332Scy if (pid == 0) { 528255332Scy (void)execve(USR_BIN_TRUE, execve_args, environ); 529255332Scy err(-1, "execve"); 530255332Scy } 531255332Scy if (waitpid(pid, NULL, 0) < 0) 532255332Scy err(-1, "test_fork: waitpid"); 533255332Scy benchmark_start(); 534255332Scy for (i = 0; i < num; i++) { 535255332Scy if (alarm_fired) 536255332Scy break; 537255332Scy pid = fork(); 538255332Scy if (pid < 0) 539255332Scy err(-1, "test_fork_exec: fork"); 540255332Scy if (pid == 0) { 541255332Scy (void)execve(USR_BIN_TRUE, execve_args, environ); 542255332Scy err(-1, "test_fork_exec: execve"); 543255332Scy } 544255332Scy if (waitpid(pid, NULL, 0) < 0) 545255332Scy err(-1, "test_fork_exec: waitpid"); 546255332Scy } 547255332Scy benchmark_stop(); 548255332Scy return (i); 549255332Scy} 550255332Scy 551255332Scyuintmax_t 552255332Scytest_vfork_exec(uintmax_t num, uintmax_t int_arg, const char *path) 553255332Scy{ 554255332Scy pid_t pid; 555255332Scy uintmax_t i; 556255332Scy 557255332Scy pid = vfork(); 558255332Scy if (pid < 0) 559255332Scy err(-1, "test_vfork_exec: vfork"); 560255332Scy if (pid == 0) { 561255332Scy (void)execve(USR_BIN_TRUE, execve_args, environ); 562255332Scy err(-1, "test_vfork_exec: execve"); 563255332Scy } 564255332Scy if (waitpid(pid, NULL, 0) < 0) 565255332Scy err(-1, "test_vfork_exec: waitpid"); 566145510Sdarrenr benchmark_start(); 567145510Sdarrenr for (i = 0; i < num; i++) { 568255332Scy if (alarm_fired) 569255332Scy break; 570255332Scy pid = vfork(); 571255332Scy if (pid < 0) 572255332Scy err(-1, "test_vfork_exec: vfork"); 573255332Scy if (pid == 0) { 574255332Scy (void)execve(USR_BIN_TRUE, execve_args, environ); 575255332Scy err(-1, "execve"); 576255332Scy } 577255332Scy if (waitpid(pid, NULL, 0) < 0) 578255332Scy err(-1, "test_vfork_exec: waitpid"); 579255332Scy } 580255332Scy benchmark_stop(); 581255332Scy return (i); 582255332Scy} 583255332Scy 584255332Scyuintmax_t 585255332Scytest_chroot(uintmax_t num, uintmax_t int_arg, const char *path) 586255332Scy{ 587255332Scy uintmax_t i; 588255332Scy 589255332Scy if (chroot("/") < 0) 590255332Scy err(-1, "test_chroot: chroot"); 591255332Scy benchmark_start(); 592255332Scy for (i = 0; i < num; i++) { 593255332Scy if (alarm_fired) 594255332Scy break; 595255332Scy if (chroot("/") < 0) 596255332Scy err(-1, "test_chroot: chroot"); 597255332Scy } 598145510Sdarrenr benchmark_stop(); 599145510Sdarrenr return (i); 600145510Sdarrenr} 601145510Sdarrenr 602145510Sdarrenruintmax_t 603145510Sdarrenrtest_setuid(uintmax_t num, uintmax_t int_arg, const char *path) 604145510Sdarrenr{ 605145510Sdarrenr uid_t uid; 606145510Sdarrenr uintmax_t i; 607145510Sdarrenr 608145510Sdarrenr uid = getuid(); 609145510Sdarrenr if (setuid(uid) < 0) 610145510Sdarrenr err(-1, "test_setuid: setuid"); 611145510Sdarrenr benchmark_start(); 612145510Sdarrenr for (i = 0; i < num; i++) { 613145510Sdarrenr if (alarm_fired) 614145510Sdarrenr break; 615145510Sdarrenr if (setuid(uid) < 0) 616145510Sdarrenr err(-1, "test_setuid: setuid"); 617145510Sdarrenr } 618145510Sdarrenr benchmark_stop(); 619145510Sdarrenr return (i); 620145510Sdarrenr} 621145510Sdarrenr 622145510Sdarrenrstruct test { 623145510Sdarrenr const char *t_name; 624145510Sdarrenr uintmax_t (*t_func)(uintmax_t, uintmax_t, const char *); 625145510Sdarrenr int t_flags; 626145510Sdarrenr uintmax_t t_int; 627145510Sdarrenr}; 628145510Sdarrenr 629145510Sdarrenr#define FLAG_PATH 0x00000001 630145510Sdarrenr 631145510Sdarrenrstatic const struct test tests[] = { 632145510Sdarrenr { "getuid", test_getuid }, 633145510Sdarrenr { "getppid", test_getppid }, 634145510Sdarrenr { "clock_gettime", test_clock_gettime }, 635145510Sdarrenr { "gettimeofday", test_gettimeofday }, 636145510Sdarrenr { "pipe", test_pipe }, 637145510Sdarrenr { "socket_local_stream", test_socket_stream, .t_int = PF_LOCAL }, 638145510Sdarrenr { "socket_local_dgram", test_socket_dgram, .t_int = PF_LOCAL }, 639145510Sdarrenr { "socketpair_stream", test_socketpair_stream }, 640145510Sdarrenr { "socketpair_dgram", test_socketpair_dgram }, 641145510Sdarrenr { "socket_tcp", test_socket_stream, .t_int = PF_INET }, 642145510Sdarrenr { "socket_udp", test_socket_dgram, .t_int = PF_INET }, 643145510Sdarrenr { "create_unlink", test_create_unlink, .t_flags = FLAG_PATH }, 644145510Sdarrenr { "open_close", test_open_close, .t_flags = FLAG_PATH }, 645145510Sdarrenr { "open_read_close_1", test_open_read_close, .t_flags = FLAG_PATH, 646145510Sdarrenr .t_int = 1 }, 647145510Sdarrenr { "open_read_close_10", test_open_read_close, .t_flags = FLAG_PATH, 648145510Sdarrenr .t_int = 10 }, 649145510Sdarrenr { "open_read_close_100", test_open_read_close, .t_flags = FLAG_PATH, 650145510Sdarrenr .t_int = 100 }, 651145510Sdarrenr { "open_read_close_1000", test_open_read_close, .t_flags = FLAG_PATH, 652145510Sdarrenr .t_int = 1000 }, 653145510Sdarrenr { "open_read_close_10000", test_open_read_close, 654145510Sdarrenr .t_flags = FLAG_PATH, .t_int = 10000 }, 655145510Sdarrenr { "open_read_close_100000", test_open_read_close, 656145510Sdarrenr .t_flags = FLAG_PATH, .t_int = 100000 }, 657145510Sdarrenr { "open_read_close_1000000", test_open_read_close, 658145510Sdarrenr .t_flags = FLAG_PATH, .t_int = 1000000 }, 659145510Sdarrenr { "read_1", test_read, .t_flags = FLAG_PATH, .t_int = 1 }, 660145510Sdarrenr { "read_10", test_read, .t_flags = FLAG_PATH, .t_int = 10 }, 661145510Sdarrenr { "read_100", test_read, .t_flags = FLAG_PATH, .t_int = 100 }, 662145510Sdarrenr { "read_1000", test_read, .t_flags = FLAG_PATH, .t_int = 1000 }, 663145510Sdarrenr { "read_10000", test_read, .t_flags = FLAG_PATH, .t_int = 10000 }, 664145510Sdarrenr { "read_100000", test_read, .t_flags = FLAG_PATH, .t_int = 100000 }, 665170268Sdarrenr { "read_1000000", test_read, .t_flags = FLAG_PATH, .t_int = 1000000 }, 666170268Sdarrenr { "dup", test_dup }, 667170268Sdarrenr { "shmfd", test_shmfd }, 668170268Sdarrenr { "fstat_shmfd", test_fstat_shmfd }, 669170268Sdarrenr { "fork", test_fork }, 670170268Sdarrenr { "vfork", test_vfork }, 671170268Sdarrenr { "fork_exec", test_fork_exec }, 672170268Sdarrenr { "vfork_exec", test_vfork_exec }, 673170268Sdarrenr { "chroot", test_chroot }, 674170268Sdarrenr { "setuid", test_setuid }, 675170268Sdarrenr}; 676170268Sdarrenrstatic const int tests_count = sizeof(tests) / sizeof(tests[0]); 677170268Sdarrenr 678170268Sdarrenrstatic void 679170268Sdarrenrusage(void) 680170268Sdarrenr{ 681170268Sdarrenr int i; 682170268Sdarrenr 683255332Scy fprintf(stderr, "syscall_timing [-i iterations] [-l loops] " 684170268Sdarrenr "[-p path] [-s seconds] test\n"); 685255332Scy for (i = 0; i < tests_count; i++) 686170268Sdarrenr fprintf(stderr, " %s\n", tests[i].t_name); 687170268Sdarrenr exit(-1); 688170268Sdarrenr} 689170268Sdarrenr 690170268Sdarrenrint 691170268Sdarrenrmain(int argc, char *argv[]) 692170268Sdarrenr{ 693170268Sdarrenr struct timespec ts_res; 694170268Sdarrenr const struct test *the_test; 695170268Sdarrenr const char *path; 696255332Scy long long ll; 697255332Scy char *endp; 698255332Scy int ch, error, i, j, k; 699170268Sdarrenr uintmax_t iterations, loops; 700170268Sdarrenr 701170268Sdarrenr alarm_timeout = 1; 702170268Sdarrenr iterations = 0; 703170268Sdarrenr loops = 10; 704170268Sdarrenr path = NULL; 705170268Sdarrenr while ((ch = getopt(argc, argv, "i:l:p:s:")) != -1) { 706170268Sdarrenr switch (ch) { 707170268Sdarrenr case 'i': 708170268Sdarrenr ll = strtol(optarg, &endp, 10); 709170268Sdarrenr if (*endp != 0 || ll < 1 || ll > 100000) 710170268Sdarrenr usage(); 711170268Sdarrenr iterations = ll; 712170268Sdarrenr break; 713170268Sdarrenr 714170268Sdarrenr case 'l': 715170268Sdarrenr ll = strtol(optarg, &endp, 10); 716170268Sdarrenr if (*endp != 0 || ll < 1 || ll > 100000) 717170268Sdarrenr usage(); 718170268Sdarrenr loops = ll; 719170268Sdarrenr break; 720170268Sdarrenr 721170268Sdarrenr case 'p': 722170268Sdarrenr path = optarg; 723170268Sdarrenr break; 724170268Sdarrenr 725170268Sdarrenr case 's': 726170268Sdarrenr ll = strtol(optarg, &endp, 10); 727170268Sdarrenr if (*endp != 0 || ll < 1 || ll > 60*60) 728170268Sdarrenr usage(); 729255332Scy alarm_timeout = ll; 730170268Sdarrenr break; 731255332Scy 732170268Sdarrenr case '?': 733170268Sdarrenr default: 734170268Sdarrenr usage(); 735170268Sdarrenr } 736170268Sdarrenr } 737170268Sdarrenr argc -= optind; 738170268Sdarrenr argv += optind; 739170268Sdarrenr 740170268Sdarrenr if (iterations < 1 && alarm_timeout < 1) 741255332Scy usage(); 742170268Sdarrenr if (iterations < 1) 743255332Scy iterations = UINT64_MAX; 744255332Scy if (loops < 1) 745255332Scy loops = 1; 746255332Scy 747255332Scy if (argc < 1) 748255332Scy usage(); 749255332Scy 750255332Scy /* 751255332Scy * Validate test list and that, if a path is required, it is 752170268Sdarrenr * defined. 753255332Scy */ 754170268Sdarrenr for (j = 0; j < argc; j++) { 755170268Sdarrenr the_test = NULL; 756170268Sdarrenr for (i = 0; i < tests_count; i++) { 757170268Sdarrenr if (strcmp(argv[j], tests[i].t_name) == 0) 758170268Sdarrenr the_test = &tests[i]; 759170268Sdarrenr } 760170268Sdarrenr if (the_test == NULL) 761170268Sdarrenr usage(); 762170268Sdarrenr if ((the_test->t_flags & FLAG_PATH) && (path == NULL)) { 763170268Sdarrenr errx(-1, "%s requires -p", the_test->t_name); 764170268Sdarrenr } 765170268Sdarrenr } 766255332Scy 767255332Scy error = clock_getres(CLOCK_REALTIME, &ts_res); 768255332Scy assert(error == 0); 769255332Scy printf("Clock resolution: %ju.%09ju\n", (uintmax_t)ts_res.tv_sec, 770255332Scy (uintmax_t)ts_res.tv_nsec); 771255332Scy printf("test\tloop\ttime\titerations\tperiteration\n"); 772255332Scy 773255332Scy for (j = 0; j < argc; j++) { 774255332Scy uintmax_t calls, nsecsperit; 775255332Scy 776255332Scy the_test = NULL; 777255332Scy for (i = 0; i < tests_count; i++) { 778255332Scy if (strcmp(argv[j], tests[i].t_name) == 0) 779255332Scy the_test = &tests[i]; 780255332Scy } 781255332Scy 782255332Scy /* 783255332Scy * Run one warmup, then do the real thing (loops) times. 784255332Scy */ 785255332Scy the_test->t_func(iterations, the_test->t_int, path); 786255332Scy calls = 0; 787255332Scy for (k = 0; k < loops; k++) { 788255332Scy calls = the_test->t_func(iterations, the_test->t_int, 789255332Scy path); 790255332Scy timespecsub(&ts_end, &ts_start); 791255332Scy printf("%s\t%d\t", the_test->t_name, k); 792255332Scy printf("%ju.%09ju\t%ju\t", (uintmax_t)ts_end.tv_sec, 793255332Scy (uintmax_t)ts_end.tv_nsec, calls); 794255332Scy 795255332Scy /* 796255332Scy * Note. This assumes that each iteration takes less than 797255332Scy * a second, and that our total nanoseconds doesn't exceed 798255332Scy * the room in our arithmetic unit. Fine for system calls, 799255332Scy * but not for long things. 800255332Scy */ 801255332Scy nsecsperit = ts_end.tv_sec * 1000000000; 802255332Scy nsecsperit += ts_end.tv_nsec; 803255332Scy nsecsperit /= calls; 804255332Scy printf("0.%09ju\n", (uintmax_t)nsecsperit); 805255332Scy } 806255332Scy } 807255332Scy return (0); 808255332Scy} 809255332Scy