#ifdef __sun
#pragma ident "@(#)trivial.c 1.0 08/17/06 Apple Inc."
#endif
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <sys/socket.h>
#include <signal.h>
#include "../libmicro.h"
void writer(int controlfd, int writefd, char* buf, void* cookie);
void touch(char *buf, int nbytes);
#if DEBUG
# define debug(fmt, args...) (void) fprintf(stderr, fmt "\n" , ##args)
#else
# define debug(fmt, args...)
#endif
typedef struct {
int pid;
size_t xfer;
size_t bytes;
char *buf;
int pipes[2];
int control[2];
int initerr;
int parallel;
int warmup;
int repetitions;
} tsd_t;
size_t XFER = 10*1024*1024;
#ifndef XFERSIZE
#define XFERSIZE (64*1024)
#endif
static int optm = XFERSIZE;
static int opts = 10*1024*1024;
static int optw = 0;
int
benchmark_init()
{
debug("benchmark_init\n");
(void) sprintf(lm_optstr, "m:s:w:");
lm_tsdsize = sizeof (tsd_t);
(void) sprintf(lm_usage,
" [-m <message size>]\n"
" [-s <total bytes>]\n"
" [-w <warmup>]\n");
return (0);
}
int
benchmark_optswitch(int opt, char *optarg)
{
debug("benchmark_optswitch\n");
switch (opt) {
case 'm':
optm = atoi(optarg);
break;
case 's':
opts = atoi(optarg);
break;
case 'w':
optw = atoi(optarg);
break;
default:
return (-1);
}
return (0);
}
int
benchmark_initrun()
{
debug("benchmark_initrun\n");
return (0);
}
int
benchmark_initworker(void *tsd)
{
tsd_t *state = (tsd_t *)tsd;
state->xfer = optm;
state->bytes = opts;
state->parallel = lm_optP;
state->warmup = optw;
state->repetitions = lm_optB;
debug("benchmark_initworker: repetitions = %i\n",state->repetitions);
return (0);
}
int
benchmark_initbatch(void *tsd)
{
tsd_t *state = (tsd_t *)tsd;
state->buf = valloc(XFERSIZE);
touch(state->buf, XFERSIZE);
state->initerr = 0;
if (socketpair(AF_UNIX, SOCK_STREAM, 0, state->pipes) == -1) {
perror("socketpair");
state->initerr = 1;
return(0);
}
if (pipe(state->control) == -1) {
perror("pipe");
state->initerr = 2;
return(0);
}
switch (state->pid = fork()) {
case 0:
close(state->control[1]);
close(state->pipes[0]);
writer(state->control[0], state->pipes[1], state->buf, state);
return (0);
case -1:
perror("fork");
state->initerr = 3;
return (0);
default:
break;
}
close(state->control[0]);
close(state->pipes[1]);
return (0);
}
int
benchmark(void *tsd, result_t *res)
{
tsd_t *state = (tsd_t *)tsd;
size_t done, n;
size_t todo = state->bytes;
int i;
debug("in to benchmark - optB = %i : repetitions = %i\n", lm_optB, state->repetitions);
for (i = 0; i < lm_optB; i++) {
write(state->control[1], &todo, sizeof(todo));
for (done = 0; done < todo; done += n) {
if ((n = read(state->pipes[0], state->buf, state->xfer)) <= 0) {
debug("error (n = %d) exiting now\n", n);
exit(1);
}
}
}
res->re_count = i;
debug("out of benchmark - optB = %i : repetitions = %i\n", lm_optB, state->repetitions);
return (0);
}
int
benchmark_finibatch(void *tsd)
{
tsd_t *state = (tsd_t *)tsd;
close(state->control[1]);
close(state->pipes[0]);
if (state->pid > 0) {
kill(state->pid, SIGKILL);
waitpid(state->pid, NULL, 0);
}
state->pid = 0;
return (0);
}
int
benchmark_finiworker(void *tsd)
{
tsd_t *ts = (tsd_t *)tsd;
ts->repetitions++;
ts->repetitions--;
debug("benchmark_finiworker: repetitions = %i\n",ts->repetitions);
return (0);
}
char *
benchmark_result()
{
static char result = '\0';
debug("benchmark_result\n");
return (&result);
}
int
benchmark_finirun()
{
debug("benchmark_finirun\n");
return (0);
}
int
benchmark_fini()
{
debug("benchmark_fini\n");
return (0);
}
void
writer(int controlfd, int writefd, char* buf, void* cookie)
{
size_t todo, n, done;
tsd_t *state = (tsd_t *)cookie;
for ( ;; ) {
read(controlfd, &todo, sizeof(todo));
for (done = 0; done < todo; done += n) {
#ifdef TOUCH
touch(buf, XFERSIZE);
#endif
if ((n = write(writefd, buf, state->xfer)) < 0) {
exit(1);
}
}
}
}
void
touch(char *buf, int nbytes)
{
static int psize;
if (!psize) {
psize = getpagesize();
}
while (nbytes > 0) {
*buf = 1;
buf += psize;
nbytes -= psize;
}
}