/* Memory streaming benchmark */ /* * Copyright (C) 2003-2006 IBM * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #define __int64 long long #include <sys/time.h> #define SLASHC '/' #define SLASHSTR "/" #include <sys/types.h> #include <string.h> #include <stddef.h> #include <stdlib.h> #include <stdio.h> #include <ctype.h> #define equal !strcmp size_t atoik(char *); void *Malloc(size_t sz); void tstart(void); void tend(void); double tval(void); char *methods[] = { "\"memcpy\"", "\"char *\"", "\"short *\"", "\"int *\"", "\"long *\"", "\"__int64 *\"", "\"double *\"", }; int nmethods = sizeof(methods) / sizeof(methods[0]); int fflag = 0; // if 0, then just Malloc once; else malloc/free each time int wflag = 0; // if 1, call SetProcessWorkingSetSize() (WINDOWS ONLY) int sflag = 0; // if 1, only print averages. int pflag = 0; int csvflag = 0; // Print Comma separated list for spreadsheet input. char *progname; double tottim = 0.0; int main(int ac, char *av[]) { size_t size; int i; unsigned ui; size_t j; unsigned cnt; int method = 0; char *p1, *p2; char *p, *q; short *sp, *sq; int *ip, *iq; long *lp, *lq; __int64 *llp, *llq; double *dp, *dq; double t; progname = av[0]; if (strrchr(progname, SLASHC)) progname = strrchr(progname, SLASHC) + 1; while (ac > 1) { if (equal(av[1], "-f")) { ac--; fflag = 1; av++; } else if (equal(av[1], "-w")) { ac--; wflag = 1; av++; } else if (equal(av[1], "-s")) { ac--; sflag = 1; av++; } else if (equal(av[1], "-p")) { ac--; pflag = 1; av++; } else if (equal(av[1], "-csv")) { ac--; csvflag++; av++; } else break; } if (ac < 3) { (void) printf("Usage: %s [-f] [-w] [-s] [-p] size cnt [method]\n", progname); (void) printf ("\t-f flag says to malloc and free of the \"cnt\" times.\n"); (void) printf ("\t-w = set process min and max working set size to \"size\"\n"); (void)printf("\t-s = silent; only print averages\n"); (void) printf ("\t-p = prep; \"freshen\" cache before; -w disables\n"); (void)printf("\t-csv = print output in CSV format\n"); (void)printf("\tmethods:\n"); for (i = 0; i < nmethods; i++) printf("\t%2d:\t%s\n", i, methods[i]); return 0; } size = atoik(av[1]); // // Round size up to 4*sizeof(double) bytes. // if (size != ((size / (4 * sizeof(double))) * (4 * sizeof(double)))) { size += (4 * sizeof(double)); size /= (4 * sizeof(double)); size *= (4 * sizeof(double)); } cnt = (unsigned)atoik(av[2]); if (fflag == 0) { p1 = (char *)Malloc(size); p2 = (char *)Malloc(size); if (pflag) memcpy(p1, p2, size); } printf("%s ", progname); if (fflag) printf("-f "); if (wflag) printf("-w "); if (sflag) printf("-s "); if (pflag) printf("-p "); if (csvflag) printf("-csv "); printf("%u %u ", size, cnt); if (csvflag) { printf("Linux"); } printf("\n"); if (ac == 3) { ac = 4; av[3] = "0"; } for (; ac > 3; ac--, av++) { if (isdigit(*av[3])) method = *av[3] - '0'; if (method < 0 || method >= nmethods) method = 0; if (sflag) tstart(); for (ui = 0; ui < cnt; ui++) { if (!sflag) { (void)printf("%s %d %d %-18.18s\t", progname, size, cnt, methods[method]); tstart(); } if (fflag == 1) { p1 = (char *)Malloc(size); p2 = (char *)Malloc(size); } switch (method) { case 0: (void)memcpy(p1, p2, size); break; case 1: p = p1; q = p2; for (j = 0; j < size; j++) *p++ = *q++; break; case 2: sp = (short *)p1; sq = (short *)p2; for (j = 0; j < size; j += sizeof(short)) *sp++ = *sq++; break; case 3: ip = (int *)p1; iq = (int *)p2; for (j = 0; j < size; j += sizeof(int)) *ip++ = *iq++; break; case 4: lp = (long *)p1; lq = (long *)p2; for (j = 0; j < size; j += sizeof(long)) *lp++ = *lq++; break; case 5: llp = (__int64 *) p1; llq = (__int64 *) p2; for (j = 0; j < size; j += sizeof(__int64)) *llp++ = *llq++; break; case 6: dp = (double *)p1; dq = (double *)p2; for (j = 0; j < size; j += 4 * sizeof(double)) { *dp++ = *dq++; *dp++ = *dq++; *dp++ = *dq++; *dp++ = *dq++; } break; } if (fflag == 1) { free(p1); free(p2); } if (!sflag) { tend(); t = tval(); tottim += t; if (t == 0.0) t = .0001; printf(" %8.6f seconds %8.3f MB/s\n", t, (double)size / t / 1000000.); } } if (sflag) { tend(); tottim = tval(); } if (csvflag) { printf("%s,%u,%u,%8.3f,%8.3f\n", methods[method], size, size * cnt, tottim, (double)size / (tottim / cnt) / 1000000.); } else { (void)printf("\tAVG: %d %-18.18s\t", size, methods[method]); (void)printf(" %8.3f MB/s\n", (double)size / (tottim / cnt) / 1000000.); } tottim = 0.0; } return 0; } size_t atoik(char *s) { size_t ret = 0; size_t base; if (*s == '0') { base = 8; if (*++s == 'x' || *s == 'X') { base = 16; s++; } } else base = 10; for (; isxdigit(*s); s++) { if (base == 16) if (isalpha(*s)) ret = base * ret + (toupper(*s) - 'A'); else ret = base * ret + (*s - '0'); else if (isdigit(*s)) ret = base * ret + (*s - '0'); else break; } for (; isalpha(*s); s++) { switch (toupper(*s)) { case 'K': ret *= 1024; break; case 'M': ret *= 1024 * 1024; break; default: return ret; } } return ret; } void *Malloc(size_t sz) { char *p; p = (char *)malloc(sz); if (p == NULL) { (void)printf("malloc(%d) failed\n", sz); exit(1); } return (void *)p; } static struct timeval _tstart, _tend; void tstart(void) { gettimeofday(&_tstart, NULL); } void tend(void) { gettimeofday(&_tend, NULL); } double tval() { double t1, t2; t1 = (double)_tstart.tv_sec + (double)_tstart.tv_usec / (1000 * 1000); t2 = (double)_tend.tv_sec + (double)_tend.tv_usec / (1000 * 1000); return t2 - t1; }