Back to home page

Redis cross reference

 
 

    


0001 /*
0002  * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
0003  * All rights reserved.
0004  *
0005  * Redistribution and use in source and binary forms, with or without
0006  * modification, are permitted provided that the following conditions are met:
0007  *
0008  *   * Redistributions of source code must retain the above copyright notice,
0009  *     this list of conditions and the following disclaimer.
0010  *   * Redistributions in binary form must reproduce the above copyright
0011  *     notice, this list of conditions and the following disclaimer in the
0012  *     documentation and/or other materials provided with the distribution.
0013  *   * Neither the name of Redis nor the names of its contributors may be used
0014  *     to endorse or promote products derived from this software without
0015  *     specific prior written permission.
0016  *
0017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0027  * POSSIBILITY OF SUCH DAMAGE.
0028  */
0029 
0030 #include <stdlib.h>
0031 #include <stdio.h>
0032 #include <string.h>
0033 #include <assert.h>
0034 #include <limits.h>
0035 #include <errno.h>
0036 #include <termios.h>
0037 #include <sys/ioctl.h>
0038 
0039 #if (ULONG_MAX == 4294967295UL)
0040 #define MEMTEST_32BIT
0041 #elif (ULONG_MAX == 18446744073709551615ULL)
0042 #define MEMTEST_64BIT
0043 #else
0044 #error "ULONG_MAX value not supported."
0045 #endif
0046 
0047 #ifdef MEMTEST_32BIT
0048 #define ULONG_ONEZERO 0xaaaaaaaaUL
0049 #define ULONG_ZEROONE 0x55555555UL
0050 #else
0051 #define ULONG_ONEZERO 0xaaaaaaaaaaaaaaaaUL
0052 #define ULONG_ZEROONE 0x5555555555555555UL
0053 #endif
0054 
0055 static struct winsize ws;
0056 size_t progress_printed; /* Printed chars in screen-wide progress bar. */
0057 size_t progress_full; /* How many chars to write to fill the progress bar. */
0058 
0059 void memtest_progress_start(char *title, int pass) {
0060     int j;
0061 
0062     printf("\x1b[H\x1b[2J");    /* Cursor home, clear screen. */
0063     /* Fill with dots. */
0064     for (j = 0; j < ws.ws_col*(ws.ws_row-2); j++) printf(".");
0065     printf("Please keep the test running several minutes per GB of memory.\n");
0066     printf("Also check http://www.memtest86.com/ and http://pyropus.ca/software/memtester/");
0067     printf("\x1b[H\x1b[2K");          /* Cursor home, clear current line.  */
0068     printf("%s [%d]\n", title, pass); /* Print title. */
0069     progress_printed = 0;
0070     progress_full = ws.ws_col*(ws.ws_row-3);
0071     fflush(stdout);
0072 }
0073 
0074 void memtest_progress_end(void) {
0075     printf("\x1b[H\x1b[2J");    /* Cursor home, clear screen. */
0076 }
0077 
0078 void memtest_progress_step(size_t curr, size_t size, char c) {
0079     size_t chars = ((unsigned long long)curr*progress_full)/size, j;
0080 
0081     for (j = 0; j < chars-progress_printed; j++) printf("%c",c);
0082     progress_printed = chars;
0083     fflush(stdout);
0084 }
0085 
0086 /* Test that addressing is fine. Every location is populated with its own
0087  * address, and finally verified. This test is very fast but may detect
0088  * ASAP big issues with the memory subsystem. */
0089 void memtest_addressing(unsigned long *l, size_t bytes) {
0090     unsigned long words = bytes/sizeof(unsigned long);
0091     unsigned long j, *p;
0092 
0093     /* Fill */
0094     p = l;
0095     for (j = 0; j < words; j++) {
0096         *p = (unsigned long)p;
0097         p++;
0098         if ((j & 0xffff) == 0) memtest_progress_step(j,words*2,'A');
0099     }
0100     /* Test */
0101     p = l;
0102     for (j = 0; j < words; j++) {
0103         if (*p != (unsigned long)p) {
0104             printf("\n*** MEMORY ADDRESSING ERROR: %p contains %lu\n",
0105                 (void*) p, *p);
0106             exit(1);
0107         }
0108         p++;
0109         if ((j & 0xffff) == 0) memtest_progress_step(j+words,words*2,'A');
0110     }
0111 }
0112 
0113 /* Fill words stepping a single page at every write, so we continue to
0114  * touch all the pages in the smallest amount of time reducing the
0115  * effectiveness of caches, and making it hard for the OS to transfer
0116  * pages on the swap. */
0117 void memtest_fill_random(unsigned long *l, size_t bytes) {
0118     unsigned long step = 4096/sizeof(unsigned long);
0119     unsigned long words = bytes/sizeof(unsigned long)/2;
0120     unsigned long iwords = words/step;  /* words per iteration */
0121     unsigned long off, w, *l1, *l2;
0122 
0123     assert((bytes & 4095) == 0);
0124     for (off = 0; off < step; off++) {
0125         l1 = l+off;
0126         l2 = l1+words;
0127         for (w = 0; w < iwords; w++) {
0128 #ifdef MEMTEST_32BIT
0129             *l1 = *l2 = ((unsigned long)     (rand()&0xffff)) |
0130                         (((unsigned long)    (rand()&0xffff)) << 16);
0131 #else
0132             *l1 = *l2 = ((unsigned long)     (rand()&0xffff)) |
0133                         (((unsigned long)    (rand()&0xffff)) << 16) |
0134                         (((unsigned long)    (rand()&0xffff)) << 32) |
0135                         (((unsigned long)    (rand()&0xffff)) << 48);
0136 #endif
0137             l1 += step;
0138             l2 += step;
0139             if ((w & 0xffff) == 0)
0140                 memtest_progress_step(w+iwords*off,words,'R');
0141         }
0142     }
0143 }
0144 
0145 /* Like memtest_fill_random() but uses the two specified values to fill
0146  * memory, in an alternated way (v1|v2|v1|v2|...) */
0147 void memtest_fill_value(unsigned long *l, size_t bytes, unsigned long v1,
0148                         unsigned long v2, char sym)
0149 {
0150     unsigned long step = 4096/sizeof(unsigned long);
0151     unsigned long words = bytes/sizeof(unsigned long)/2;
0152     unsigned long iwords = words/step;  /* words per iteration */
0153     unsigned long off, w, *l1, *l2, v;
0154 
0155     assert((bytes & 4095) == 0);
0156     for (off = 0; off < step; off++) {
0157         l1 = l+off;
0158         l2 = l1+words;
0159         v = (off & 1) ? v2 : v1;
0160         for (w = 0; w < iwords; w++) {
0161 #ifdef MEMTEST_32BIT
0162             *l1 = *l2 = ((unsigned long)     v) |
0163                         (((unsigned long)    v) << 16);
0164 #else
0165             *l1 = *l2 = ((unsigned long)     v) |
0166                         (((unsigned long)    v) << 16) |
0167                         (((unsigned long)    v) << 32) |
0168                         (((unsigned long)    v) << 48);
0169 #endif
0170             l1 += step;
0171             l2 += step;
0172             if ((w & 0xffff) == 0)
0173                 memtest_progress_step(w+iwords*off,words,sym);
0174         }
0175     }
0176 }
0177 
0178 void memtest_compare(unsigned long *l, size_t bytes) {
0179     unsigned long words = bytes/sizeof(unsigned long)/2;
0180     unsigned long w, *l1, *l2;
0181 
0182     assert((bytes & 4095) == 0);
0183     l1 = l;
0184     l2 = l1+words;
0185     for (w = 0; w < words; w++) {
0186         if (*l1 != *l2) {
0187             printf("\n*** MEMORY ERROR DETECTED: %p != %p (%lu vs %lu)\n",
0188                 (void*)l1, (void*)l2, *l1, *l2);
0189             exit(1);
0190         }
0191         l1 ++;
0192         l2 ++;
0193         if ((w & 0xffff) == 0) memtest_progress_step(w,words,'=');
0194     }
0195 }
0196 
0197 void memtest_compare_times(unsigned long *m, size_t bytes, int pass, int times) {
0198     int j;
0199 
0200     for (j = 0; j < times; j++) {
0201         memtest_progress_start("Compare",pass);
0202         memtest_compare(m,bytes);
0203         memtest_progress_end();
0204     }
0205 }
0206 
0207 void memtest_test(size_t megabytes, int passes) {
0208     size_t bytes = megabytes*1024*1024;
0209     unsigned long *m = malloc(bytes);
0210     int pass = 0;
0211 
0212     if (m == NULL) {
0213         fprintf(stderr,"Unable to allocate %zu megabytes: %s",
0214             megabytes, strerror(errno));
0215         exit(1);
0216     }
0217     while (pass != passes) {
0218         pass++;
0219 
0220         memtest_progress_start("Addressing test",pass);
0221         memtest_addressing(m,bytes);
0222         memtest_progress_end();
0223 
0224         memtest_progress_start("Random fill",pass);
0225         memtest_fill_random(m,bytes);
0226         memtest_progress_end();
0227         memtest_compare_times(m,bytes,pass,4);
0228 
0229         memtest_progress_start("Solid fill",pass);
0230         memtest_fill_value(m,bytes,0,(unsigned long)-1,'S');
0231         memtest_progress_end();
0232         memtest_compare_times(m,bytes,pass,4);
0233 
0234         memtest_progress_start("Checkerboard fill",pass);
0235         memtest_fill_value(m,bytes,ULONG_ONEZERO,ULONG_ZEROONE,'C');
0236         memtest_progress_end();
0237         memtest_compare_times(m,bytes,pass,4);
0238     }
0239 }
0240 
0241 void memtest(size_t megabytes, int passes) {
0242     if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
0243         ws.ws_col = 80;
0244         ws.ws_row = 20;
0245     }
0246     memtest_test(megabytes,passes);
0247     printf("\nYour memory passed this test.\n");
0248     printf("Please if you are still in doubt use the following two tools:\n");
0249     printf("1) memtest86: http://www.memtest86.com/\n");
0250     printf("2) memtester: http://pyropus.ca/software/memtester/\n");
0251     exit(0);
0252 }