Redis源代码分析(十一年)--- memtest内存测试

       今天,我们继续redis源代码test下测试在封装中的其它文件。今天读数memtest档,翻译了,那是,memory test 存储器测试工具。。可是里面的提及了非常多东西,也给我涨了非常多见识,网上关于memtest这样的类似的redis内部边缘的文件解析基本没有,所以自己从头開始学习。机器的内存检測会和机器的CPU位数有关,32位或64位会影响后面的一些宏定义參数。

首先亮出memtest中的API:

/* 内存检測API */
void memtest_progress_start(char *title, int pass) /* 内存检測载入開始,输出開始的一些图线显示 */
void memtest_progress_end(void) /* progress bar载入完再次清屏操作 */
void memtest_progress_step(size_t curr, size_t size, char c) /* progress填充自己设置的字符串 */
void memtest_addressing(unsigned long *l, size_t bytes) /* 地址检測方法 */
void memtest_fill_random(unsigned long *l, size_t bytes) /* 随机填充内存 */
void memtest_fill_value(unsigned long *l, size_t bytes, unsigned long v1, unsigned long v2, char sym) /* 像上面的方法,仅仅只是这是特定2种值的填充v1,v2 */
void memtest_compare(unsigned long *l, size_t bytes) /* 内存比較方法 */
void memtest_compare_times(unsigned long *m, size_t bytes, int pass, int times) /* 进行多次内存compare比較操作 */
void memtest_test(size_t megabytes, int passes) /* 整个内存检測类操作的測试方法,passes为目标的循环数 */
void memtest_non_destructive_invert(void *addr, size_t size) /* 将内存地址,进行了按位取反操作。不具有对数据的破坏性 */
void memtest_non_destructive_swap(void *addr, size_t size) /* 将内存地址,2个,2个内部之间做交换,相同不正确数据具有破坏性 */
void memtest(size_t megabytes, int passes) /* 开发给整个系统使用的内存检測方法 */

里面基本的方法就几个,每当一个内存检測的開始,都会出现progress bar的图线输出:

/* 内存检測载入開始,输出開始的一些图线显示 */
void memtest_progress_start(char *title, int pass) {
    int j;
	
	/*这里事实上包括2个命令。"\xlb[H","xlb[2j",后面的命令是基本的操作
	 *"\x1b" 是ESC的16进制ASCII码值,这里也可经表示成八进制的\033,
	 *[是一个CSI(Control sequence introducer),转义序列的作用由最后一个字符决定的,
	 *这里J表示删除,默认情况下它删除从当前光标处到行尾的内容,
	 *这里的2为參数,它表示删除全部的显示内容。

也能够使用printf "\x1b[2J"。*/ //现定位home最開始的位置。然后实现请屏幕操作 printf("\x1b[H\x1b[2J"); /* Cursor home, clear screen. */ /* Fill with dots. */ /* 输出.符号填充屏幕 */ for (j = 0; j < ws.ws_col*(ws.ws_row-2); j++) printf("."); printf("Please keep the test running several minutes per GB of memory.\n"); printf("Also check http://www.memtest86.com/ and http://pyropus.ca/software/memtester/"); //最后一个參数变了,为K,意义也不一样了变成删除当前行操作 printf("\x1b[H\x1b[2K"); /* Cursor home, clear current line. */ printf("%s [%d]\n", title, pass); /* Print title. */ progress_printed = 0; //求出填满progress bar所需点的个数 progress_full = ws.ws_col*(ws.ws_row-3); fflush(stdout); }


我在里面解释了一下清屏操作的。printf输出形式。

内存地址有效性的核心方法;

/* Test that addressing is fine. Every location is populated with its own
 * address, and finally verified. This test is very fast but may detect
 * ASAP big issues with the memory subsystem. */
/* 此方法是測试内存地址是否有效。此种检測的速度是很快的。但可能会检測出ASAP的巨大问题 */
/* ASAP网上查了下:(可能为)Automated Statistical Analysis Programme 自己主动统计分析程序 */
void memtest_addressing(unsigned long *l, size_t bytes) {
	//算出地址的长度
    unsigned long words = bytes/sizeof(unsigned long);
    unsigned long j, *p;

    /* Fill */
    p = l;
    for (j = 0; j < words; j++) {
    	//将(unsigned long)p强制类型转换到此时的*p,后面以此来推断,没有转换成功,说明存在内存地址的问题
        *p = (unsigned long)p;
        p++;
        //用A字符填充部分progress bar
        if ((j & 0xffff) == 0) memtest_progress_step(j,words*2,'A');
    }
    /* Test */
    p = l;
    for (j = 0; j < words; j++) {
    	//比較Address的关键在于
        if (*p != (unsigned long)p) {
            printf("\n*** MEMORY ADDRESSING ERROR: %p contains %lu\n",
                (void*) p, *p);
            exit(1);
        }
        p++;
        if ((j & 0xffff) == 0) memtest_progress_step(j+words,words*2,'A');
    }
}
为什么这个方案去检測。本人也是带着比較疑惑的感觉。在内存检測中,内存地址有效性的检查仅仅是当中的一个方法。另一个是内存地址的填充測试,分为随机填充。和给定值的填充。以下给出随机填充的方法实现:

/* Fill words stepping a single page at every write, so we continue to
 * touch all the pages in the smallest amount of time reducing the
 * effectiveness of caches, and making it hard for the OS to transfer
 * pages on the swap. */
/* 在每次写操作的时候,在单页上填满整个字符,这样能够做到最高速的触及全部的页面 */
/* 降低了低效率的缓存使用,可是会让分区在转移页面时会比較困难 */
/* 随机填充内存 */
void memtest_fill_random(unsigned long *l, size_t bytes) {
    unsigned long step = 4096/sizeof(unsigned long);
    unsigned long words = bytes/sizeof(unsigned long)/2;
    unsigned long iwords = words/step;  /* words per iteration */
    unsigned long off, w, *l1, *l2;

    assert((bytes & 4095) == 0);
    for (off = 0; off < step; off++) {
        l1 = l+off;
        l2 = l1+words;
        for (w = 0; w < iwords; w++) {
        	//以下的rand()达到了随机存储的目的
#ifdef MEMTEST_32BIT
            *l1 = *l2 = ((unsigned long)     (rand()&0xffff)) |
                        (((unsigned long)    (rand()&0xffff)) << 16);
#else
            *l1 = *l2 = ((unsigned long)     (rand()&0xffff)) |
                        (((unsigned long)    (rand()&0xffff)) << 16) |
                        (((unsigned long)    (rand()&0xffff)) << 32) |
                        (((unsigned long)    (rand()&0xffff)) << 48);
#endif
            l1 += step;
            l2 += step;
            if ((w & 0xffff) == 0)
                memtest_progress_step(w+iwords*off,words,'R');
        }
    }
}

填充内存的优点是訪问页面速度更快,不会出现断断续续的内存片。可是做页面交换的时候。因为没有空间,效率恐怕会比較低下。给定数值的填充与上面的类似,不展开说了。那么,内存測试程序究竟是測哪些东西的呢,也就是说,他这个文件开放给外部的一个最直接的test方法是什么呢?

/* 整个内存检測类操作的測试方法,passes为目标的循环数 */
void memtest_test(size_t megabytes, int passes) {
    size_t bytes = megabytes*1024*1024;
    unsigned long *m = malloc(bytes);
    int pass = 0;

    if (m == NULL) {
        fprintf(stderr,"Unable to allocate %zu megabytes: %s",
            megabytes, strerror(errno));
        exit(1);
    }
    
    //必须经过passes论循环測试
    while (pass != passes) {
        pass++;

		//地址检測
        memtest_progress_start("Addressing test",pass);
        memtest_addressing(m,bytes);
        memtest_progress_end();

		//随机填充检測
        memtest_progress_start("Random fill",pass);
        memtest_fill_random(m,bytes);
        memtest_progress_end();
        //填充后比較四次
        memtest_compare_times(m,bytes,pass,4);

		//给定数值填充,这里称为Solid fill固态填充
        memtest_progress_start("Solid fill",pass);
        memtest_fill_value(m,bytes,0,(unsigned long)-1,'S');
        memtest_progress_end();
        //填充后比較四次
        memtest_compare_times(m,bytes,pass,4);
		
		//也是属于给定数值填充,这里叫Checkerboard fill键盘填充
        memtest_progress_start("Checkerboard fill",pass);
        memtest_fill_value(m,bytes,ULONG_ONEZERO,ULONG_ZEROONE,'C');
        memtest_progress_end();
        //填充后比較四次
        memtest_compare_times(m,bytes,pass,4);
    }
    free(m);
}

能够看见,分为4中情况,1内存地址測试,2,3,4都为填充測试,分为3种类型的填充Random fill, Solid fill, Checkboard fill 。填充之后再做内存比較,这里的内存比較是在内存内部做前半部分的内存和后半部分的内存比較操作。在memtest文件的最后。提到了一个这个方案:

/* 开发给整个系统使用的内存检測方法 */
void memtest(size_t megabytes, int passes) {
    if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
        ws.ws_col = 80;
        ws.ws_row = 20;
    }
    memtest_test(megabytes,passes);
    printf("\nYour memory passed this test.\n");
    printf("Please if you are still in doubt use the following two tools:\n");
    printf("1) memtest86: http://www.memtest86.com/\n");
    printf("2) memtester: http://pyropus.ca/software/memtester/\n");
    exit(0);
}

这里提到了memtester和memtest86,上网查了一下,大体例如以下:

 * * memtest和memtest86是2款内存检測软件 
 * memtest不但能够彻底的检測出内存的稳定度,还可同一时候測试记忆的储存与检索数据的能力,让你能够确实掌控到眼下你机器上正在使用的内存究竟可不可信赖。 
 * MemTest是一个绿色软件。直接点击执行文件就可以执行 
 * memtest86这是一款小巧而专业的内存測试程序,是在著名的内存測试软件Memtest86基础上开发的。 
 * Memtest86+的安装和使用和其他内存測试软件有些不同,由于他不能在Windows下执行。


 * 只是还是有四种方式能够执行此程序,分别为ISO引导盘、Linux下使用的bin文件、
 * USB启动盘使用的EXE文件和软盘引导制作包。

因为Memtest86+測试耗时较长,因此它不仅能够用于内存測试,还能够用于系统稳定性測试。Memtest86+測试完成后,
 * 按“Esc”退出并重新启动系统。 

版权声明:本文博主原创文章。博客,未经同意不得转载。

posted @ 2015-10-28 08:04  mengfanrong  阅读(1102)  评论(0编辑  收藏  举报