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 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 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 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 321 void tstart(void) 322 { 323 gettimeofday(&_tstart, NULL); 324 } 325 326 void tend(void) 327 { 328 gettimeofday(&_tend, NULL); 329 } 330 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