/* * Copyright (c) 2006 Apple Inc. All Rights Reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Order of Execution * * benchmark_init * * benchmark_optswitch * * benchmark_initrun * * benchmark_initworker * benchmark_initbatch * benchmark * benchmark_finibatch * benchmark_initbatch * benchmark * benchmark_finibatch, etc. * benchmark_finiworker * * benchmark_result * * benchmark_finirun * * benchmark_fini */ #ifdef __sun #pragma ident "@(#)trivial.c 1.0 08/17/06 Apple Inc." #endif #include #include #include #include #include // add additional headers needed here. #include #include #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 /* * Your state variables should live in the tsd_t struct below */ typedef struct { int pid; size_t xfer; /* bytes to read/write per "packet" */ size_t bytes; /* bytes to read/write in one iteration */ char *buf; /* buffer memory space */ 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) /* all bandwidth I/O should use this */ #endif /* * You can have any lower-case option you want to define. * options are specified in the lm_optstr as either a * single lower-case letter, or a single lower case letter * with a colon after it. In this example, you can optionally * specify -c {str} -e or -t {number} * -c takes a string (quote the string if blanks) * -e is a boolean * -t takes a numeric * argument. */ static int optm = XFERSIZE; static int opts = 10*1024*1024; static int optw = 0; int benchmark_init() { debug("benchmark_init\n"); /* * the lm_optstr must be defined here or no options for you * * ...and the framework will throw an error * */ (void) sprintf(lm_optstr, "m:s:w:"); /* * * tsd_t is the state_information struct * * lm_tsdsize will allocate the space we need for this * structure throughout the rest of the framework */ lm_tsdsize = sizeof (tsd_t); (void) sprintf(lm_usage, " [-m ]\n" " [-s ]\n" " [-w ]\n"); return (0); } /* * This is where you parse your lower-case arguments. * the format was defined in the lm_optstr assignment * in benchmark_init */ 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) { /* * initialize your state variables here first */ 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); } /*ARGSUSED*/ 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); } // handle_scheduler(benchmp_childid(), 0, 1); switch (state->pid = fork()) { case 0: // handle_scheduler(benchmp_childid(), 1, 1); close(state->control[1]); close(state->pipes[0]); writer(state->control[0], state->pipes[1], state->buf, state); return (0); /*NOTREACHED*/ case -1: perror("fork"); state->initerr = 3; return (0); /*NOTREACHED*/ default: break; } close(state->control[0]); close(state->pipes[1]); return (0); } int benchmark(void *tsd, result_t *res) { /* * try not to initialize things here. This is the main * loop of things to get timed. Start a server in * benchmark_initbatch */ 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) { /* error! */ 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; // useless code to show what you can do. 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); } /* * functions from bw_unix.c */ 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) { /* error! */ exit(1); } } } } void touch(char *buf, int nbytes) { static int psize; if (!psize) { psize = getpagesize(); } while (nbytes > 0) { *buf = 1; buf += psize; nbytes -= psize; } }