对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 ", 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 ", buf); */

aligned = (void volatile *) ((size_t) buf & pagesizemask) + pagesize;

/* printf(" now 0x%tx -- lost %d bytes ", 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 ");

} else {

exit_code |= EXIT_FAIL_OTHERTEST;

}

fflush(stdout);

}

 

最核心的就是上面的这段代码,这段代码不断的调用测试的函数,不断的输出测试的报告。

不断调用的代码为:

if (!tests[i].fp(bufa, bufb, count)) {

这里利用了函数的指针,用法比较经典。

原文地址:https://www.cnblogs.com/pslfree/p/4451091.html