]>
git.saurik.com Git - redis.git/blob - src/memtest.c
10 #if (ULONG_MAX == 4294967295UL)
12 #elif (ULONG_MAX == 18446744073709551615ULL)
15 #error "ULONG_MAX value not supported."
19 #define ULONG_ONEZERO 0xaaaaaaaaUL
20 #define ULONG_ZEROONE 0x55555555UL
22 #define ULONG_ONEZERO 0xaaaaaaaaaaaaaaaaUL
23 #define ULONG_ZEROONE 0x5555555555555555UL
26 static struct winsize ws
;
27 size_t progress_printed
; /* Printed chars in screen-wide progress bar. */
28 size_t progress_full
; /* How many chars to write to fill the progress bar. */
30 void memtest_progress_start(char *title
, int pass
) {
33 printf("\x1b[H\x1b[2J"); /* Cursor home, clear screen. */
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/");
38 printf("\x1b[H\x1b[2K"); /* Cursor home, clear current line. */
39 printf("%s [%d]\n", title
, pass
); /* Print title. */
41 progress_full
= ws
.ws_col
*(ws
.ws_row
-3);
45 void memtest_progress_end(void) {
46 printf("\x1b[H\x1b[2J"); /* Cursor home, clear screen. */
49 void memtest_progress_step(size_t curr
, size_t size
, char c
) {
50 size_t chars
= ((unsigned long long)curr
*progress_full
)/size
, j
;
52 for (j
= 0; j
< chars
-progress_printed
; j
++) {
59 /* Test that addressing is fine. Every location is populated with its own
60 * address, and finally verified. This test is very fast but may detect
61 * ASAP big issues with the memory subsystem. */
62 void memtest_addressing(unsigned long *l
, size_t bytes
) {
63 unsigned long words
= bytes
/sizeof(unsigned long);
68 for (j
= 0; j
< words
; j
++) {
69 *p
= (unsigned long)p
;
71 if ((j
& 0xffff) == 0) memtest_progress_step(j
,words
*2,'A');
75 for (j
= 0; j
< words
; j
++) {
76 if (*p
!= (unsigned long)p
) {
77 printf("\n*** MEMORY ADDRESSING ERROR: %p contains %lu\n",
82 if ((j
& 0xffff) == 0) memtest_progress_step(j
+words
,words
*2,'A');
86 /* Fill words stepping a single page at every write, so we continue to
87 * touch all the pages in the smallest amount of time reducing the
88 * effectiveness of caches, and making it hard for the OS to transfer
89 * pages on the swap. */
90 void memtest_fill_random(unsigned long *l
, size_t bytes
) {
91 unsigned long step
= 4096/sizeof(unsigned long);
92 unsigned long words
= bytes
/sizeof(unsigned long)/2;
93 unsigned long iwords
= words
/step
; /* words per iteration */
94 unsigned long off
, w
, *l1
, *l2
;
96 assert((bytes
& 4095) == 0);
97 for (off
= 0; off
< step
; off
++) {
100 for (w
= 0; w
< iwords
; w
++) {
102 *l1
= *l2
= ((unsigned long) (rand()&0xffff)) |
103 (((unsigned long) (rand()&0xffff)) << 16);
105 *l1
= *l2
= ((unsigned long) (rand()&0xffff)) |
106 (((unsigned long) (rand()&0xffff)) << 16) |
107 (((unsigned long) (rand()&0xffff)) << 32) |
108 (((unsigned long) (rand()&0xffff)) << 48);
112 if ((w
& 0xffff) == 0)
113 memtest_progress_step(w
+iwords
*off
,words
,'R');
118 /* Like memtest_fill_random() but uses the two specified values to fill
119 * memory, in an alternated way (v1|v2|v1|v2|...) */
120 void memtest_fill_value(unsigned long *l
, size_t bytes
, unsigned long v1
,
121 unsigned long v2
, char sym
)
123 unsigned long step
= 4096/sizeof(unsigned long);
124 unsigned long words
= bytes
/sizeof(unsigned long)/2;
125 unsigned long iwords
= words
/step
; /* words per iteration */
126 unsigned long off
, w
, *l1
, *l2
, v
;
128 assert((bytes
& 4095) == 0);
129 for (off
= 0; off
< step
; off
++) {
132 v
= (off
& 1) ? v2
: v1
;
133 for (w
= 0; w
< iwords
; w
++) {
135 *l1
= *l2
= ((unsigned long) v
) |
136 (((unsigned long) v
) << 16);
138 *l1
= *l2
= ((unsigned long) v
) |
139 (((unsigned long) v
) << 16) |
140 (((unsigned long) v
) << 32) |
141 (((unsigned long) v
) << 48);
145 if ((w
& 0xffff) == 0)
146 memtest_progress_step(w
+iwords
*off
,words
,sym
);
151 void memtest_compare(unsigned long *l
, size_t bytes
) {
152 unsigned long words
= bytes
/sizeof(unsigned long)/2;
153 unsigned long w
, *l1
, *l2
;
155 assert((bytes
& 4095) == 0);
158 for (w
= 0; w
< words
; w
++) {
160 printf("\n*** MEMORY ERROR DETECTED: %p != %p (%lu vs %lu)\n",
161 (void*)l1
, (void*)l2
, *l1
, *l2
);
166 if ((w
& 0xffff) == 0) memtest_progress_step(w
,words
,'=');
170 void memtest_compare_times(unsigned long *m
, size_t bytes
, int pass
, int times
) {
173 for (j
= 0; j
< times
; j
++) {
174 memtest_progress_start("Compare",pass
);
175 memtest_compare(m
,bytes
);
176 memtest_progress_end();
180 void memtest_test(size_t megabytes
, int passes
) {
181 size_t bytes
= megabytes
*1024*1024;
182 unsigned long *m
= malloc(bytes
);
186 fprintf(stderr
,"Unable to allocate %zu megabytes: %s",
187 megabytes
, strerror(errno
));
190 while (pass
!= passes
) {
193 memtest_progress_start("Addressing test",pass
);
194 memtest_addressing(m
,bytes
);
195 memtest_progress_end();
197 memtest_progress_start("Random fill",pass
);
198 memtest_fill_random(m
,bytes
);
199 memtest_progress_end();
200 memtest_compare_times(m
,bytes
,pass
,4);
202 memtest_progress_start("Solid fill",pass
);
203 memtest_fill_value(m
,bytes
,0,(unsigned long)-1,'S');
204 memtest_progress_end();
205 memtest_compare_times(m
,bytes
,pass
,4);
207 memtest_progress_start("Checkerboard fill",pass
);
208 memtest_fill_value(m
,bytes
,ULONG_ONEZERO
,ULONG_ZEROONE
,'C');
209 memtest_progress_end();
210 memtest_compare_times(m
,bytes
,pass
,4);
214 void memtest(size_t megabytes
, int passes
) {
215 if (ioctl(1, TIOCGWINSZ
, &ws
) == -1) {
219 memtest_test(megabytes
,passes
);
220 printf("\nYour memory passed this test.\n");
221 printf("Please if you are still in doubt use the following two tools:\n");
222 printf("1) memtest86: http://www.memtest86.com/\n");
223 printf("2) memtester: http://pyropus.ca/software/memtester/\n");