1/*
2 * Copyright (c) 2006 Apple Inc.  All Rights Reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30/*
31 *	Order of Execution
32 *
33 *	benchmark_init
34 *
35 *	benchmark_optswitch
36 *
37 *		benchmark_initrun
38 *
39 *			benchmark_initworker
40 *				benchmark_initbatch
41 *					benchmark
42 *				benchmark_finibatch
43 *				benchmark_initbatch
44 *					benchmark
45 *				benchmark_finibatch, etc.
46 *			benchmark_finiworker
47 *
48 *		benchmark_result
49 *
50 *		benchmark_finirun
51 *
52 *	benchmark_fini
53 */
54
55
56
57#ifdef	__sun
58#pragma ident	"@(#)trivial.c	1.0	08/17/06 Apple Inc."
59#endif
60
61
62
63#include <unistd.h>
64#include <stdlib.h>
65#include <stdio.h>
66#include <stdbool.h>
67#include <string.h>
68// add additional headers needed here.
69#include <sys/socket.h>
70#include <signal.h>
71
72#include "../libmicro.h"
73
74void	writer(int controlfd, int writefd, char* buf, void* cookie);
75void	touch(char *buf, int nbytes);
76
77#if DEBUG
78# define debug(fmt, args...)	(void) fprintf(stderr, fmt "\n" , ##args)
79#else
80# define debug(fmt, args...)
81#endif
82
83/*
84 *	Your state variables should live in the tsd_t struct below
85 */
86typedef struct {
87	int	pid;
88	size_t	xfer;	/* bytes to read/write per "packet" */
89	size_t	bytes;	/* bytes to read/write in one iteration */
90	char	*buf;	/* buffer memory space */
91	int	pipes[2];
92	int	control[2];
93	int	initerr;
94	int	parallel;
95	int warmup;
96	int repetitions;
97} tsd_t;
98
99size_t	XFER	= 10*1024*1024;
100#ifndef XFERSIZE
101#define XFERSIZE    (64*1024)   /* all bandwidth I/O should use this */
102#endif
103
104/*
105 * You can have any lower-case option you want to define.
106 * options are specified in the lm_optstr as either a
107 * single lower-case letter, or a single lower case letter
108 * with a colon after it.  In this example, you can optionally
109 * specify -c {str} -e or -t {number}
110 *    -c takes a string (quote the string if blanks)
111 *    -e is a boolean
112 *    -t takes a numeric
113 * argument.
114 */
115static int	optm = XFERSIZE;
116static int	opts = 10*1024*1024;
117static int	optw = 0;
118
119int
120benchmark_init()
121{
122	debug("benchmark_init\n");
123	/*
124	 *	the lm_optstr must be defined here or no options for you
125	 *
126	 * 	...and the framework will throw an error
127	 *
128	 */
129	(void) sprintf(lm_optstr, "m:s:w:");
130	/*
131	 *
132	 * 	tsd_t is the state_information struct
133	 *
134	 *	lm_tsdsize will allocate the space we need for this
135	 *	structure throughout the rest of the framework
136	 */
137	lm_tsdsize = sizeof (tsd_t);
138
139	(void) sprintf(lm_usage,
140		"		[-m <message size>]\n"
141		"		[-s <total bytes>]\n"
142		"		[-w <warmup>]\n");
143
144	return (0);
145}
146
147/*
148 * This is where you parse your lower-case arguments.
149 * the format was defined in the lm_optstr assignment
150 * in benchmark_init
151 */
152int
153benchmark_optswitch(int opt, char *optarg)
154{
155	debug("benchmark_optswitch\n");
156
157	switch (opt) {
158		case 'm':
159			optm = atoi(optarg);
160			break;
161		case 's':
162			opts = atoi(optarg);
163			break;
164		case 'w':
165			optw = atoi(optarg);
166			break;
167	default:
168		return (-1);
169	}
170	return (0);
171}
172
173int
174benchmark_initrun()
175{
176	debug("benchmark_initrun\n");
177	return (0);
178}
179
180int
181benchmark_initworker(void *tsd)
182{
183	/*
184	 *	initialize your state variables here first
185	 */
186	tsd_t	*state = (tsd_t *)tsd;
187	state->xfer = optm;
188	state->bytes = opts;
189	state->parallel = lm_optP;
190	state->warmup = optw;
191	state->repetitions = lm_optB;
192	debug("benchmark_initworker: repetitions = %i\n",state->repetitions);
193	return (0);
194}
195
196/*ARGSUSED*/
197int
198benchmark_initbatch(void *tsd)
199{
200	tsd_t	*state = (tsd_t *)tsd;
201
202	state->buf = valloc(XFERSIZE);
203	touch(state->buf, XFERSIZE);
204	state->initerr = 0;
205	if (socketpair(AF_UNIX, SOCK_STREAM, 0, state->pipes) == -1) {
206		perror("socketpair");
207		state->initerr = 1;
208		return(0);
209	}
210	if (pipe(state->control) == -1) {
211		perror("pipe");
212		state->initerr = 2;
213		return(0);
214	}
215//	handle_scheduler(benchmp_childid(), 0, 1);
216	switch (state->pid = fork()) {
217	    case 0:
218//	      handle_scheduler(benchmp_childid(), 1, 1);
219		close(state->control[1]);
220		close(state->pipes[0]);
221		writer(state->control[0], state->pipes[1], state->buf, state);
222		return (0);
223		/*NOTREACHED*/
224
225	    case -1:
226		perror("fork");
227		state->initerr = 3;
228		return (0);
229		/*NOTREACHED*/
230
231	    default:
232		break;
233	}
234	close(state->control[0]);
235	close(state->pipes[1]);
236	return (0);
237}
238
239int
240benchmark(void *tsd, result_t *res)
241{
242	/*
243	 *	try not to initialize things here.  This is the main
244	 *  loop of things to get timed.  Start a server in
245	 *  benchmark_initbatch
246	 */
247	tsd_t	*state = (tsd_t *)tsd;
248	size_t	done, n;
249	size_t	todo = state->bytes;
250	int		i;
251
252	debug("in to benchmark - optB = %i : repetitions = %i\n", lm_optB, state->repetitions);
253	for (i = 0; i < lm_optB; i++) {
254		write(state->control[1], &todo, sizeof(todo));
255		for (done = 0; done < todo; done += n) {
256			if ((n = read(state->pipes[0], state->buf, state->xfer)) <= 0) {
257				/* error! */
258				debug("error (n = %d) exiting now\n", n);
259				exit(1);
260			}
261		}
262	}
263	res->re_count = i;
264	debug("out of benchmark - optB = %i : repetitions = %i\n", lm_optB, state->repetitions);
265
266	return (0);
267}
268
269int
270benchmark_finibatch(void *tsd)
271{
272	tsd_t			*state = (tsd_t *)tsd;
273
274	close(state->control[1]);
275	close(state->pipes[0]);
276	if (state->pid > 0) {
277		kill(state->pid, SIGKILL);
278		waitpid(state->pid, NULL, 0);
279	}
280	state->pid = 0;
281	return (0);
282}
283
284int
285benchmark_finiworker(void *tsd)
286{
287	tsd_t			*ts = (tsd_t *)tsd;
288	// useless code to show what you can do.
289	 ts->repetitions++;
290	 ts->repetitions--;
291	debug("benchmark_finiworker: repetitions = %i\n",ts->repetitions);
292	return (0);
293}
294
295char *
296benchmark_result()
297{
298	static char		result = '\0';
299	debug("benchmark_result\n");
300	return (&result);
301}
302
303int
304benchmark_finirun()
305{
306	debug("benchmark_finirun\n");
307	return (0);
308}
309
310
311int
312benchmark_fini()
313{
314	debug("benchmark_fini\n");
315	return (0);
316}
317
318/*
319 * functions from bw_unix.c
320 */
321void
322writer(int controlfd, int writefd, char* buf, void* cookie)
323{
324	size_t	todo, n, done;
325	tsd_t	*state = (tsd_t *)cookie;
326
327	for ( ;; ) {
328		read(controlfd, &todo, sizeof(todo));
329		for (done = 0; done < todo; done += n) {
330#ifdef TOUCH
331			touch(buf, XFERSIZE);
332#endif
333			if ((n = write(writefd, buf, state->xfer)) < 0) {
334				/* error! */
335				exit(1);
336			}
337		}
338	}
339}
340
341void
342touch(char *buf, int nbytes)
343{
344    static int	psize;
345
346    if (!psize) {
347        psize = getpagesize();
348    }
349    while (nbytes > 0) {
350        *buf = 1;
351        buf += psize;
352        nbytes -= psize;
353    }
354}
355
356