对memtester源码分析
测试环境:Linux
代码工具:source insight
Memtester版本:4.3.0
下载地址: http://pyropus.ca/software/memtester/
Memtester是一个很好的内存测试工具。其代码也不是很复杂。最主要的就是memtester.c和test.c,这两文件。其他脚本是一些配置编译选项,对分析这个源码没有什么影响。
我们先从memtester.c开始分析。
在memtester.c的134行中有
check_posix_system();
pagesize = memtester_pagesize();
pagesizemask = (ptrdiff_t) ~(pagesize - 1);
printf("pagesizemask is 0x%tx\n", pagesizemask);
check_posix_system是确认所测试的系统支不支持标准的POSIX接口。下面很多函数需要用到标准的接口,如果不支持,则只有error。
memtester_pagesize是用接口测试系统是32位还是64位,这涉及到其后的很多方方面面。
Pagesizemask是得出最大的地址范围。
下面很重要的就是:
while ((opt = getopt(argc, argv, "p:d:")) != -1) {
这句话是用来处理用户输入的数据的。关于getopt函数的解析,后面会有地址链接。
case 'p': 是用来处理-p后面的参数的。
physaddrbase = (off_t) strtoull(optarg, &addrsuffix, 16);
上面这句话是将-p后面的参数转化数字并赋值给physaddrbase
下面的就是一些错误处理。
case 'd': 是用来处理-d后面的参数的。
if (stat(optarg,&statbuf)) {
上面这句话是用来获取所指定设备的参数细节的。
接下来到203行
if (device_specified && !use_phys) {
这句话的意思是如果有-d选项,必须要有-p选项,否者就会出错。
接下来就是处理错误和获取最后内存大小的参数。
wantraw = (size_t) strtoul(argv[optind], &memsuffix, 0);
上面的代码是将输入的参数转化为数字,并且赋值给wantraw.其后就是对这个参数的单位的处理。
最后 wantmb = (wantbytes_orig >> 20); 将单位转化为M并赋值给wantmb。
248-243行基本上是处理错误和获取循环的次数。最后输出。
接下来代码分为两块 一块为有-p选项的处理方法。一块为没有-p选项的处理方法。
最先处理的是有-p选项的情况。
其中最重要的代码为:
buf = (void volatile *) mmap(0, wantbytes, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_LOCKED, memfd,
physaddrbase);
这一行是将内存的具体地址映射到具体的进程地址空间里面。这样便于处理其后的操作。具体每个参数的含义,其后会有讲解。
其余的代码就是处理错误的情况。并且给申请到的内存加锁。加锁的原因是避免操作系统对内存进行一下操作。
下面的:
while (!done_mem) {
就是处理没有-p选项的情况。
buf = (void volatile *) malloc(wantbytes); 这句话是申请内存。
余下的最重要的操作就是对齐和加锁了。关于对齐的原因是内存是以一块一块来申请和释放的。
if ((size_t) buf % pagesize) {
/* printf("aligning to page -- was 0x%tx\n", buf); */
aligned = (void volatile *) ((size_t) buf & pagesizemask) + pagesize;
/* printf(" now 0x%tx -- lost %d bytes\n", aligned,
* (size_t) aligned - (size_t) buf);
*/
bufsize -= ((size_t) aligned - (size_t) buf);
}
上面就是对齐的代码。
if (mlock((void *) aligned, bufsize) < 0) {
加锁的代码很简单,其余的都是处理错误的代码。
到375行 进入正式的循环。 for(loop=1; ((!loops) || loop <= loops); loop++) {
第一个分开测试的是 test_stuck_address
这个比较简单 就是先在申请的内存里面写入数据,然后读出来与其对比。这样反复对比16次。
for (i=0;;i++) {
if (!tests[i].name) break;
/* If using a custom testmask, only run this test if the
bit corresponding to this test was set by the user.
*/
if (testmask && (!((1 << i) & testmask))) {
continue;
}
printf(" %-20s: ", tests[i].name);
if (!tests[i].fp(bufa, bufb, count)) {
printf("ok\n");
} else {
exit_code |= EXIT_FAIL_OTHERTEST;
}
fflush(stdout);
}
最核心的就是上面的这段代码,这段代码不断的调用测试的函数,不断的输出测试的报告。
不断调用的代码为:
if (!tests[i].fp(bufa, bufb, count)) {
这里利用了函数的指针,用法比较经典。