#include #include #include #include #include #include #include #include #include char * volatile src, * volatile dst; #define CHECK(x) do{ \ errno=0; \ if(!(x)) { \ fprintf(stderr,"%s:%d: %s failed -- %s\n", \ __FILE__, __LINE__, #x, strerror(errno)); \ abort(); } }while(0) double now (void) { struct timeval tv; gettimeofday(&tv,0); return tv.tv_sec + 1e-6 * tv.tv_usec; } extern void memcpy_gcc (char * restrict d, const char * restrict s, size_t n); extern void memcpy_clang (char * restrict d, const char * restrict s, size_t n); static inline void movsb(void *d, const void *s, size_t n) { asm volatile ("rep movsb" : "=D" (d), "=S" (s), "=c" (n) : "0" (d), "1" (s), "2" (n) : "memory"); } char *fmt_uint (unsigned long long x, char *buf) { char tmp[80]; /* sic! */ size_t i, j, n; snprintf(tmp,sizeof(tmp)-1,"%llu",x); n = strlen(tmp); j = 0; for(i = 0; i < n; i++) { if (i && (n-i)%3 == 0) buf[j++]=','; buf[j++] = tmp[i]; } buf[j]=0; return buf; } char *meth_name[] = { "for loop", "for loop", "rep movsb", "memcpy" }; char *meth_name2[] = { "gcc", "clang", "", "" }; #define N_METH ((sizeof(meth_name)/sizeof(meth_name[0]))-1) volatile int had_alarm; void alarm_handler (int ignore) { (void)ignore; had_alarm = 1; } double bench_1 (int meth, size_t sz) { double t1; int rep = 10; CHECK (src = malloc(sz)); CHECK (dst = malloc(sz)); memset(src,1,sz); memset(dst,2,sz); signal(SIGALRM,alarm_handler); had_alarm = 0; alarm(1); rep = 0; t1 = now(); switch (meth) { case 0: while(!had_alarm) { memcpy_gcc(dst,src,sz); rep++; } break; case 1: while(!had_alarm) { memcpy_clang(dst,src,sz); rep++; } break; case 2: while(!had_alarm) { movsb(dst,src,sz); rep++; } break; case 3: while(!had_alarm) { memcpy(dst,src,sz); rep++; } break; } t1 = now() - t1; CHECK(0 == memcmp(dst,src,sz)); free(src); free(dst); return t1 / rep; } void bench (size_t sz) { char b1[80], b2[80]; double ti [N_METH]; int i; sz = 64 * ((sz+63)/64); /* Hmm */ for (i = 0; i < N_METH; i++) ti[i] = bench_1(i, sz); int winner = 0; for (i = 0; i < N_METH; i++) if (ti[i] < ti[winner]) winner = i; printf("%16s octets ", fmt_uint(sz,b1)); for (i = 0; i < N_METH; i++) printf ("%11s MB/s %s", fmt_uint(((sz)/ti[i])/1024/1024, b2), (i==winner)?"*":" "); printf("\n"); fflush(stdout); } size_t e12_series [] = { 10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82 }; size_t e12 (int x) { if (x >= 12) return 10 * e12(x-12); else return e12_series[x]; } int main (void) { int i; printf("%16s ",""); for (i = 0; i < N_METH; i++) printf("%16s ", meth_name[i]); printf("\n"); printf("%16s ",""); for (i = 0; i < N_METH; i++) printf("%16s ", meth_name2[i]); printf("\n"); for(i=0;i < 79;i++)printf("-"); printf("\n"); for (i = 1*12; i < 7*12; i+=1) bench (e12(i)); printf("\n'*' marks the fastest.\n"); return 0; }