My just-shovel-data-through-for-X-amount-of-time test

David Howells
2019-09-13T13:06:43Z

/*
* Benchmark a pipe by seeing how many 511-byte writes can be stuffed through
* it in a certain amount of time. Compile with -lm.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <math.h>
#include <sys/wait.h>
#include <sys/mman.h>

static char buf1[4096] __attribute__((aligned(4096)));
static char buf2[4096] __attribute__((aligned(4096)));
static unsigned long long *results;

static volatile int stop;
void sigalrm(int sig)
{
stop = 1;
}

static __attribute__((noreturn))
void producer(int fd, int i)
{
unsigned long long l = 0;
ssize_t n;

signal(SIGALRM, sigalrm);
alarm(1);

while (!stop) {
n = write(fd, buf1, 511);
if (n == -1) {
perror("read");
exit(1);
}

l += n;
}

results[i] = l;
exit(0);
}

static __attribute__((noreturn))
void consumer(int fd)
{
unsigned long long l = 0;
ssize_t n;

for (;;) {
n = read(fd, buf2, 4096);
if (n == 0)
break;
if (n == -1) {
perror("read");
exit(1);
}

l += n;
}

exit(0);
}

unsigned long long stddev(const unsigned long long *vals, int nvals)
{
double sum = 0.0, mean, sd = 0.0;
int i;

for (i = 0; i < nvals; i++)
sum += vals[i];

mean = sum / nvals;
for (i = 0; i < nvals; i++)
sd += pow(vals[i] - mean, 2);
return sqrt(sd / 10);
}

int main()
{
unsigned long long t = 0;
int ex = 0, i;

results = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
if (results == MAP_FAILED) {
perror("mmap");
exit(1);
}

for (i = 0; i < 16 && ex == 0; i++) {
pid_t prod, con;
int pfd[2], wt;

if (pipe2(pfd, 0) < 0) {
perror("pipe");
exit(1);
}

con = fork();
switch (con) {
case -1:
perror("fork/c");
exit(1);
case 0:
close(pfd[1]);
consumer(pfd[0]);
default:
break;
}

prod = fork();
switch (prod) {
case -1:
perror("fork/p");
exit(1);
case 0:
close(pfd[0]);
producer(pfd[1], i);
default:
break;
}

close(pfd[0]);
close(pfd[1]);

for (;;) {
errno = 0;
wait(&wt);
if (errno == ECHILD)
break;
if (!WIFEXITED(wt) || WEXITSTATUS(wt) != 0)
ex = 1;
}

printf("WR[%02u]: %12llu\n", i, results[i]);
t += results[i];
}

printf("total : %12llu\n", t);
printf("avg : %12llu\n", t / i);
printf("stddev: %12llu\n", stddev(results, i));
exit(ex);
}