]>
git.saurik.com Git - redis.git/blob - src/memtest.c
   2  * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com> 
   5  * Redistribution and use in source and binary forms, with or without 
   6  * modification, are permitted provided that the following conditions are met: 
   8  *   * Redistributions of source code must retain the above copyright notice, 
   9  *     this list of conditions and the following disclaimer. 
  10  *   * Redistributions in binary form must reproduce the above copyright 
  11  *     notice, this list of conditions and the following disclaimer in the 
  12  *     documentation and/or other materials provided with the distribution. 
  13  *   * Neither the name of Redis nor the names of its contributors may be used 
  14  *     to endorse or promote products derived from this software without 
  15  *     specific prior written permission. 
  17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  27  * POSSIBILITY OF SUCH DAMAGE. 
  37 #include <sys/ioctl.h> 
  40 #if (ULONG_MAX == 4294967295UL) 
  42 #elif (ULONG_MAX == 18446744073709551615ULL) 
  45 #error "ULONG_MAX value not supported." 
  49 #define ULONG_ONEZERO 0xaaaaaaaaUL 
  50 #define ULONG_ZEROONE 0x55555555UL 
  52 #define ULONG_ONEZERO 0xaaaaaaaaaaaaaaaaUL 
  53 #define ULONG_ZEROONE 0x5555555555555555UL 
  56 static struct winsize ws
; 
  57 size_t progress_printed
; /* Printed chars in screen-wide progress bar. */ 
  58 size_t progress_full
; /* How many chars to write to fill the progress bar. */ 
  60 void memtest_progress_start(char *title
, int pass
) { 
  63     printf("\x1b[H\x1b[2J");    /* Cursor home, clear screen. */ 
  65     for (j 
= 0; j 
< ws
.ws_col
*(ws
.ws_row
-2); j
++) printf("."); 
  66     printf("Please keep the test running several minutes per GB of memory.\n"); 
  67     printf("Also check http://www.memtest86.com/ and http://pyropus.ca/software/memtester/"); 
  68     printf("\x1b[H\x1b[2K");          /* Cursor home, clear current line.  */ 
  69     printf("%s [%d]\n", title
, pass
); /* Print title. */ 
  71     progress_full 
= ws
.ws_col
*(ws
.ws_row
-3); 
  75 void memtest_progress_end(void) { 
  76     printf("\x1b[H\x1b[2J");    /* Cursor home, clear screen. */ 
  79 void memtest_progress_step(size_t curr
, size_t size
, char c
) { 
  80     size_t chars 
= ((unsigned long long)curr
*progress_full
)/size
, j
; 
  82     for (j 
= 0; j 
< chars
-progress_printed
; j
++) { 
  89 /* Test that addressing is fine. Every location is populated with its own 
  90  * address, and finally verified. This test is very fast but may detect 
  91  * ASAP big issues with the memory subsystem. */ 
  92 void memtest_addressing(unsigned long *l
, size_t bytes
) { 
  93     unsigned long words 
= bytes
/sizeof(unsigned long); 
  98     for (j 
= 0; j 
< words
; j
++) { 
  99         *p 
= (unsigned long)p
; 
 101         if ((j 
& 0xffff) == 0) memtest_progress_step(j
,words
*2,'A'); 
 105     for (j 
= 0; j 
< words
; j
++) { 
 106         if (*p 
!= (unsigned long)p
) { 
 107             printf("\n*** MEMORY ADDRESSING ERROR: %p contains %lu\n", 
 112         if ((j 
& 0xffff) == 0) memtest_progress_step(j
+words
,words
*2,'A'); 
 116 /* Fill words stepping a single page at every write, so we continue to 
 117  * touch all the pages in the smallest amount of time reducing the 
 118  * effectiveness of caches, and making it hard for the OS to transfer 
 119  * pages on the swap. */ 
 120 void memtest_fill_random(unsigned long *l
, size_t bytes
) { 
 121     unsigned long step 
= 4096/sizeof(unsigned long); 
 122     unsigned long words 
= bytes
/sizeof(unsigned long)/2; 
 123     unsigned long iwords 
= words
/step
;  /* words per iteration */ 
 124     unsigned long off
, w
, *l1
, *l2
; 
 126     assert((bytes 
& 4095) == 0); 
 127     for (off 
= 0; off 
< step
; off
++) { 
 130         for (w 
= 0; w 
< iwords
; w
++) { 
 132             *l1 
= *l2 
= ((unsigned long)     (rand()&0xffff)) | 
 133                         (((unsigned long)    (rand()&0xffff)) << 16); 
 135             *l1 
= *l2 
= ((unsigned long)     (rand()&0xffff)) | 
 136                         (((unsigned long)    (rand()&0xffff)) << 16) | 
 137                         (((unsigned long)    (rand()&0xffff)) << 32) | 
 138                         (((unsigned long)    (rand()&0xffff)) << 48); 
 142             if ((w 
& 0xffff) == 0) 
 143                 memtest_progress_step(w
+iwords
*off
,words
,'R'); 
 148 /* Like memtest_fill_random() but uses the two specified values to fill 
 149  * memory, in an alternated way (v1|v2|v1|v2|...) */ 
 150 void memtest_fill_value(unsigned long *l
, size_t bytes
, unsigned long v1
, 
 151                         unsigned long v2
, char sym
) 
 153     unsigned long step 
= 4096/sizeof(unsigned long); 
 154     unsigned long words 
= bytes
/sizeof(unsigned long)/2; 
 155     unsigned long iwords 
= words
/step
;  /* words per iteration */ 
 156     unsigned long off
, w
, *l1
, *l2
, v
; 
 158     assert((bytes 
& 4095) == 0); 
 159     for (off 
= 0; off 
< step
; off
++) { 
 162         v 
= (off 
& 1) ? v2 
: v1
; 
 163         for (w 
= 0; w 
< iwords
; w
++) { 
 165             *l1 
= *l2 
= ((unsigned long)     v
) | 
 166                         (((unsigned long)    v
) << 16); 
 168             *l1 
= *l2 
= ((unsigned long)     v
) | 
 169                         (((unsigned long)    v
) << 16) | 
 170                         (((unsigned long)    v
) << 32) | 
 171                         (((unsigned long)    v
) << 48); 
 175             if ((w 
& 0xffff) == 0) 
 176                 memtest_progress_step(w
+iwords
*off
,words
,sym
); 
 181 void memtest_compare(unsigned long *l
, size_t bytes
) { 
 182     unsigned long words 
= bytes
/sizeof(unsigned long)/2; 
 183     unsigned long w
, *l1
, *l2
; 
 185     assert((bytes 
& 4095) == 0); 
 188     for (w 
= 0; w 
< words
; w
++) { 
 190             printf("\n*** MEMORY ERROR DETECTED: %p != %p (%lu vs %lu)\n", 
 191                 (void*)l1
, (void*)l2
, *l1
, *l2
); 
 196         if ((w 
& 0xffff) == 0) memtest_progress_step(w
,words
,'='); 
 200 void memtest_compare_times(unsigned long *m
, size_t bytes
, int pass
, int times
) { 
 203     for (j 
= 0; j 
< times
; j
++) { 
 204         memtest_progress_start("Compare",pass
); 
 205         memtest_compare(m
,bytes
); 
 206         memtest_progress_end(); 
 210 void memtest_test(size_t megabytes
, int passes
) { 
 211     size_t bytes 
= megabytes
*1024*1024; 
 212     unsigned long *m 
= malloc(bytes
); 
 216         fprintf(stderr
,"Unable to allocate %zu megabytes: %s", 
 217             megabytes
, strerror(errno
)); 
 220     while (pass 
!= passes
) { 
 223         memtest_progress_start("Addressing test",pass
); 
 224         memtest_addressing(m
,bytes
); 
 225         memtest_progress_end(); 
 227         memtest_progress_start("Random fill",pass
); 
 228         memtest_fill_random(m
,bytes
); 
 229         memtest_progress_end(); 
 230         memtest_compare_times(m
,bytes
,pass
,4); 
 232         memtest_progress_start("Solid fill",pass
); 
 233         memtest_fill_value(m
,bytes
,0,(unsigned long)-1,'S'); 
 234         memtest_progress_end(); 
 235         memtest_compare_times(m
,bytes
,pass
,4); 
 237         memtest_progress_start("Checkerboard fill",pass
); 
 238         memtest_fill_value(m
,bytes
,ULONG_ONEZERO
,ULONG_ZEROONE
,'C'); 
 239         memtest_progress_end(); 
 240         memtest_compare_times(m
,bytes
,pass
,4); 
 244 /* This is a fast O(N) best effort memory test, only ZERO-ONE tests and 
 245  * checkerboard tests are performed, without pauses between setting and 
 246  * reading the value, so this can only detect a subclass of permanent errors. 
 248  * However the function does not destroy the content of the memory tested that 
 249  * is left unmodified. 
 251  * If a memory error is detected, 1 is returned. Otherwise 0 is returned. */ 
 252 int memtest_non_destructive(void *addr
, size_t size
) { 
 253     volatile unsigned long *p 
= addr
; 
 257     size 
/= sizeof(unsigned long); 
 258     for (j 
= 0; j 
< size
; j
++) { 
 261         p
[j
] = 0; if (p
[j
] != 0) goto err
; 
 262         p
[j
] = (unsigned long)-1; if (p
[j
] != (unsigned long)-1) goto err
; 
 263         p
[j
] = ULONG_ONEZERO
; if (p
[j
] != ULONG_ONEZERO
) goto err
; 
 264         p
[j
] = ULONG_ZEROONE
; if (p
[j
] != ULONG_ZEROONE
) goto err
; 
 265         p
[j
] = val
; /* restore the original value. */ 
 269 err
: /* memory error detected. */ 
 274 void memtest(size_t megabytes
, int passes
) { 
 275     if (ioctl(1, TIOCGWINSZ
, &ws
) == -1) { 
 279     memtest_test(megabytes
,passes
); 
 280     printf("\nYour memory passed this test.\n"); 
 281     printf("Please if you are still in doubt use the following two tools:\n"); 
 282     printf("1) memtest86: http://www.memtest86.com/\n"); 
 283     printf("2) memtester: http://pyropus.ca/software/memtester/\n");