]> git.saurik.com Git - redis.git/blob - src/memtest.c
memtest.c: integer overflow fixed.
[redis.git] / src / memtest.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <assert.h>
5 #include <limits.h>
6 #include <errno.h>
7 #include <termios.h>
8 #include <sys/ioctl.h>
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
18 #ifdef MEMTEST_32BIT
19 #define ULONG_ONEZERO 0xaaaaaaaaUL
20 #define ULONG_ZEROONE 0x55555555UL
21 #else
22 #define ULONG_ONEZERO 0xaaaaaaaaaaaaaaaaUL
23 #define ULONG_ZEROONE 0x5555555555555555UL
24 #endif
25
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. */
29
30 void 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. */
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. */
40 progress_printed = 0;
41 progress_full = ws.ws_col*(ws.ws_row-3);
42 fflush(stdout);
43 }
44
45 void memtest_progress_end(void) {
46 printf("\x1b[H\x1b[2J"); /* Cursor home, clear screen. */
47 }
48
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;
51
52 for (j = 0; j < chars-progress_printed; j++) {
53 printf("%c",c);
54 progress_printed++;
55 }
56 fflush(stdout);
57 }
58
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);
64 unsigned long j, *p;
65
66 /* Fill */
67 p = l;
68 for (j = 0; j < words; j++) {
69 *p = (unsigned long)p;
70 p++;
71 if ((j & 0xffff) == 0) memtest_progress_step(j,words*2,'A');
72 }
73 /* Test */
74 p = l;
75 for (j = 0; j < words; j++) {
76 if (*p != (unsigned long)p) {
77 printf("\n*** MEMORY ADDRESSING ERROR: %p contains %lu\n",
78 (void*) p, *p);
79 exit(1);
80 }
81 p++;
82 if ((j & 0xffff) == 0) memtest_progress_step(j+words,words*2,'A');
83 }
84 }
85
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;
95
96 assert((bytes & 4095) == 0);
97 for (off = 0; off < step; off++) {
98 l1 = l+off;
99 l2 = l1+words;
100 for (w = 0; w < iwords; w++) {
101 #ifdef MEMTEST_32BIT
102 *l1 = *l2 = ((unsigned long) (rand()&0xffff)) |
103 (((unsigned long) (rand()&0xffff)) << 16);
104 #else
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);
109 #endif
110 l1 += step;
111 l2 += step;
112 if ((w & 0xffff) == 0)
113 memtest_progress_step(w+iwords*off,words,'R');
114 }
115 }
116 }
117
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)
122 {
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;
127
128 assert((bytes & 4095) == 0);
129 for (off = 0; off < step; off++) {
130 l1 = l+off;
131 l2 = l1+words;
132 v = (off & 1) ? v2 : v1;
133 for (w = 0; w < iwords; w++) {
134 #ifdef MEMTEST_32BIT
135 *l1 = *l2 = ((unsigned long) (rand()&0xffff)) |
136 (((unsigned long) (rand()&0xffff)) << 16);
137 #else
138 *l1 = *l2 = ((unsigned long) (rand()&0xffff)) |
139 (((unsigned long) (rand()&0xffff)) << 16) |
140 (((unsigned long) (rand()&0xffff)) << 32) |
141 (((unsigned long) (rand()&0xffff)) << 48);
142 #endif
143 l1 += step;
144 l2 += step;
145 if ((w & 0xffff) == 0)
146 memtest_progress_step(w+iwords*off,words,sym);
147 }
148 }
149 }
150
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;
154
155 assert((bytes & 4095) == 0);
156 l1 = l;
157 l2 = l1+words;
158 for (w = 0; w < words; w++) {
159 if (*l1 != *l2) {
160 printf("\n*** MEMORY ERROR DETECTED: %p != %p (%lu vs %lu)\n",
161 (void*)l1, (void*)l2, *l1, *l2);
162 exit(1);
163 }
164 l1 ++;
165 l2 ++;
166 if ((w & 0xffff) == 0) memtest_progress_step(w,words,'=');
167 }
168 }
169
170 void memtest_compare_times(unsigned long *m, size_t bytes, int pass, int times) {
171 int j;
172
173 for (j = 0; j < times; j++) {
174 memtest_progress_start("Compare",pass);
175 memtest_compare(m,bytes);
176 memtest_progress_end();
177 }
178 }
179
180 void memtest_test(size_t megabytes, int passes) {
181 size_t bytes = megabytes*1024*1024;
182 unsigned long *m = malloc(bytes);
183 int pass = 0;
184
185 if (m == NULL) {
186 fprintf(stderr,"Unable to allocate %zu megabytes: %s",
187 megabytes, strerror(errno));
188 exit(1);
189 }
190 while (pass != passes) {
191 pass++;
192
193 memtest_progress_start("Addressing test",pass);
194 memtest_addressing(m,bytes);
195 memtest_progress_end();
196
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);
201
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);
206
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);
211 }
212 }
213
214 void memtest(size_t megabytes, int passes) {
215 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
216 ws.ws_col = 80;
217 ws.ws_row = 20;
218 }
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");
224 exit(0);
225 }