]> git.saurik.com Git - redis.git/blame - src/memtest.c
More memory tests implemented. Default number of iterations lowered to a more accepta...
[redis.git] / src / memtest.c
CommitLineData
f4df22d1 1#include <stdlib.h>
2#include <stdio.h>
3#include <string.h>
4#include <assert.h>
5#include <limits.h>
6#include <errno.h>
d605fdab 7#include <termios.h>
8#include <sys/ioctl.h>
f4df22d1 9
10#if (ULONG_MAX == 4294967295UL)
11#define MEMTEST_32BIT
12#elif (ULONG_MAX == 18446744073709551615ULL)
13#define MEMTEST_64BIT
14#else
15#error "ULONG_MAX value not supported."
16#endif
17
ea693f02 18#ifdef MEMTEST_32BIT
19#define ULONG_ONEZERO 0xaaaaaaaaaaaaaaaaUL
20#define ULONG_ZEROONE 0x5555555555555555UL
21#else
22#define ULONG_ONEZERO 0xaaaaaaaaUL
23#define ULONG_ZEROONE 0x55555555UL
24#endif
25
d605fdab 26static struct winsize ws;
27size_t progress_printed; /* Printed chars in screen-wide progress bar. */
28size_t progress_full; /* How many chars to write to fill the progress bar. */
29
30void memtest_progress_start(char *title, int pass) {
31 int j;
32
33 printf("\x1b[H\x1b[2J"); /* Cursor home, clear screen. */
34 /* Fill with dots. */
32f62ed6 35 for (j = 0; j < ws.ws_col*(ws.ws_row-2); j++) printf(".");
36 printf("Please keep the test running several minutes per GB of memory.\n");
37 printf("Also check http://www.memtest86.com/ and http://pyropus.ca/software/memtester/");
d605fdab 38 printf("\x1b[H\x1b[2K"); /* Cursor home, clear current line. */
39 printf("%s [%d]\n", title, pass); /* Print title. */
40 progress_printed = 0;
32f62ed6 41 progress_full = ws.ws_col*(ws.ws_row-3);
d605fdab 42 fflush(stdout);
43}
44
45void memtest_progress_end(void) {
46 printf("\x1b[H\x1b[2J"); /* Cursor home, clear screen. */
47}
48
49void memtest_progress_step(size_t curr, size_t size, char c) {
50 size_t chars = (curr*progress_full)/size, j;
51
52 for (j = 0; j < chars-progress_printed; j++) {
53 printf("%c",c);
54 progress_printed++;
55 }
56 fflush(stdout);
57}
58
f4df22d1 59/* Fill words stepping a single page at every write, so we continue to
60 * touch all the pages in the smallest amount of time reducing the
61 * effectiveness of caches, and making it hard for the OS to transfer
62 * pages on the swap. */
ea693f02 63void memtest_fill_random(unsigned long *l, size_t bytes) {
f4df22d1 64 unsigned long step = 4096/sizeof(unsigned long);
65 unsigned long words = bytes/sizeof(unsigned long)/2;
66 unsigned long iwords = words/step; /* words per iteration */
67 unsigned long off, w, *l1, *l2;
68
69 assert((bytes & 4095) == 0);
70 for (off = 0; off < step; off++) {
71 l1 = l+off;
72 l2 = l1+words;
73 for (w = 0; w < iwords; w++) {
74#ifdef MEMTEST_32BIT
75 *l1 = *l2 = ((unsigned long) (rand()&0xffff)) |
76 (((unsigned long) (rand()&0xffff)) << 16);
77#else
78 *l1 = *l2 = ((unsigned long) (rand()&0xffff)) |
79 (((unsigned long) (rand()&0xffff)) << 16) |
80 (((unsigned long) (rand()&0xffff)) << 32) |
81 (((unsigned long) (rand()&0xffff)) << 48);
82#endif
83 l1 += step;
84 l2 += step;
d605fdab 85 if ((w & 0xffff) == 0)
ea693f02 86 memtest_progress_step(w+iwords*off,words,'R');
87 }
88 }
89}
90
91/* Like memtest_fill_random() but uses the two specified values to fill
92 * memory, in an alternated way (v1|v2|v1|v2|...) */
93void memtest_fill_value(unsigned long *l, size_t bytes, unsigned long v1,
94 unsigned long v2, char sym)
95{
96 unsigned long step = 4096/sizeof(unsigned long);
97 unsigned long words = bytes/sizeof(unsigned long)/2;
98 unsigned long iwords = words/step; /* words per iteration */
99 unsigned long off, w, *l1, *l2, v;
100
101 assert((bytes & 4095) == 0);
102 for (off = 0; off < step; off++) {
103 l1 = l+off;
104 l2 = l1+words;
105 v = (off & 1) ? v2 : v1;
106 for (w = 0; w < iwords; w++) {
107#ifdef MEMTEST_32BIT
108 *l1 = *l2 = ((unsigned long) (rand()&0xffff)) |
109 (((unsigned long) (rand()&0xffff)) << 16);
110#else
111 *l1 = *l2 = ((unsigned long) (rand()&0xffff)) |
112 (((unsigned long) (rand()&0xffff)) << 16) |
113 (((unsigned long) (rand()&0xffff)) << 32) |
114 (((unsigned long) (rand()&0xffff)) << 48);
115#endif
116 l1 += step;
117 l2 += step;
118 if ((w & 0xffff) == 0)
119 memtest_progress_step(w+iwords*off,words,sym);
f4df22d1 120 }
121 }
122}
123
124void memtest_compare(unsigned long *l, size_t bytes) {
125 unsigned long words = bytes/sizeof(unsigned long)/2;
126 unsigned long w, *l1, *l2;
127
128 assert((bytes & 4095) == 0);
129 l1 = l;
130 l2 = l1+words;
131 for (w = 0; w < words; w++) {
132 if (*l1 != *l2) {
133 printf("\n*** MEMORY ERROR DETECTED: %p != %p (%lu vs %lu)\n",
134 (void*)l1, (void*)l2, *l1, *l2);
135 exit(1);
136 }
137 l1 ++;
138 l2 ++;
d605fdab 139 if ((w & 0xffff) == 0) memtest_progress_step(w,words,'=');
f4df22d1 140 }
141}
142
ea693f02 143void memtest_compare_times(unsigned long *m, size_t bytes, int pass, int times) {
144 int j;
145
146 for (j = 0; j < times; j++) {
147 memtest_progress_start("Compare",pass);
148 memtest_compare(m,bytes);
149 memtest_progress_end();
150 }
151}
152
f4df22d1 153void memtest_test(size_t megabytes, int passes) {
154 size_t bytes = megabytes*1024*1024;
155 unsigned long *m = malloc(bytes);
ea693f02 156 int pass = 0;
f4df22d1 157
158 if (m == NULL) {
159 fprintf(stderr,"Unable to allocate %zu megabytes: %s",
160 megabytes, strerror(errno));
161 exit(1);
162 }
163 while (pass != passes) {
164 pass++;
d605fdab 165 memtest_progress_start("Random fill",pass);
ea693f02 166 memtest_fill_random(m,bytes);
d605fdab 167 memtest_progress_end();
ea693f02 168 memtest_compare_times(m,bytes,pass,4);
169
170 memtest_progress_start("Solid fill",pass);
171 memtest_fill_value(m,bytes,0,(unsigned long)-1,'S');
172 memtest_progress_end();
173 memtest_compare_times(m,bytes,pass,4);
174
175 memtest_progress_start("Checkerboard fill",pass);
176 memtest_fill_value(m,bytes,ULONG_ONEZERO,ULONG_ZEROONE,'C');
177 memtest_progress_end();
178 memtest_compare_times(m,bytes,pass,4);
f4df22d1 179 }
180}
181
182void memtest(size_t megabytes, int passes) {
d605fdab 183 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
184 ws.ws_col = 80;
185 ws.ws_row = 20;
186 }
f4df22d1 187 memtest_test(megabytes,passes);
188 printf("\nYour memory passed this test.\n");
74760d3c 189 printf("Please if you are still in doubt use the following two tools:\n");
f4df22d1 190 printf("1) memtest86: http://www.memtest86.com/\n");
191 printf("2) memtester: http://pyropus.ca/software/memtester/\n");
192 exit(0);
193}