1 /*
2  * bw_mem.c - simple memory write bandwidth benchmark
3  *
4  * Usage: bw_mem [-P <parallelism>] [-W <warmup>] [-N <repetitions>] size what
5  *        what: rd wr rdwr cp fwr frd fcp bzero bcopy
6  *
7  * Copyright (c) 1994-1996 Larry McVoy.  Distributed under the FSF GPL with
8  * additional restriction that results may published only if
9  * (1) the benchmark is unmodified, and
10  * (2) the version in the sccsid below is included in the report.
11  * Support for this development by Sun Microsystems is gratefully acknowledged.
12  */
13 char	*id = "$Id$";
14 
15 #include "bench.h"
16 
17 #define TYPE    int
18 
19 /*
20  * rd - 4 byte read, 32 byte stride
21  * wr - 4 byte write, 32 byte stride
22  * rdwr - 4 byte read followed by 4 byte write to same place, 32 byte stride
23  * cp - 4 byte read then 4 byte write to different place, 32 byte stride
24  * fwr - write every 4 byte word
25  * frd - read every 4 byte word
26  * fcp - copy every 4 byte word
27  *
28  * All tests do 512 byte chunks in a loop.
29  *
30  * XXX - do a 64bit version of this.
31  */
32 void	rd(iter_t iterations, void *cookie);
33 void	wr(iter_t iterations, void *cookie);
34 void	rdwr(iter_t iterations, void *cookie);
35 void	mcp(iter_t iterations, void *cookie);
36 void	fwr(iter_t iterations, void *cookie);
37 void	frd(iter_t iterations, void *cookie);
38 void	fcp(iter_t iterations, void *cookie);
39 void	loop_bzero(iter_t iterations, void *cookie);
40 void	loop_bcopy(iter_t iterations, void *cookie);
41 void	init_overhead(iter_t iterations, void *cookie);
42 void	init_loop(iter_t iterations, void *cookie);
43 void	cleanup(iter_t iterations, void *cookie);
44 
45 typedef struct _state {
46 	double	overhead;
47 	size_t	nbytes;
48 	int	need_buf2;
49 	int	aligned;
50 	TYPE	*buf;
51 	TYPE	*buf2;
52 	TYPE	*buf2_orig;
53 	TYPE	*lastone;
54 	size_t	N;
55 } state_t;
56 
57 void	adjusted_bandwidth(uint64 t, uint64 b, uint64 iter, double ovrhd);
58 
59 int
main(int ac,char ** av)60 main(int ac, char **av)
61 {
62 	int	parallel = 1;
63 	int	warmup = 0;
64 	int	repetitions = -1;
65 	size_t	nbytes;
66 	state_t	state;
67 	int	c;
68 	char	*usage = "[-P <parallelism>] [-W <warmup>] [-N <repetitions>] <size> what [conflict]\nwhat: rd wr rdwr cp fwr frd fcp bzero bcopy\n<size> must be larger than 512";
69 
70 	state.overhead = 0;
71 
72 	while (( c = getopt(ac, av, "P:W:N:")) != EOF) {
73 		switch(c) {
74 		case 'P':
75 			parallel = atoi(optarg);
76 			if (parallel <= 0) lmbench_usage(ac, av, usage);
77 			break;
78 		case 'W':
79 			warmup = atoi(optarg);
80 			break;
81 		case 'N':
82 			repetitions = atoi(optarg);
83 			break;
84 		default:
85 			lmbench_usage(ac, av, usage);
86 			break;
87 		}
88 	}
89 
90 	/* should have two, possibly three [indicates align] arguments left */
91 	state.aligned = state.need_buf2 = 0;
92 	if (optind + 3 == ac) {
93 		state.aligned = 1;
94 	} else if (optind + 2 != ac) {
95 		lmbench_usage(ac, av, usage);
96 	}
97 
98 	nbytes = state.nbytes = bytes(av[optind]);
99 	if (state.nbytes < 512) { /* this is the number of bytes in the loop */
100 		lmbench_usage(ac, av, usage);
101 	}
102 
103 	if (streq(av[optind+1], "cp") ||
104 	    streq(av[optind+1], "fcp") || streq(av[optind+1], "bcopy")) {
105 		state.need_buf2 = 1;
106 	}
107 
108 	if (streq(av[optind+1], "rd")) {
109 		benchmp(init_loop, rd, cleanup, 0, parallel,
110 			warmup, repetitions, &state);
111 	} else if (streq(av[optind+1], "wr")) {
112 		benchmp(init_loop, wr, cleanup, 0, parallel,
113 			warmup, repetitions, &state);
114 	} else if (streq(av[optind+1], "rdwr")) {
115 		benchmp(init_loop, rdwr, cleanup, 0, parallel,
116 			warmup, repetitions, &state);
117 	} else if (streq(av[optind+1], "cp")) {
118 		benchmp(init_loop, mcp, cleanup, 0, parallel,
119 			warmup, repetitions, &state);
120 	} else if (streq(av[optind+1], "frd")) {
121 		benchmp(init_loop, frd, cleanup, 0, parallel,
122 			warmup, repetitions, &state);
123 	} else if (streq(av[optind+1], "fwr")) {
124 		benchmp(init_loop, fwr, cleanup, 0, parallel,
125 			warmup, repetitions, &state);
126 	} else if (streq(av[optind+1], "fcp")) {
127 		benchmp(init_loop, fcp, cleanup, 0, parallel,
128 			warmup, repetitions, &state);
129 	} else if (streq(av[optind+1], "bzero")) {
130 		benchmp(init_loop, loop_bzero, cleanup, 0, parallel,
131 			warmup, repetitions, &state);
132 	} else if (streq(av[optind+1], "bcopy")) {
133 		benchmp(init_loop, loop_bcopy, cleanup, 0, parallel,
134 			warmup, repetitions, &state);
135 	} else {
136 		lmbench_usage(ac, av, usage);
137 	}
138 	adjusted_bandwidth(gettime(), nbytes,
139 			   get_n() * parallel, state.overhead);
140 	return(0);
141 }
142 
143 void
init_overhead(iter_t iterations,void * cookie)144 init_overhead(iter_t iterations, void *cookie)
145 {
146 }
147 
148 void
init_loop(iter_t iterations,void * cookie)149 init_loop(iter_t iterations, void *cookie)
150 {
151 	state_t *state = (state_t *) cookie;
152 
153 	if (iterations) return;
154 
155         state->buf = (TYPE *)valloc(state->nbytes);
156 	state->buf2_orig = NULL;
157 	state->lastone = (TYPE*)state->buf - 1;
158 	state->lastone = (TYPE*)((char *)state->buf + state->nbytes - 512);
159 	state->N = state->nbytes;
160 
161 	if (!state->buf) {
162 		perror("malloc");
163 		exit(1);
164 	}
165 	bzero((void*)state->buf, state->nbytes);
166 
167 	if (state->need_buf2 == 1) {
168 		state->buf2_orig = state->buf2 = (TYPE *)valloc(state->nbytes + 2048);
169 		if (!state->buf2) {
170 			perror("malloc");
171 			exit(1);
172 		}
173 
174 		/* default is to have stuff unaligned wrt each other */
175 		/* XXX - this is not well tested or thought out */
176 		if (state->aligned) {
177 			char	*tmp = (char *)state->buf2;
178 
179 			tmp += 2048 - 128;
180 			state->buf2 = (TYPE *)tmp;
181 		}
182 	}
183 }
184 
185 void
cleanup(iter_t iterations,void * cookie)186 cleanup(iter_t iterations, void *cookie)
187 {
188 	state_t *state = (state_t *) cookie;
189 
190 	if (iterations) return;
191 
192 	free(state->buf);
193 	if (state->buf2_orig) free(state->buf2_orig);
194 }
195 
196 void
rd(iter_t iterations,void * cookie)197 rd(iter_t iterations, void *cookie)
198 {
199 	state_t *state = (state_t *) cookie;
200 	register TYPE *lastone = state->lastone;
201 	register int sum = 0;
202 
203 	while (iterations-- > 0) {
204 	    register TYPE *p = state->buf;
205 	    while (p <= lastone) {
206 		sum +=
207 #define	DOIT(i)	p[i]+
208 		DOIT(0) DOIT(4) DOIT(8) DOIT(12) DOIT(16) DOIT(20) DOIT(24)
209 		DOIT(28) DOIT(32) DOIT(36) DOIT(40) DOIT(44) DOIT(48) DOIT(52)
210 		DOIT(56) DOIT(60) DOIT(64) DOIT(68) DOIT(72) DOIT(76)
211 		DOIT(80) DOIT(84) DOIT(88) DOIT(92) DOIT(96) DOIT(100)
212 		DOIT(104) DOIT(108) DOIT(112) DOIT(116) DOIT(120)
213 		p[124];
214 		p +=  128;
215 	    }
216 	}
217 	use_int(sum);
218 }
219 #undef	DOIT
220 
221 void
wr(iter_t iterations,void * cookie)222 wr(iter_t iterations, void *cookie)
223 {
224 	state_t *state = (state_t *) cookie;
225 	register TYPE *lastone = state->lastone;
226 
227 	while (iterations-- > 0) {
228 	    register TYPE *p = state->buf;
229 	    while (p <= lastone) {
230 #define	DOIT(i)	p[i] = 1;
231 		DOIT(0) DOIT(4) DOIT(8) DOIT(12) DOIT(16) DOIT(20) DOIT(24)
232 		DOIT(28) DOIT(32) DOIT(36) DOIT(40) DOIT(44) DOIT(48) DOIT(52)
233 		DOIT(56) DOIT(60) DOIT(64) DOIT(68) DOIT(72) DOIT(76)
234 		DOIT(80) DOIT(84) DOIT(88) DOIT(92) DOIT(96) DOIT(100)
235 		DOIT(104) DOIT(108) DOIT(112) DOIT(116) DOIT(120) DOIT(124);
236 		p +=  128;
237 	    }
238 	}
239 }
240 #undef	DOIT
241 
242 void
rdwr(iter_t iterations,void * cookie)243 rdwr(iter_t iterations, void *cookie)
244 {
245 	state_t *state = (state_t *) cookie;
246 	register TYPE *lastone = state->lastone;
247 	register int sum = 0;
248 
249 	while (iterations-- > 0) {
250 	    register TYPE *p = state->buf;
251 	    while (p <= lastone) {
252 #define	DOIT(i)	sum += p[i]; p[i] = 1;
253 		DOIT(0) DOIT(4) DOIT(8) DOIT(12) DOIT(16) DOIT(20) DOIT(24)
254 		DOIT(28) DOIT(32) DOIT(36) DOIT(40) DOIT(44) DOIT(48) DOIT(52)
255 		DOIT(56) DOIT(60) DOIT(64) DOIT(68) DOIT(72) DOIT(76)
256 		DOIT(80) DOIT(84) DOIT(88) DOIT(92) DOIT(96) DOIT(100)
257 		DOIT(104) DOIT(108) DOIT(112) DOIT(116) DOIT(120) DOIT(124);
258 		p +=  128;
259 	    }
260 	}
261 	use_int(sum);
262 }
263 #undef	DOIT
264 
265 void
mcp(iter_t iterations,void * cookie)266 mcp(iter_t iterations, void *cookie)
267 {
268 	state_t *state = (state_t *) cookie;
269 	register TYPE *lastone = state->lastone;
270 	TYPE* p_save = NULL;
271 
272 	while (iterations-- > 0) {
273 	    register TYPE *p = state->buf;
274 	    register TYPE *dst = state->buf2;
275 	    while (p <= lastone) {
276 #define	DOIT(i)	dst[i] = p[i];
277 		DOIT(0) DOIT(4) DOIT(8) DOIT(12) DOIT(16) DOIT(20) DOIT(24)
278 		DOIT(28) DOIT(32) DOIT(36) DOIT(40) DOIT(44) DOIT(48) DOIT(52)
279 		DOIT(56) DOIT(60) DOIT(64) DOIT(68) DOIT(72) DOIT(76)
280 		DOIT(80) DOIT(84) DOIT(88) DOIT(92) DOIT(96) DOIT(100)
281 		DOIT(104) DOIT(108) DOIT(112) DOIT(116) DOIT(120) DOIT(124);
282 		p += 128;
283 		dst += 128;
284 	    }
285 	    p_save = p;
286 	}
287 	use_pointer(p_save);
288 }
289 #undef	DOIT
290 
291 void
fwr(iter_t iterations,void * cookie)292 fwr(iter_t iterations, void *cookie)
293 {
294 	state_t *state = (state_t *) cookie;
295 	register TYPE *lastone = state->lastone;
296 	TYPE* p_save = NULL;
297 
298 	while (iterations-- > 0) {
299 	    register TYPE *p = state->buf;
300 	    while (p <= lastone) {
301 #define	DOIT(i)	p[i]=
302 		DOIT(0) DOIT(1) DOIT(2) DOIT(3) DOIT(4) DOIT(5) DOIT(6)
303 		DOIT(7) DOIT(8) DOIT(9) DOIT(10) DOIT(11) DOIT(12)
304 		DOIT(13) DOIT(14) DOIT(15) DOIT(16) DOIT(17) DOIT(18)
305 		DOIT(19) DOIT(20) DOIT(21) DOIT(22) DOIT(23) DOIT(24)
306 		DOIT(25) DOIT(26) DOIT(27) DOIT(28) DOIT(29) DOIT(30)
307 		DOIT(31) DOIT(32) DOIT(33) DOIT(34) DOIT(35) DOIT(36)
308 		DOIT(37) DOIT(38) DOIT(39) DOIT(40) DOIT(41) DOIT(42)
309 		DOIT(43) DOIT(44) DOIT(45) DOIT(46) DOIT(47) DOIT(48)
310 		DOIT(49) DOIT(50) DOIT(51) DOIT(52) DOIT(53) DOIT(54)
311 		DOIT(55) DOIT(56) DOIT(57) DOIT(58) DOIT(59) DOIT(60)
312 		DOIT(61) DOIT(62) DOIT(63) DOIT(64) DOIT(65) DOIT(66)
313 		DOIT(67) DOIT(68) DOIT(69) DOIT(70) DOIT(71) DOIT(72)
314 		DOIT(73) DOIT(74) DOIT(75) DOIT(76) DOIT(77) DOIT(78)
315 		DOIT(79) DOIT(80) DOIT(81) DOIT(82) DOIT(83) DOIT(84)
316 		DOIT(85) DOIT(86) DOIT(87) DOIT(88) DOIT(89) DOIT(90)
317 		DOIT(91) DOIT(92) DOIT(93) DOIT(94) DOIT(95) DOIT(96)
318 		DOIT(97) DOIT(98) DOIT(99) DOIT(100) DOIT(101) DOIT(102)
319 		DOIT(103) DOIT(104) DOIT(105) DOIT(106) DOIT(107)
320 		DOIT(108) DOIT(109) DOIT(110) DOIT(111) DOIT(112)
321 		DOIT(113) DOIT(114) DOIT(115) DOIT(116) DOIT(117)
322 		DOIT(118) DOIT(119) DOIT(120) DOIT(121) DOIT(122)
323 		DOIT(123) DOIT(124) DOIT(125) DOIT(126) DOIT(127) 1;
324 		p += 128;
325 	    }
326 	    p_save = p;
327 	}
328 	use_pointer(p_save);
329 }
330 #undef	DOIT
331 
332 void
frd(iter_t iterations,void * cookie)333 frd(iter_t iterations, void *cookie)
334 {
335 	state_t *state = (state_t *) cookie;
336 	register int sum = 0;
337 	register TYPE *lastone = state->lastone;
338 
339 	while (iterations-- > 0) {
340 	    register TYPE *p = state->buf;
341 	    while (p <= lastone) {
342 		sum +=
343 #define	DOIT(i)	p[i]+
344 		DOIT(0) DOIT(1) DOIT(2) DOIT(3) DOIT(4) DOIT(5) DOIT(6)
345 		DOIT(7) DOIT(8) DOIT(9) DOIT(10) DOIT(11) DOIT(12)
346 		DOIT(13) DOIT(14) DOIT(15) DOIT(16) DOIT(17) DOIT(18)
347 		DOIT(19) DOIT(20) DOIT(21) DOIT(22) DOIT(23) DOIT(24)
348 		DOIT(25) DOIT(26) DOIT(27) DOIT(28) DOIT(29) DOIT(30)
349 		DOIT(31) DOIT(32) DOIT(33) DOIT(34) DOIT(35) DOIT(36)
350 		DOIT(37) DOIT(38) DOIT(39) DOIT(40) DOIT(41) DOIT(42)
351 		DOIT(43) DOIT(44) DOIT(45) DOIT(46) DOIT(47) DOIT(48)
352 		DOIT(49) DOIT(50) DOIT(51) DOIT(52) DOIT(53) DOIT(54)
353 		DOIT(55) DOIT(56) DOIT(57) DOIT(58) DOIT(59) DOIT(60)
354 		DOIT(61) DOIT(62) DOIT(63) DOIT(64) DOIT(65) DOIT(66)
355 		DOIT(67) DOIT(68) DOIT(69) DOIT(70) DOIT(71) DOIT(72)
356 		DOIT(73) DOIT(74) DOIT(75) DOIT(76) DOIT(77) DOIT(78)
357 		DOIT(79) DOIT(80) DOIT(81) DOIT(82) DOIT(83) DOIT(84)
358 		DOIT(85) DOIT(86) DOIT(87) DOIT(88) DOIT(89) DOIT(90)
359 		DOIT(91) DOIT(92) DOIT(93) DOIT(94) DOIT(95) DOIT(96)
360 		DOIT(97) DOIT(98) DOIT(99) DOIT(100) DOIT(101) DOIT(102)
361 		DOIT(103) DOIT(104) DOIT(105) DOIT(106) DOIT(107)
362 		DOIT(108) DOIT(109) DOIT(110) DOIT(111) DOIT(112)
363 		DOIT(113) DOIT(114) DOIT(115) DOIT(116) DOIT(117)
364 		DOIT(118) DOIT(119) DOIT(120) DOIT(121) DOIT(122)
365 		DOIT(123) DOIT(124) DOIT(125) DOIT(126) p[127];
366 		p += 128;
367 	    }
368 	}
369 	use_int(sum);
370 }
371 #undef	DOIT
372 
373 void
fcp(iter_t iterations,void * cookie)374 fcp(iter_t iterations, void *cookie)
375 {
376 	state_t *state = (state_t *) cookie;
377 	register TYPE *lastone = state->lastone;
378 
379 	while (iterations-- > 0) {
380 	    register TYPE *p = state->buf;
381 	    register TYPE *dst = state->buf2;
382 	    while (p <= lastone) {
383 #define	DOIT(i)	dst[i]=p[i];
384 		DOIT(0) DOIT(1) DOIT(2) DOIT(3) DOIT(4) DOIT(5) DOIT(6)
385 		DOIT(7) DOIT(8) DOIT(9) DOIT(10) DOIT(11) DOIT(12)
386 		DOIT(13) DOIT(14) DOIT(15) DOIT(16) DOIT(17) DOIT(18)
387 		DOIT(19) DOIT(20) DOIT(21) DOIT(22) DOIT(23) DOIT(24)
388 		DOIT(25) DOIT(26) DOIT(27) DOIT(28) DOIT(29) DOIT(30)
389 		DOIT(31) DOIT(32) DOIT(33) DOIT(34) DOIT(35) DOIT(36)
390 		DOIT(37) DOIT(38) DOIT(39) DOIT(40) DOIT(41) DOIT(42)
391 		DOIT(43) DOIT(44) DOIT(45) DOIT(46) DOIT(47) DOIT(48)
392 		DOIT(49) DOIT(50) DOIT(51) DOIT(52) DOIT(53) DOIT(54)
393 		DOIT(55) DOIT(56) DOIT(57) DOIT(58) DOIT(59) DOIT(60)
394 		DOIT(61) DOIT(62) DOIT(63) DOIT(64) DOIT(65) DOIT(66)
395 		DOIT(67) DOIT(68) DOIT(69) DOIT(70) DOIT(71) DOIT(72)
396 		DOIT(73) DOIT(74) DOIT(75) DOIT(76) DOIT(77) DOIT(78)
397 		DOIT(79) DOIT(80) DOIT(81) DOIT(82) DOIT(83) DOIT(84)
398 		DOIT(85) DOIT(86) DOIT(87) DOIT(88) DOIT(89) DOIT(90)
399 		DOIT(91) DOIT(92) DOIT(93) DOIT(94) DOIT(95) DOIT(96)
400 		DOIT(97) DOIT(98) DOIT(99) DOIT(100) DOIT(101) DOIT(102)
401 		DOIT(103) DOIT(104) DOIT(105) DOIT(106) DOIT(107)
402 		DOIT(108) DOIT(109) DOIT(110) DOIT(111) DOIT(112)
403 		DOIT(113) DOIT(114) DOIT(115) DOIT(116) DOIT(117)
404 		DOIT(118) DOIT(119) DOIT(120) DOIT(121) DOIT(122)
405 		DOIT(123) DOIT(124) DOIT(125) DOIT(126) DOIT(127)
406 		p += 128;
407 		dst += 128;
408 	    }
409 	}
410 }
411 
412 void
loop_bzero(iter_t iterations,void * cookie)413 loop_bzero(iter_t iterations, void *cookie)
414 {
415 	state_t *state = (state_t *) cookie;
416 	register TYPE *p = state->buf;
417 	register size_t  N = state->N;
418 
419 	while (iterations-- > 0) {
420 		bzero(p, N);
421 	}
422 }
423 
424 void
loop_bcopy(iter_t iterations,void * cookie)425 loop_bcopy(iter_t iterations, void *cookie)
426 {
427 	state_t *state = (state_t *) cookie;
428 	register TYPE *p = state->buf;
429 	register TYPE *dst = state->buf2;
430 	register size_t  N = state->N;
431 
432 	while (iterations-- > 0) {
433 		bcopy(p,dst,N);
434 	}
435 }
436 
437 /*
438  * Almost like bandwidth() in lib_timing.c, but we need to adjust
439  * bandwidth based upon loop overhead.
440  */
adjusted_bandwidth(uint64 time,uint64 bytes,uint64 iter,double overhd)441 void adjusted_bandwidth(uint64 time, uint64 bytes, uint64 iter, double overhd)
442 {
443 #define MB	(1000. * 1000.)
444 	extern FILE *ftiming;
445 	double secs = ((double)time / (double)iter - overhd) / 1000000.0;
446 	double mb;
447 
448         mb = bytes / MB;
449 
450 	if (secs <= 0.)
451 		return;
452 
453         if (!ftiming) ftiming = stderr;
454 	if (mb < 1.) {
455 		(void) fprintf(ftiming, "%.6f ", mb);
456 	} else {
457 		(void) fprintf(ftiming, "%.2f ", mb);
458 	}
459 	if (mb / secs < 1.) {
460 		(void) fprintf(ftiming, "%.6f\n", mb/secs);
461 	} else {
462 		(void) fprintf(ftiming, "%.2f\n", mb/secs);
463 	}
464 }
465 
466 
467