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	"@(#)lmbench_bw_mmap_rd.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 <fcntl.h>
70#include <limits.h>
71#include <sys/mman.h>
72
73#include "../libmicro.h"
74
75#if DEBUG
76# define debug(fmt, args...)	(void) fprintf(stderr, fmt "\n" , ##args)
77#else
78# define debug(fmt, args...)
79#endif
80
81/*
82 *	Your state variables should live in the tsd_t struct below
83 */
84typedef struct {
85	size_t	nbytes;
86	char 	filename[_POSIX_PATH_MAX];
87	int 	fd;
88	int 	clone;
89	void	*buf;
90	bool open_read_close;
91} tsd_t;
92
93/*
94 * You can have any lower-case option you want to define.
95 * options are specified in the lm_optstr as either a
96 * single lower-case letter, or a single lower case letter
97 * with a colon after it.  In this example, you can optionally
98 * specify -c {str} -e or -t {number}
99 *    -c takes a string (quote the string if blanks)
100 *    -e is a boolean
101 *    -t takes a numeric
102 * argument.
103 */
104static char 	optf[_POSIX_PATH_MAX];
105static int		opts = 1024;
106static bool 	opti = false;	// io_only or read and i/o (default read and i/o)
107
108#ifdef MAP_FILE
109#	define	MMAP_FLAGS	MAP_FILE|MAP_SHARED
110#else
111#	define	MMAP_FLAGS	MAP_SHARED
112#endif
113
114#define	CHK(x)		if ((int)(x) == -1) { perror(#x); exit(1); }
115#ifndef	MIN
116#define	MIN(a, b)	((a) < (b) ? (a) : (b))
117#endif
118
119#define	TYPE	int
120#define	MINSZ	(sizeof(TYPE) * 128)
121
122void	*buf;		/* do the I/O here */
123size_t	xfersize;	/* do it in units of this */
124size_t	count;		/* bytes to move (can't be modified) */
125
126/* analogous to bzero, bcopy, etc., except that it just reads
127 * data into the processor
128 */
129long
130bread(void* buf, long nbytes)
131{
132	long sum = 0;
133	register long *p, *next;
134	register char *end;
135
136	p = (long*)buf;
137	end = (char*)buf + nbytes;
138	for (next = p + 128; (void*)next <= (void*)end; p = next, next += 128) {
139		sum +=
140			p[0]+p[1]+p[2]+p[3]+p[4]+p[5]+p[6]+p[7]+
141			p[8]+p[9]+p[10]+p[11]+p[12]+p[13]+p[14]+
142			p[15]+p[16]+p[17]+p[18]+p[19]+p[20]+p[21]+
143			p[22]+p[23]+p[24]+p[25]+p[26]+p[27]+p[28]+
144			p[29]+p[30]+p[31]+p[32]+p[33]+p[34]+p[35]+
145			p[36]+p[37]+p[38]+p[39]+p[40]+p[41]+p[42]+
146			p[43]+p[44]+p[45]+p[46]+p[47]+p[48]+p[49]+
147			p[50]+p[51]+p[52]+p[53]+p[54]+p[55]+p[56]+
148			p[57]+p[58]+p[59]+p[60]+p[61]+p[62]+p[63]+
149			p[64]+p[65]+p[66]+p[67]+p[68]+p[69]+p[70]+
150			p[71]+p[72]+p[73]+p[74]+p[75]+p[76]+p[77]+
151			p[78]+p[79]+p[80]+p[81]+p[82]+p[83]+p[84]+
152			p[85]+p[86]+p[87]+p[88]+p[89]+p[90]+p[91]+
153			p[92]+p[93]+p[94]+p[95]+p[96]+p[97]+p[98]+
154			p[99]+p[100]+p[101]+p[102]+p[103]+p[104]+
155			p[105]+p[106]+p[107]+p[108]+p[109]+p[110]+
156			p[111]+p[112]+p[113]+p[114]+p[115]+p[116]+
157			p[117]+p[118]+p[119]+p[120]+p[121]+p[122]+
158			p[123]+p[124]+p[125]+p[126]+p[127];
159	}
160	for (next = p + 16; (void*)next <= (void*)end; p = next, next += 16) {
161		sum +=
162			p[0]+p[1]+p[2]+p[3]+p[4]+p[5]+p[6]+p[7]+
163			p[8]+p[9]+p[10]+p[11]+p[12]+p[13]+p[14]+
164			p[15];
165	}
166	for (next = p + 1; (void*)next <= (void*)end; p = next, next++) {
167		sum += *p;
168	}
169	return sum;
170}
171
172int
173cp(char* src, char* dst, mode_t mode)
174{
175    int sfd, dfd;
176    char buf[8192];
177    ssize_t size;
178
179    if ((sfd = open(src, O_RDONLY)) < 0) {
180        return -1;
181    }
182    if ((dfd = open(dst, O_CREAT|O_TRUNC|O_RDWR, mode)) < 0) {
183        return -1;
184    }
185    while ((size = read(sfd, buf, 8192)) > 0) {
186        if (write(dfd, buf, size) < size) return -1;
187    }
188    fsync(dfd);
189    close(sfd);
190    close(dfd);
191    return 0;
192}
193
194
195int
196benchmark_init()
197{
198	debug("benchmark_init");
199	/*
200	 *	the lm_optstr must be defined here or no options for you
201	 *
202	 * 	...and the framework will throw an error
203	 *
204	 */
205	(void) sprintf(lm_optstr, "f:is:");
206	/*
207	 * 	tsd_t is the state info struct that we pass around
208	 *
209	 *	lm_tsdsize will allocate the space we need for this
210	 *	structure throughout the rest of the framework
211	 */
212	lm_tsdsize = sizeof (tsd_t);
213
214	(void) sprintf(lm_usage,
215		"		-f filename\n"
216		"		-s size\n"
217		"		[-i] io_only (no open/close)\n"
218	    "notes: read and sum file via memory mapping mmap(2) interface");
219	sprintf(optf, "/tmp/%d", (int)getpid());
220	opts = 1024;
221	return (0);
222}
223
224/*
225 * This is where you parse your lower-case arguments.
226 * the format was defined in the lm_optstr assignment
227 * in benchmark_init
228 */
229int
230benchmark_optswitch(int opt, char *optarg)
231{
232	debug("benchmark_optswitch");
233
234	switch (opt) {
235	case 'f':
236		strncpy(optf, optarg, 255);
237		debug("optf = %s\n", optf);
238		break;
239	case 'i':
240		opti = true;
241		debug("opti = %s\n", opti? "true": "false");
242		break;
243	case 's':
244		opts = sizetoint(optarg);
245		debug("opts = %d\n", opts);
246		break;
247	default:
248		return (-1);
249	}
250	return (0);
251}
252
253int
254benchmark_initrun()
255{
256	debug("benchmark_initrun");
257	return (0);
258}
259
260int
261benchmark_initworker(void *tsd)
262{
263	/*
264	 *	initialize your state variables here first
265	 */
266	tsd_t	*state = (tsd_t *)tsd;
267
268	strncpy(state->filename, optf, 255);
269	state->nbytes = opts;
270	state->open_read_close = opti;
271
272	debug("benchmark_initworker\n");
273	return (0);
274}
275
276/*ARGSUSED*/
277int
278benchmark_initbatch(void *tsd)
279{
280	tsd_t	*state = (tsd_t *)tsd;
281	state->fd = -1;
282	state->buf = NULL;
283
284	if (state->clone) {
285		char buf[8192];
286		char* s;
287
288		/* copy original file into a process-specific one */
289		sprintf(buf, "/tmp/%d", (int)getpid());
290		s = (char*)malloc(strlen(state->filename) + strlen(buf) + 1);
291		sprintf(s, "/tmp/%s%d", state->filename, (int)getpid());
292		if (cp(state->filename, s, S_IREAD|S_IWRITE) < 0) {
293			perror("creating private tempfile");
294			unlink(s);
295			exit(1);
296		}
297		strcpy(state->filename, s);
298	}
299
300	CHK(state->fd = open(state->filename, 0));
301	CHK(state->buf = mmap(0, state->nbytes, PROT_READ,
302				     MMAP_FLAGS, state->fd, 0));
303	debug("benchmark_initbatch");
304	return (0);
305}
306
307int
308benchmark(void *tsd, result_t *res)
309{
310	/*
311	 *	try not to initialize things here.  This is the main
312	 *  loop of things to get timed.  Start a server in
313	 *  benchmark_initbatch
314	 */
315	tsd_t	*state = (tsd_t *)tsd;
316	int		i;
317	int		fd;
318	void	*p;
319
320	debug("in to benchmark - optB = %i", lm_optB);
321	for (i = 0; i < lm_optB; i++) {
322		if (state->open_read_close) {
323			CHK(fd = open(state->filename, 0));
324			CHK(p = mmap(0, state->nbytes, PROT_READ, MMAP_FLAGS, fd, 0));
325			bread(p, state->nbytes);
326			close(fd);
327			munmap(p, state->nbytes);
328		} else {
329			bread(state->buf, state->nbytes);
330		}
331	}
332	res->re_count = i;
333	debug("out of benchmark - optB = %i", lm_optB);
334
335	return (0);
336}
337
338int
339benchmark_finibatch(void *tsd)
340{
341	tsd_t	*state = (tsd_t *)tsd;
342	if (state->buf) munmap(state->buf, state->nbytes);
343	if (state->fd >= 0) close(state->fd);
344	if (state->clone) unlink(state->filename);
345	debug("benchmark_finibatch");
346	return (0);
347}
348
349int
350benchmark_finiworker(void *tsd)
351{
352	debug("benchmark_finiworker");
353	return (0);
354}
355
356char *
357benchmark_result()
358{
359	static char		result = '\0';
360	debug("benchmark_result");
361	return (&result);
362}
363
364int
365benchmark_finirun()
366{
367	debug("benchmark_finirun");
368	return (0);
369}
370
371
372int
373benchmark_fini()
374{
375	debug("benchmark_fini");
376	return (0);
377}
378
379