1153790Srwatson/*- 2153790Srwatson * Copyright (c) 2005 Robert N. M. Watson 3153790Srwatson * All rights reserved. 4153790Srwatson * 5153790Srwatson * Redistribution and use in source and binary forms, with or without 6153790Srwatson * modification, are permitted provided that the following conditions 7153790Srwatson * are met: 8153790Srwatson * 1. Redistributions of source code must retain the above copyright 9153790Srwatson * notice, this list of conditions and the following disclaimer. 10153790Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11153790Srwatson * notice, this list of conditions and the following disclaimer in the 12153790Srwatson * documentation and/or other materials provided with the distribution. 13153790Srwatson * 14153790Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15153790Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16153790Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17153790Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18153790Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19153790Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20153790Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21153790Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22153790Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23153790Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24153790Srwatson * SUCH DAMAGE. 25153790Srwatson * 26153790Srwatson * $FreeBSD$ 27153790Srwatson */ 28153790Srwatson 29153790Srwatson#include <sys/types.h> 30153790Srwatson#include <sys/socket.h> 31213574Spluknet#include <sys/stdint.h> 32153790Srwatson#include <sys/time.h> 33153790Srwatson#include <sys/utsname.h> 34153790Srwatson#include <sys/wait.h> 35153790Srwatson 36153790Srwatson#include <netinet/in.h> 37153790Srwatson 38153790Srwatson#include <err.h> 39153790Srwatson#include <errno.h> 40153790Srwatson#include <pthread.h> 41153790Srwatson#include <signal.h> 42153790Srwatson#include <stdio.h> 43153790Srwatson#include <stdlib.h> 44153790Srwatson#include <string.h> 45153790Srwatson#include <unistd.h> 46153790Srwatson 47153790Srwatson/* 48153790Srwatson * juggle is a simple IPC/context switch performance test, which works on 49153790Srwatson * pairs of file descriptors of various types. In various runs, it considers 50153790Srwatson * the cost of bouncing a message synchronously across the descriptor pair, 51153790Srwatson * either in the same thread, two different threads, or two different 52153790Srwatson * processes. Timing measurements for each series of I/O's are reported, but 53153790Srwatson * the first measurement in each series discarded as "warmup" on the IPC 54153790Srwatson * primitive. Variations on the test permit for pipelining, or the insertion 55153790Srwatson * of more than one packet into the stream at a time, intended to permit 56153790Srwatson * greater parallelism, hopefully allowing performance numbers to reflect 57153790Srwatson * use of available parallelism, and/or intelligence in context switching to 58153790Srwatson * avoid premature switching when multiple messages are queued. 59153790Srwatson */ 60153790Srwatson 61153790Srwatson/* 62153790Srwatson * The UDP test uses UDP over the loopback interface. Two arbitrary but 63153790Srwatson * fixed port numbers. 64153790Srwatson */ 65153790Srwatson#define UDP_PORT1 2020 66153790Srwatson#define UDP_PORT2 2021 67153790Srwatson 68153790Srwatson/* 69153790Srwatson * Size of each message. Must be smaller than the socket buffer or pipe 70153790Srwatson * buffer maximum size, as we want to send it atomically without blocking. 71153790Srwatson * If pipelining is in use, must be able to fit PIPELINE_MAX of these 72153790Srwatson * messages into the send queue. 73153790Srwatson */ 74153790Srwatson#define MESSAGELEN 128 75153790Srwatson 76153790Srwatson/* 77153790Srwatson * Number of message cycles -- into fd1, out of fd2, into fd2, and out of 78153790Srwatson * fd1. By counting in cycles, we allow the master thread or process to 79153790Srwatson * perform timing without explicitly synchronizing with the secondary thread 80153790Srwatson * or process. 81153790Srwatson */ 82153790Srwatson#define NUMCYCLES 1024 83153790Srwatson 84153790Srwatson/* 85153790Srwatson * Number of times to run each test. 86153790Srwatson */ 87153790Srwatson#define LOOPS 10 88153790Srwatson 89153790Srwatson/* 90153790Srwatson * Number of in-flight messages per cycle. I adjusting this value, be 91153790Srwatson * careful not to exceed the socket/etc buffer depth, or messages may be lost 92153790Srwatson * or result in blocking. 93153790Srwatson */ 94153790Srwatson#define PIPELINE_MAX 4 95153790Srwatson 96153790Srwatson/* 97153790Srwatson * As in all programs, steal timespecsub() from time.h. 98153790Srwatson */ 99153790Srwatson#define timespecsub(vvp, uvp) \ 100153790Srwatson do { \ 101153790Srwatson (vvp)->tv_sec -= (uvp)->tv_sec; \ 102153790Srwatson (vvp)->tv_nsec -= (uvp)->tv_nsec; \ 103153790Srwatson if ((vvp)->tv_nsec < 0) { \ 104153790Srwatson (vvp)->tv_sec--; \ 105153790Srwatson (vvp)->tv_nsec += 1000000000; \ 106153790Srwatson } \ 107153790Srwatson } while (0) 108153790Srwatson 109153790Srwatsonstatic int 110153790Srwatsonudp_create(int *fd1p, int *fd2p) 111153790Srwatson{ 112153790Srwatson struct sockaddr_in sin1, sin2; 113153790Srwatson int sock1, sock2; 114153790Srwatson 115153790Srwatson sock1 = socket(PF_INET, SOCK_DGRAM, 0); 116153790Srwatson if (sock1 == -1) 117153790Srwatson return (-1); 118153790Srwatson 119153790Srwatson sock2 = socket(PF_INET, SOCK_DGRAM, 0); 120153790Srwatson if (sock2 == -1) { 121153790Srwatson close(sock1); 122153790Srwatson return (-1); 123153790Srwatson } 124153790Srwatson 125153790Srwatson bzero(&sin1, sizeof(sin1)); 126153790Srwatson sin1.sin_len = sizeof(sin1); 127153790Srwatson sin1.sin_family = AF_INET; 128153790Srwatson sin1.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 129153790Srwatson sin1.sin_port = htons(UDP_PORT1); 130153790Srwatson 131153790Srwatson bzero(&sin2, sizeof(sin2)); 132153790Srwatson sin2.sin_len = sizeof(sin2); 133153790Srwatson sin2.sin_family = AF_INET; 134153790Srwatson sin2.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 135153790Srwatson sin2.sin_port = htons(UDP_PORT2); 136153790Srwatson 137153790Srwatson if (bind(sock1, (struct sockaddr *) &sin1, sizeof(sin1)) < 0) { 138153790Srwatson close(sock1); 139153790Srwatson close(sock2); 140153790Srwatson return (-1); 141153790Srwatson } 142153790Srwatson 143153790Srwatson if (bind(sock2, (struct sockaddr *) &sin2, sizeof(sin2)) < 0) { 144153790Srwatson close(sock1); 145153790Srwatson close(sock2); 146153790Srwatson return (-1); 147153790Srwatson } 148153790Srwatson 149153790Srwatson if (connect(sock1, (struct sockaddr *) &sin2, sizeof(sin2)) < 0) { 150153790Srwatson close(sock1); 151153790Srwatson close(sock2); 152153790Srwatson return (-1); 153153790Srwatson } 154153790Srwatson 155153790Srwatson if (connect(sock2, (struct sockaddr *) &sin1, sizeof(sin1)) < 0) { 156153790Srwatson close(sock1); 157153790Srwatson close(sock2); 158153790Srwatson return (-1); 159153790Srwatson } 160153790Srwatson 161153790Srwatson *fd1p = sock1; 162153790Srwatson *fd2p = sock2; 163153790Srwatson 164153790Srwatson return (0); 165153790Srwatson} 166153790Srwatson 167153790Srwatsonstatic int 168153790Srwatsonpipe_create(int *fd1p, int *fd2p) 169153790Srwatson{ 170153790Srwatson int fds[2]; 171153790Srwatson 172153790Srwatson if (pipe(fds) < 0) 173153790Srwatson return (-1); 174153790Srwatson 175153790Srwatson *fd1p = fds[0]; 176153790Srwatson *fd2p = fds[1]; 177153790Srwatson 178153790Srwatson return (0); 179153790Srwatson} 180153790Srwatson 181153790Srwatsonstatic int 182153790Srwatsonsocketpairdgram_create(int *fd1p, int *fd2p) 183153790Srwatson{ 184153790Srwatson int fds[2]; 185153790Srwatson 186153790Srwatson if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, fds) < 0) 187153790Srwatson return (-1); 188153790Srwatson 189153790Srwatson *fd1p = fds[0]; 190153790Srwatson *fd2p = fds[1]; 191153790Srwatson 192153790Srwatson return (0); 193153790Srwatson} 194153790Srwatson 195153790Srwatsonstatic int 196153790Srwatsonsocketpairstream_create(int *fd1p, int *fd2p) 197153790Srwatson{ 198153790Srwatson int fds[2]; 199153790Srwatson 200153790Srwatson if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) 201153790Srwatson return (-1); 202153790Srwatson 203153790Srwatson *fd1p = fds[0]; 204153790Srwatson *fd2p = fds[1]; 205153790Srwatson 206153790Srwatson return (0); 207153790Srwatson} 208153790Srwatson 209153790Srwatsonstatic int 210153790Srwatsonmessage_send(int s) 211153790Srwatson{ 212153790Srwatson u_char buffer[MESSAGELEN]; 213153790Srwatson ssize_t len; 214153790Srwatson 215153790Srwatson bzero(buffer, sizeof(buffer)); 216153790Srwatson 217153790Srwatson len = write(s, buffer, sizeof(buffer)); 218153790Srwatson if (len == -1) 219153790Srwatson return (-1); 220153790Srwatson if (len != sizeof(buffer)) { 221153790Srwatson errno = EMSGSIZE; 222153790Srwatson return (-1); 223153790Srwatson } 224153790Srwatson return (0); 225153790Srwatson} 226153790Srwatson 227153790Srwatsonstatic int 228153790Srwatsonmessage_recv(int s) 229153790Srwatson{ 230153790Srwatson u_char buffer[MESSAGELEN]; 231153790Srwatson ssize_t len; 232153790Srwatson 233153790Srwatson len = read(s, buffer, sizeof(buffer)); 234153790Srwatson if (len == -1) 235153790Srwatson return (-1); 236153790Srwatson if (len != sizeof(buffer)) { 237153790Srwatson errno = EMSGSIZE; 238153790Srwatson return (-1); 239153790Srwatson } 240153790Srwatson return (0); 241153790Srwatson} 242153790Srwatson 243153790Srwatson/* 244153790Srwatson * Juggle messages between two file descriptors in a single thread/process, 245153790Srwatson * so simply a measure of IPC performance. 246153790Srwatson */ 247153790Srwatsonstatic struct timespec 248153790Srwatsonjuggle(int fd1, int fd2, int pipeline) 249153790Srwatson{ 250153790Srwatson struct timespec tstart, tfinish; 251153790Srwatson int i, j; 252153790Srwatson 253153790Srwatson if (clock_gettime(CLOCK_REALTIME, &tstart) < 0) 254153790Srwatson err(-1, "juggle: clock_gettime"); 255153790Srwatson 256153790Srwatson for (i = 0; i < NUMCYCLES; i++) { 257153790Srwatson 258153790Srwatson for (j = 0; j < pipeline; j++) { 259153790Srwatson if (message_send(fd1) < 0) 260153790Srwatson err(-1, "message_send fd1"); 261153790Srwatson } 262153790Srwatson 263153790Srwatson for (j = 0; j < pipeline; j++) { 264153790Srwatson if (message_recv(fd2) < 0) 265153790Srwatson err(-1, "message_recv fd2"); 266153790Srwatson 267153790Srwatson if (message_send(fd2) < 0) 268153790Srwatson err(-1, "message_send fd2"); 269153790Srwatson } 270153790Srwatson 271153790Srwatson for (j = 0; j < pipeline; j++) { 272153790Srwatson if (message_recv(fd1) < 0) 273153790Srwatson err(-1, "message_recv fd1"); 274153790Srwatson } 275153790Srwatson } 276153790Srwatson 277153790Srwatson if (clock_gettime(CLOCK_REALTIME, &tfinish) < 0) 278153790Srwatson err(-1, "juggle: clock_gettime"); 279153790Srwatson 280153790Srwatson timespecsub(&tfinish, &tstart); 281153790Srwatson 282153790Srwatson return (tfinish); 283153790Srwatson} 284153790Srwatson 285153790Srwatson/* 286153790Srwatson * Juggle messages between two file descriptors in two threads, so measure 287153790Srwatson * the cost of IPC and the cost of a thread context switch. 288153790Srwatson * 289153790Srwatson * In order to avoid measuring thread creation time, we make use of a 290153790Srwatson * condition variable to decide when both threads are ready to begin 291153790Srwatson * juggling. 292153790Srwatson */ 293153790Srwatsonstatic int threaded_child_ready; 294153790Srwatsonstatic pthread_mutex_t threaded_mtx; 295153790Srwatsonstatic pthread_cond_t threaded_cond; 296153790Srwatsonstatic int threaded_pipeline; 297153790Srwatson 298153790Srwatsonstatic void * 299153790Srwatsonjuggling_thread(void *arg) 300153790Srwatson{ 301153790Srwatson int fd2, i, j; 302153790Srwatson 303153790Srwatson fd2 = *(int *)arg; 304153790Srwatson 305203800Sru if (pthread_mutex_lock(&threaded_mtx) != 0) 306153790Srwatson err(-1, "juggling_thread: pthread_mutex_lock"); 307153790Srwatson 308153790Srwatson threaded_child_ready = 1; 309153790Srwatson 310203800Sru if (pthread_cond_signal(&threaded_cond) != 0) 311153790Srwatson err(-1, "juggling_thread: pthread_cond_signal"); 312153790Srwatson 313203800Sru if (pthread_mutex_unlock(&threaded_mtx) != 0) 314153790Srwatson err(-1, "juggling_thread: pthread_mutex_unlock"); 315153790Srwatson 316153790Srwatson for (i = 0; i < NUMCYCLES; i++) { 317153790Srwatson for (j = 0; j < threaded_pipeline; j++) { 318153790Srwatson if (message_recv(fd2) < 0) 319153790Srwatson err(-1, "message_recv fd2"); 320153790Srwatson 321153790Srwatson if (message_send(fd2) < 0) 322153790Srwatson err(-1, "message_send fd2"); 323153790Srwatson } 324153790Srwatson } 325153790Srwatson 326153790Srwatson return (NULL); 327153790Srwatson} 328153790Srwatson 329153790Srwatsonstatic struct timespec 330153790Srwatsonthread_juggle(int fd1, int fd2, int pipeline) 331153790Srwatson{ 332153790Srwatson struct timespec tstart, tfinish; 333153790Srwatson pthread_t thread; 334153790Srwatson int i, j; 335153790Srwatson 336153790Srwatson threaded_pipeline = pipeline; 337153790Srwatson 338203800Sru if (pthread_mutex_init(&threaded_mtx, NULL) != 0) 339153790Srwatson err(-1, "thread_juggle: pthread_mutex_init"); 340153790Srwatson 341203800Sru if (pthread_create(&thread, NULL, juggling_thread, &fd2) != 0) 342153790Srwatson err(-1, "thread_juggle: pthread_create"); 343153790Srwatson 344203800Sru if (pthread_mutex_lock(&threaded_mtx) != 0) 345153790Srwatson err(-1, "thread_juggle: pthread_mutex_lock"); 346153790Srwatson 347153790Srwatson while (!threaded_child_ready) { 348203800Sru if (pthread_cond_wait(&threaded_cond, &threaded_mtx) != 0) 349153790Srwatson err(-1, "thread_juggle: pthread_cond_wait"); 350153790Srwatson } 351153790Srwatson 352203800Sru if (pthread_mutex_unlock(&threaded_mtx) != 0) 353153790Srwatson err(-1, "thread_juggle: pthread_mutex_unlock"); 354153790Srwatson 355153790Srwatson if (clock_gettime(CLOCK_REALTIME, &tstart) < 0) 356153790Srwatson err(-1, "thread_juggle: clock_gettime"); 357153790Srwatson 358153790Srwatson for (i = 0; i < NUMCYCLES; i++) { 359153790Srwatson for (j = 0; j < pipeline; j++) { 360153790Srwatson if (message_send(fd1) < 0) 361153790Srwatson err(-1, "message_send fd1"); 362153790Srwatson } 363153790Srwatson 364153790Srwatson for (j = 0; j < pipeline; j++) { 365153790Srwatson if (message_recv(fd1) < 0) 366153790Srwatson err(-1, "message_recv fd1"); 367153790Srwatson } 368153790Srwatson } 369153790Srwatson 370153790Srwatson if (clock_gettime(CLOCK_REALTIME, &tfinish) < 0) 371153790Srwatson err(-1, "thread_juggle: clock_gettime"); 372153790Srwatson 373203800Sru if (pthread_join(thread, NULL) != 0) 374153790Srwatson err(-1, "thread_juggle: pthread_join"); 375153790Srwatson 376153790Srwatson timespecsub(&tfinish, &tstart); 377153790Srwatson 378153790Srwatson return (tfinish); 379153790Srwatson} 380153790Srwatson 381153790Srwatson/* 382153790Srwatson * Juggle messages between two file descriptors in two processes, so measure 383153790Srwatson * the cost of IPC and the cost of a process context switch. 384153790Srwatson * 385153790Srwatson * Since we can't use a mutex between the processes, we simply do an extra 386153790Srwatson * write on the child to let the parent know that it's ready to start. 387153790Srwatson */ 388153790Srwatsonstatic struct timespec 389153790Srwatsonprocess_juggle(int fd1, int fd2, int pipeline) 390153790Srwatson{ 391153790Srwatson struct timespec tstart, tfinish; 392153790Srwatson pid_t pid, ppid, wpid; 393153790Srwatson int error, i, j; 394153790Srwatson 395153790Srwatson ppid = getpid(); 396153790Srwatson 397153790Srwatson pid = fork(); 398153790Srwatson if (pid < 0) 399153790Srwatson err(-1, "process_juggle: fork"); 400153790Srwatson 401153790Srwatson if (pid == 0) { 402153790Srwatson if (message_send(fd2) < 0) { 403153790Srwatson error = errno; 404153790Srwatson kill(ppid, SIGTERM); 405153790Srwatson errno = error; 406153790Srwatson err(-1, "process_juggle: child: message_send"); 407153790Srwatson } 408153790Srwatson 409153790Srwatson for (i = 0; i < NUMCYCLES; i++) { 410153790Srwatson for (j = 0; j < pipeline; j++) { 411153790Srwatson if (message_send(fd2) < 0) 412153790Srwatson err(-1, "message_send fd2"); 413153790Srwatson 414153790Srwatson if (message_recv(fd2) < 0) 415153790Srwatson err(-1, "message_recv fd2"); 416153790Srwatson } 417153790Srwatson } 418153790Srwatson 419153790Srwatson exit(0); 420153790Srwatson } else { 421153790Srwatson if (message_recv(fd1) < 0) { 422153790Srwatson error = errno; 423153790Srwatson kill(pid, SIGTERM); 424153790Srwatson errno = error; 425153790Srwatson err(-1, "process_juggle: parent: message_recv"); 426153790Srwatson } 427153790Srwatson 428153790Srwatson if (clock_gettime(CLOCK_REALTIME, &tstart) < 0) 429153790Srwatson err(-1, "process_juggle: clock_gettime"); 430153790Srwatson 431153790Srwatson for (i = 0; i < NUMCYCLES; i++) { 432153790Srwatson for (j = 0; j < pipeline; j++) { 433153790Srwatson if (message_send(fd1) < 0) { 434153790Srwatson error = errno; 435153790Srwatson kill(pid, SIGTERM); 436153790Srwatson errno = error; 437153790Srwatson err(-1, "message_send fd1"); 438153790Srwatson } 439153790Srwatson } 440153790Srwatson 441153790Srwatson for (j = 0; j < pipeline; j++) { 442153790Srwatson if (message_recv(fd1) < 0) { 443153790Srwatson error = errno; 444153790Srwatson kill(pid, SIGTERM); 445153790Srwatson errno = error; 446153790Srwatson err(-1, "message_recv fd1"); 447153790Srwatson } 448153790Srwatson } 449153790Srwatson } 450153790Srwatson 451153790Srwatson if (clock_gettime(CLOCK_REALTIME, &tfinish) < 0) 452153790Srwatson err(-1, "process_juggle: clock_gettime"); 453153790Srwatson } 454153790Srwatson 455153790Srwatson wpid = waitpid(pid, NULL, 0); 456153790Srwatson if (wpid < 0) 457153790Srwatson err(-1, "process_juggle: waitpid"); 458153790Srwatson if (wpid != pid) 459153790Srwatson errx(-1, "process_juggle: waitpid: pid != wpid"); 460153790Srwatson 461153790Srwatson timespecsub(&tfinish, &tstart); 462153790Srwatson 463153790Srwatson return (tfinish); 464153790Srwatson} 465153790Srwatson 466153790Srwatson/* 467153790Srwatson * When we print out results for larger pipeline sizes, we scale back by the 468153790Srwatson * depth of the pipeline. This generally means dividing by the pipeline 469153790Srwatson * depth. Except when it means dividing by zero. 470153790Srwatson */ 471153790Srwatsonstatic void 472153790Srwatsonscale_timespec(struct timespec *ts, int p) 473153790Srwatson{ 474153790Srwatson 475153790Srwatson if (p == 0) 476153790Srwatson return; 477153790Srwatson 478153790Srwatson ts->tv_sec /= p; 479153790Srwatson ts->tv_nsec /= p; 480153790Srwatson} 481153790Srwatson 482153790Srwatsonstatic const struct ipctype { 483153790Srwatson int (*it_create)(int *fd1p, int *fd2p); 484153790Srwatson const char *it_name; 485153790Srwatson} ipctypes[] = { 486153790Srwatson { pipe_create, "pipe" }, 487153790Srwatson { udp_create, "udp" }, 488153790Srwatson { socketpairdgram_create, "socketpairdgram" }, 489153790Srwatson { socketpairstream_create, "socketpairstream" }, 490153790Srwatson}; 491153790Srwatsonstatic const int ipctypes_len = (sizeof(ipctypes) / sizeof(struct ipctype)); 492153790Srwatson 493153790Srwatsonint 494153790Srwatsonmain(int argc, char *argv[]) 495153790Srwatson{ 496153790Srwatson struct timespec juggle_results[LOOPS], process_results[LOOPS]; 497153790Srwatson struct timespec thread_results[LOOPS]; 498153790Srwatson int fd1, fd2, i, j, p; 499153790Srwatson struct utsname uts; 500153790Srwatson 501154961Srwatson printf("version, juggle.c %s\n", "$FreeBSD$"); 502153790Srwatson 503153790Srwatson if (uname(&uts) < 0) 504153790Srwatson err(-1, "utsname"); 505153790Srwatson printf("sysname, %s\n", uts.sysname); 506153790Srwatson printf("nodename, %s\n", uts.nodename); 507153790Srwatson printf("release, %s\n", uts.release); 508153790Srwatson printf("version, %s\n", uts.version); 509153790Srwatson printf("machine, %s\n", uts.machine); 510153790Srwatson printf("\n"); 511153790Srwatson 512153790Srwatson printf("MESSAGELEN, %d\n", MESSAGELEN); 513153790Srwatson printf("NUMCYCLES, %d\n", NUMCYCLES); 514153790Srwatson printf("LOOPS, %d\n", LOOPS); 515153790Srwatson printf("PIPELINE_MAX, %d\n", PIPELINE_MAX); 516153790Srwatson printf("\n\n"); 517153790Srwatson 518153790Srwatson printf("ipctype, test, pipeline_depth"); 519153790Srwatson for (j = 0; j < LOOPS; j++) 520153790Srwatson printf(", data%d", j); 521153790Srwatson printf("\n"); 522153790Srwatson fflush(stdout); 523153790Srwatson for (p = 0; p < PIPELINE_MAX + 1; p++) { 524153790Srwatson for (i = 0; i < ipctypes_len; i++) { 525153790Srwatson if (ipctypes[i].it_create(&fd1, &fd2) < 0) 526153790Srwatson err(-1, "main: %s", ipctypes[i].it_name); 527153790Srwatson 528153790Srwatson /* 529153790Srwatson * For each test, do one uncounted warmup, then LOOPS 530153790Srwatson * runs of the actual test. 531153790Srwatson */ 532153790Srwatson juggle(fd1, fd2, p); 533153790Srwatson for (j = 0; j < LOOPS; j++) 534153790Srwatson juggle_results[j] = juggle(fd1, fd2, p); 535153790Srwatson process_juggle(fd1, fd2, p); 536153790Srwatson for (j = 0; j < LOOPS; j++) 537153790Srwatson process_results[j] = process_juggle(fd1, fd2, 538153790Srwatson p); 539153790Srwatson thread_juggle(fd1, fd2, p); 540153790Srwatson for (j = 0; j < LOOPS; j++) 541153790Srwatson thread_results[j] = thread_juggle(fd1, fd2, 542153790Srwatson p); 543153790Srwatson for (j = 0; j < LOOPS; j++) { 544153790Srwatson thread_results[j].tv_sec = 0; 545153790Srwatson thread_results[j].tv_nsec = 0; 546153790Srwatson } 547153790Srwatson close(fd1); 548153790Srwatson close(fd2); 549153790Srwatson } 550153790Srwatson /* 551153790Srwatson * When printing results for the round, normalize the results 552153790Srwatson * with respect to the pipeline depth. We're doing p times 553153790Srwatson * as much work, and are we taking p times as long? 554153790Srwatson */ 555153790Srwatson for (i = 0; i < ipctypes_len; i++) { 556153790Srwatson printf("%s, juggle, %d, ", ipctypes[i].it_name, p); 557153790Srwatson for (j = 0; j < LOOPS; j++) { 558153790Srwatson if (j != 0) 559153790Srwatson printf(", "); 560153790Srwatson scale_timespec(&juggle_results[j], p); 561213574Spluknet printf("%jd.%09lu", 562213574Spluknet (intmax_t)juggle_results[j].tv_sec, 563153790Srwatson juggle_results[j].tv_nsec); 564153790Srwatson } 565153790Srwatson printf("\n"); 566153790Srwatson printf("%s, process_juggle, %d, ", 567153790Srwatson ipctypes[i].it_name, p); 568153790Srwatson for (j = 0; j < LOOPS; j++) { 569153790Srwatson if (j != 0) 570153790Srwatson printf(", "); 571153790Srwatson scale_timespec(&process_results[j], p); 572213574Spluknet printf("%jd.%09lu", 573213574Spluknet (intmax_t)process_results[j].tv_sec, 574153790Srwatson process_results[j].tv_nsec); 575153790Srwatson } 576153790Srwatson printf("\n"); 577153790Srwatson printf("%s, thread_juggle, %d, ", 578153790Srwatson ipctypes[i].it_name, p); 579153790Srwatson for (j = 0; j < LOOPS; j++) { 580153790Srwatson if (j != 0) 581153790Srwatson printf(", "); 582153790Srwatson scale_timespec(&thread_results[j], p); 583213574Spluknet printf("%jd.%09lu", 584213574Spluknet (intmax_t)thread_results[j].tv_sec, 585153790Srwatson thread_results[j].tv_nsec); 586153790Srwatson } 587153790Srwatson printf("\n"); 588153790Srwatson } 589153790Srwatson fflush(stdout); 590153790Srwatson } 591153790Srwatson return (0); 592153790Srwatson} 593