本文记录mbw测试原理及代码分析
1、mbw下载地址:
包含文件Makefile mbw mbw.1 mbw.c mbw.spec
2、mbw代码分析
/* mbw.c源码格函数解析*/ /* allocate a test array and fill it with data * so as to force Linux to _really_ allocate it */ long *make_array(unsigned long long asize) { unsigned long long t; unsigned int long_size=sizeof(long); long *a; //calloc是一个ISO C函数函数名: calloc函数原型:void *calloc(size_t n, size_t size);功 能: 在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。 a=calloc(asize, long_size); if(NULL==a) { perror("Error allocating memory"); exit(1); } /* make sure both arrays are allocated, fill with pattern */ for(t=0; t<asize; t++) { a[t]=0xaa; } return a; } ============================= /* actual benchmark */ /* asize: number of type 'long' elements in test arrays //测试数组中long型元素个数 * long_size: sizeof(long) cached //long型内存大小,即占几个字节 * type: 0=use memcpy, 1=use dumb copy loop (whatever GCC thinks best) * * return value: elapsed time in seconds */ double worker(unsigned long long asize, long *a, long *b, int type, unsigned long long block_size) { unsigned long long t; struct timeval starttime, endtime; //timeval结构体定义在time.h中,具体解析http://blog.csdn.net/yusiguyuan/article/details/21781839 double te; unsigned int long_size=sizeof(long); /* array size in bytes */ unsigned long long array_bytes=asize*long_size; if(type==1) { /* memcpy test */ /* timer starts */ gettimeofday(&starttime, NULL);//记录开始时间 memcpy(b, a, array_bytes);//拷贝array_bytes大小 内存 /* timer stops */ gettimeofday(&endtime, NULL);//记录结束时间 } else if(type==2) { /* memcpy block test */ gettimeofday(&starttime, NULL); for(t=0; t<array_bytes; t+=block_size) {//每次按照block_size 大小逐次拷贝 b=mempcpy(b, a, block_size); //void *memccpy(void *dest, const void *src, int c, size_t n);在两块不重叠的内存地址间复制内容,直至复制了n字节或遇到内容为c的字节 } if(t>array_bytes) { b=mempcpy(b, a, t-array_bytes); } gettimeofday(&endtime, NULL); } else { /* dumb test */ // gettimeofday(&starttime, NULL); for(t=0; t<asize; t++) { b[t]=a[t]; } gettimeofday(&endtime, NULL); } te=((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000; return te; } /* ------------------------------------------------------ */ /* pretty print worker's output in human-readable terms */ /* te: elapsed time in seconds * mt: amount of transferred data in MiB * type: see 'worker' above * * return value: - */ void printout(double te, double mt, int type) { switch(type) { case 0: printf("Method: MEMCPY\t"); break; case 1: printf("Method: DUMB\t"); break; case 2: printf("Method: MCBLOCK\t"); break; } printf("Elapsed: %.5f\t", te); printf("MiB: %.5f\t", mt); printf("Copy: %.3f MiB/s\n", mt/te); return; } /* ------------------------------------------------------ */ int main(int argc, char **argv) { unsigned int long_size=0; double te, te_sum; /* time elapsed */ unsigned long long asize=0; /* array size (elements in array) */ int i; long *a, *b; /* the two arrays to be copied from/to */ int o; /* getopt options */ unsigned long testno; /* options */ /* how many runs to average? */ int nr_loops=DEFAULT_NR_LOOPS; /* fixed memcpy block size for -t2 */ unsigned long long block_size=DEFAULT_BLOCK_SIZE; /* show average, -a */ int showavg=1; /* what tests to run (-t x) */ int tests[MAX_TESTS]; double mt=0; /* MiBytes transferred == array size in MiB */ int quiet=0; /* suppress extra messages */ tests[0]=0; tests[1]=0; tests[2]=0; while((o=getopt(argc, argv, "haqn:t:b:")) != EOF) { switch(o) { case 'h': usage(); exit(1); break; case 'a': /* suppress printing average */ showavg=0; break; case 'n': /* no. loops */ nr_loops=strtoul(optarg, (char **)NULL, 10); break; case 't': /* test to run */ testno=strtoul(optarg, (char **)NULL, 10); if(0>testno) { printf("Error: test number must be between 0 and %d\n", MAX_TESTS); exit(1); } tests[testno]=1; break; case 'b': /* block size in bytes*/ block_size=strtoull(optarg, (char **)NULL, 10); if(0>=block_size) { printf("Error: what block size do you mean?\n"); exit(1); } break; case 'q': /* quiet */ quiet=1; break; default: break; } } /* default is to run all tests if no specific tests were requested */ if( (tests[0]+tests[1]+tests[2]) == 0) { tests[0]=1; tests[1]=1; tests[2]=1; } if(optind<argc) { mt=strtoul(argv[optind++], (char **)NULL, 10); } else { printf("Error: no array size given!\n"); exit(1); } if(0>=mt) { printf("Error: array size wrong!\n"); exit(1); } /* ------------------------------------------------------ */ long_size=sizeof(long); /* the size of long on this platform */ asize=1024*1024/long_size*mt; /* how many longs then in one array? */ if(asize*long_size < block_size) { printf("Error: array size larger than block size (%llu bytes)!\n", block_size); exit(1); } if(!quiet) { printf("Long uses %d bytes. ", long_size); printf("Allocating 2*%lld elements = %lld bytes of memory.\n", asize, 2*asize*long_size); if(tests[2]) { printf("Using %lld bytes as blocks for memcpy block copy test.\n", block_size); } } a=make_array(asize); b=make_array(asize); /* ------------------------------------------------------ */ if(!quiet) { printf("Getting down to business... Doing %d runs per test.\n", nr_loops); } /* run all tests requested, the proper number of times */ for(testno=0; testno<MAX_TESTS; testno++) { te_sum=0; if(tests[testno]) { for (i=0; i<nr_loops; i++) { te=worker(asize, a, b, testno, block_size); te_sum+=te; printf("%d\t", i); printout(te, mt, testno); } if(showavg) { printf("AVG\t"); printout(te_sum/nr_loops, mt, testno); } } } free(a); free(b); return 0; }