1 /* Memory streaming benchmark */
2
3 /*
4 * Copyright (C) 2003-2006 IBM
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22 #define __int64 long long
23 #include <sys/time.h>
24 #define SLASHC '/'
25 #define SLASHSTR "/"
26 #include <sys/types.h>
27 #include <string.h>
28 #include <stddef.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <ctype.h>
32
33 #define equal !strcmp
34
35 size_t atoik(char *);
36 void *Malloc(size_t sz);
37 void tstart(void);
38 void tend(void);
39 double tval(void);
40
41 char *methods[] = {
42 "\"memcpy\"",
43 "\"char *\"",
44 "\"short *\"",
45 "\"int *\"",
46 "\"long *\"",
47 "\"__int64 *\"",
48 "\"double *\"",
49 };
50
51 int nmethods = sizeof(methods) / sizeof(methods[0]);
52
53 int fflag = 0; // if 0, then just Malloc once; else malloc/free each time
54 int wflag = 0; // if 1, call SetProcessWorkingSetSize() (WINDOWS ONLY)
55 int sflag = 0; // if 1, only print averages.
56 int pflag = 0;
57 int csvflag = 0; // Print Comma separated list for spreadsheet input.
58 char *progname;
59
60 double tottim = 0.0;
61
main(int ac,char * av[])62 int main(int ac, char *av[])
63 {
64 size_t size;
65 int i;
66 unsigned ui;
67 size_t j;
68 unsigned cnt;
69 int method = 0;
70 char *p1, *p2;
71 char *p, *q;
72 short *sp, *sq;
73 int *ip, *iq;
74 long *lp, *lq;
75 __int64 *llp, *llq;
76 double *dp, *dq;
77 double t;
78
79 progname = av[0];
80 if (strrchr(progname, SLASHC))
81 progname = strrchr(progname, SLASHC) + 1;
82
83 while (ac > 1) {
84 if (equal(av[1], "-f")) {
85 ac--;
86 fflag = 1;
87 av++;
88 } else if (equal(av[1], "-w")) {
89 ac--;
90 wflag = 1;
91 av++;
92 } else if (equal(av[1], "-s")) {
93 ac--;
94 sflag = 1;
95 av++;
96 } else if (equal(av[1], "-p")) {
97 ac--;
98 pflag = 1;
99 av++;
100 } else if (equal(av[1], "-csv")) {
101 ac--;
102 csvflag++;
103 av++;
104 } else
105 break;
106 }
107 if (ac < 3) {
108 (void)
109 printf("Usage: %s [-f] [-w] [-s] [-p] size cnt [method]\n",
110 progname);
111 (void)
112 printf
113 ("\t-f flag says to malloc and free of the \"cnt\" times.\n");
114 (void)
115 printf
116 ("\t-w = set process min and max working set size to \"size\"\n");
117 (void)printf("\t-s = silent; only print averages\n");
118 (void)
119 printf
120 ("\t-p = prep; \"freshen\" cache before; -w disables\n");
121 (void)printf("\t-csv = print output in CSV format\n");
122
123 (void)printf("\tmethods:\n");
124 for (i = 0; i < nmethods; i++)
125 printf("\t%2d:\t%s\n", i, methods[i]);
126 return 0;
127 }
128
129 size = atoik(av[1]);
130
131 //
132 // Round size up to 4*sizeof(double) bytes.
133 //
134 if (size != ((size / (4 * sizeof(double))) * (4 * sizeof(double)))) {
135 size += (4 * sizeof(double));
136 size /= (4 * sizeof(double));
137 size *= (4 * sizeof(double));
138 }
139 cnt = (unsigned)atoik(av[2]);
140
141 if (fflag == 0) {
142 p1 = (char *)Malloc(size);
143 p2 = (char *)Malloc(size);
144 if (pflag)
145 memcpy(p1, p2, size);
146 }
147
148 printf("%s ", progname);
149 if (fflag)
150 printf("-f ");
151 if (wflag)
152 printf("-w ");
153 if (sflag)
154 printf("-s ");
155 if (pflag)
156 printf("-p ");
157 if (csvflag)
158 printf("-csv ");
159 printf("%u %u ", size, cnt);
160 if (csvflag) {
161 printf("Linux");
162 }
163 printf("\n");
164
165 if (ac == 3) {
166 ac = 4;
167 av[3] = "0";
168 }
169
170 for (; ac > 3; ac--, av++) {
171 if (isdigit(*av[3]))
172 method = *av[3] - '0';
173 if (method < 0 || method >= nmethods)
174 method = 0;
175 if (sflag)
176 tstart();
177 for (ui = 0; ui < cnt; ui++) {
178 if (!sflag) {
179 (void)printf("%s %d %d %-18.18s\t",
180 progname, size, cnt,
181 methods[method]);
182 tstart();
183 }
184 if (fflag == 1) {
185 p1 = (char *)Malloc(size);
186 p2 = (char *)Malloc(size);
187 }
188 switch (method) {
189 case 0:
190 (void)memcpy(p1, p2, size);
191 break;
192 case 1:
193 p = p1;
194 q = p2;
195 for (j = 0; j < size; j++)
196 *p++ = *q++;
197 break;
198 case 2:
199 sp = (short *)p1;
200 sq = (short *)p2;
201 for (j = 0; j < size; j += sizeof(short))
202 *sp++ = *sq++;
203 break;
204 case 3:
205 ip = (int *)p1;
206 iq = (int *)p2;
207 for (j = 0; j < size; j += sizeof(int))
208 *ip++ = *iq++;
209 break;
210 case 4:
211 lp = (long *)p1;
212 lq = (long *)p2;
213 for (j = 0; j < size; j += sizeof(long))
214 *lp++ = *lq++;
215 break;
216 case 5:
217 llp = (__int64 *) p1;
218 llq = (__int64 *) p2;
219 for (j = 0; j < size; j += sizeof(__int64))
220 *llp++ = *llq++;
221 break;
222 case 6:
223 dp = (double *)p1;
224 dq = (double *)p2;
225 for (j = 0; j < size; j += 4 * sizeof(double)) {
226 *dp++ = *dq++;
227 *dp++ = *dq++;
228 *dp++ = *dq++;
229 *dp++ = *dq++;
230 }
231 break;
232
233 }
234 if (fflag == 1) {
235 free(p1);
236 free(p2);
237 }
238 if (!sflag) {
239 tend();
240 t = tval();
241 tottim += t;
242 if (t == 0.0)
243 t = .0001;
244 printf(" %8.6f seconds %8.3f MB/s\n",
245 t, (double)size / t / 1000000.);
246 }
247 }
248 if (sflag) {
249 tend();
250 tottim = tval();
251 }
252 if (csvflag) {
253 printf("%s,%u,%u,%8.3f,%8.3f\n",
254 methods[method], size, size * cnt, tottim,
255 (double)size / (tottim / cnt) / 1000000.);
256 } else {
257 (void)printf("\tAVG: %d %-18.18s\t", size,
258 methods[method]);
259 (void)printf(" %8.3f MB/s\n",
260 (double)size / (tottim / cnt) / 1000000.);
261 }
262 tottim = 0.0;
263 }
264 return 0;
265 }
266
atoik(char * s)267 size_t atoik(char *s)
268 {
269 size_t ret = 0;
270 size_t base;
271
272 if (*s == '0') {
273 base = 8;
274 if (*++s == 'x' || *s == 'X') {
275 base = 16;
276 s++;
277 }
278 } else
279 base = 10;
280
281 for (; isxdigit(*s); s++) {
282 if (base == 16)
283 if (isalpha(*s))
284 ret = base * ret + (toupper(*s) - 'A');
285 else
286 ret = base * ret + (*s - '0');
287 else if (isdigit(*s))
288 ret = base * ret + (*s - '0');
289 else
290 break;
291 }
292 for (; isalpha(*s); s++) {
293 switch (toupper(*s)) {
294 case 'K':
295 ret *= 1024;
296 break;
297 case 'M':
298 ret *= 1024 * 1024;
299 break;
300 default:
301 return ret;
302 }
303 }
304 return ret;
305 }
306
Malloc(size_t sz)307 void *Malloc(size_t sz)
308 {
309 char *p;
310
311 p = (char *)malloc(sz);
312 if (p == NULL) {
313 (void)printf("malloc(%d) failed\n", sz);
314 exit(1);
315 }
316 return (void *)p;
317 }
318
319 static struct timeval _tstart, _tend;
320
tstart(void)321 void tstart(void)
322 {
323 gettimeofday(&_tstart, NULL);
324 }
325
tend(void)326 void tend(void)
327 {
328 gettimeofday(&_tend, NULL);
329 }
330
tval()331 double tval()
332 {
333 double t1, t2;
334
335 t1 = (double)_tstart.tv_sec + (double)_tstart.tv_usec / (1000 * 1000);
336 t2 = (double)_tend.tv_sec + (double)_tend.tv_usec / (1000 * 1000);
337 return t2 - t1;
338 }
339