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