Redis源码分析之内存检测memtest

62 篇文章 0 订阅
30 篇文章 0 订阅

redis的内存检测会和机器的CPU位数有关,32位或64位会影响后面的一些宏定义参数。首先给出memtest中的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) /* 开发给整个系统使用的内存检测方法 */

CPU位数的限制:

#if (ULONG_MAX == 4294967295UL)
#define MEMTEST_32BIT
#elif (ULONG_MAX == 18446744073709551615ULL)
#define MEMTEST_64BIT
#else
#error "ULONG_MAX value not supported."
#endif

以其中的接口为例进行说明:

memtest_progress_start:是内存检测开始的接口

内存检测加载开始,输出开始时一些图线显示,一般的test都会有这种显示

void memtest_progress_start(char *title, int pass) {
    int j;

    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/");
    printf("\x1b[H\x1b[2K");          /* Cursor home, clear current line.  */

    // 输出标题
    printf("%s [%d]\n", title, pass); /* Print title. */
    progress_printed = 0;

    // 填满进度条的算法
    progress_full = ws.ws_col*(ws.ws_row-3);
    fflush(stdout);
}

memtest_addressing:内测检测的核心算法。

主要看里面的注释部分,其中为什么这样设置,本人也是不理解,请高手留言,在此谢过..........

int memtest_addressing(unsigned long *l, size_t bytes, int interactive) {
    // 算出地址的len
    unsigned long words = bytes/sizeof(unsigned long);
    unsigned long j, *p;

    /* Fill */
    p = l;
    for (j = 0; j < words; j++) {
        // 取出p的地址再赋值给p
        *p = (unsigned long)p;
        p++;

        // 用'A'填充progress bar中符合该条件的位置
        if ((j & 0xffff) == 0 && interactive)
            memtest_progress_step(j,words*2,'A');
    }
    /* Test */
    p = l;
    for (j = 0; j < words; j++) {
        // address比较
        if (*p != (unsigned long)p) {
            if (interactive) {
                printf("\n*** MEMORY ADDRESSING ERROR: %p contains %lu\n",
                    (void*) p, *p);
                exit(1);
            }
            return 1;
        }
        p++;
        if ((j & 0xffff) == 0 && interactive)
            memtest_progress_step(j+words,words*2,'A');
    }
    return 0;
}

还有一种是随机填充memtest_fill_random:在每次写操作的时候,在单页上填满整个字符,这样可以做到最快速的触及所有的页面, 减少了低效率的缓存使用,但是会让分区在转移页面时会比较困难

void memtest_fill_random(unsigned long *l, size_t bytes, int interactive) {
    // 每次移动的步长
    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;
    uint64_t rseed = UINT64_C(0xd13133de9afdb566); /* Just a random seed. */
    uint64_t rout = 0;

    assert((bytes & 4095) == 0);
    for (off = 0; off < step; off++) {
        l1 = l+off;
        l2 = l1+words;
        for (w = 0; w < iwords; w++) {
            xorshift64star_next();

            // 填充l1 l2
            *l1 = *l2 = (unsigned long) rout;
            l1 += step;
            l2 += step;

            // 剩余部分填充R
            if ((w & 0xffff) == 0 && interactive)
                memtest_progress_step(w+iwords*off,words,'R');
        }
    }
}

开放给外界的方法:经过passes次的测试才能确定是否通过

int memtest_test(unsigned long *m, size_t bytes, int passes, int interactive) {
    int pass = 0;
    int errors = 0;

    // 运行passes 次
    while (pass != passes) {
        pass++;

        // address test
        if (interactive) memtest_progress_start("Addressing test",pass);
        errors += memtest_addressing(m,bytes,interactive);
        if (interactive) memtest_progress_end();

        // Random fill
        if (interactive) memtest_progress_start("Random fill",pass);
        memtest_fill_random(m,bytes,interactive);
        if (interactive) memtest_progress_end();
        errors += memtest_compare_times(m,bytes,pass,4,interactive);

        // 固定填充
        if (interactive) memtest_progress_start("Solid fill",pass);
        memtest_fill_value(m,bytes,0,(unsigned long)-1,'S',interactive);
        if (interactive) memtest_progress_end();
        errors += memtest_compare_times(m,bytes,pass,4,interactive);

        // 使用C字符填充测试
        if (interactive) memtest_progress_start("Checkerboard fill",pass);
        memtest_fill_value(m,bytes,ULONG_ONEZERO,ULONG_ZEROONE,'C',interactive);
        if (interactive) memtest_progress_end();
        errors += memtest_compare_times(m,bytes,pass,4,interactive);
    }
    return errors;
}

总之,内存测试分为4中情况,内存地址测试,其他都为填充测试,分为3种类型的填充Random fill, Solid fill, Checkboard fill 。填充之后再做内存比较,这里的内存比较是在内存内部做前半部分的内存和后半部分的内存比较操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值