]> git.saurik.com Git - redis.git/blob - src/memtest.c
Memory test function now less boring thanks to screen-wide progress bar.
[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 static struct winsize ws;
19 size_t progress_printed; /* Printed chars in screen-wide progress bar. */
20 size_t progress_full; /* How many chars to write to fill the progress bar. */
21
22 void memtest_progress_start(char *title, int pass) {
23 int j;
24
25 printf("\x1b[H\x1b[2J"); /* Cursor home, clear screen. */
26 /* Fill with dots. */
27 for (j = 0; j < ws.ws_col*ws.ws_row; j++) printf(".");
28 printf("\x1b[H\x1b[2K"); /* Cursor home, clear current line. */
29 printf("%s [%d]\n", title, pass); /* Print title. */
30 progress_printed = 0;
31 progress_full = ws.ws_col*(ws.ws_row-1);
32 fflush(stdout);
33 }
34
35 void memtest_progress_end(void) {
36 printf("\x1b[H\x1b[2J"); /* Cursor home, clear screen. */
37 }
38
39 void memtest_progress_step(size_t curr, size_t size, char c) {
40 size_t chars = (curr*progress_full)/size, j;
41
42 for (j = 0; j < chars-progress_printed; j++) {
43 printf("%c",c);
44 progress_printed++;
45 }
46 fflush(stdout);
47 }
48
49 /* Fill words stepping a single page at every write, so we continue to
50 * touch all the pages in the smallest amount of time reducing the
51 * effectiveness of caches, and making it hard for the OS to transfer
52 * pages on the swap. */
53 void memtest_fill(unsigned long *l, size_t bytes) {
54 unsigned long step = 4096/sizeof(unsigned long);
55 unsigned long words = bytes/sizeof(unsigned long)/2;
56 unsigned long iwords = words/step; /* words per iteration */
57 unsigned long off, w, *l1, *l2;
58
59 assert((bytes & 4095) == 0);
60 for (off = 0; off < step; off++) {
61 l1 = l+off;
62 l2 = l1+words;
63 for (w = 0; w < iwords; w++) {
64 #ifdef MEMTEST_32BIT
65 *l1 = *l2 = ((unsigned long) (rand()&0xffff)) |
66 (((unsigned long) (rand()&0xffff)) << 16);
67 #else
68 *l1 = *l2 = ((unsigned long) (rand()&0xffff)) |
69 (((unsigned long) (rand()&0xffff)) << 16) |
70 (((unsigned long) (rand()&0xffff)) << 32) |
71 (((unsigned long) (rand()&0xffff)) << 48);
72 #endif
73 l1 += step;
74 l2 += step;
75 if ((w & 0xffff) == 0)
76 memtest_progress_step(w+iwords*off,words,'+');
77 }
78 }
79 }
80
81 void memtest_compare(unsigned long *l, size_t bytes) {
82 unsigned long words = bytes/sizeof(unsigned long)/2;
83 unsigned long w, *l1, *l2;
84
85 assert((bytes & 4095) == 0);
86 l1 = l;
87 l2 = l1+words;
88 for (w = 0; w < words; w++) {
89 if (*l1 != *l2) {
90 printf("\n*** MEMORY ERROR DETECTED: %p != %p (%lu vs %lu)\n",
91 (void*)l1, (void*)l2, *l1, *l2);
92 exit(1);
93 }
94 l1 ++;
95 l2 ++;
96 if ((w & 0xffff) == 0) memtest_progress_step(w,words,'=');
97 }
98 }
99
100 void memtest_test(size_t megabytes, int passes) {
101 size_t bytes = megabytes*1024*1024;
102 unsigned long *m = malloc(bytes);
103 int pass = 0, j;
104
105 if (m == NULL) {
106 fprintf(stderr,"Unable to allocate %zu megabytes: %s",
107 megabytes, strerror(errno));
108 exit(1);
109 }
110 while (pass != passes) {
111 pass++;
112 memtest_progress_start("Random fill",pass);
113 memtest_fill(m,bytes);
114 memtest_progress_end();
115 for (j = 0; j < 4; j++) {
116 memtest_progress_start("Compare",pass);
117 memtest_compare(m,bytes);
118 memtest_progress_end();
119 }
120 }
121 }
122
123 void memtest(size_t megabytes, int passes) {
124 if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
125 ws.ws_col = 80;
126 ws.ws_row = 20;
127 }
128 memtest_test(megabytes,passes);
129 printf("\nYour memory passed this test.\n");
130 printf("Please if you are stil in doubt use the following two tools:\n");
131 printf("1) memtest86: http://www.memtest86.com/\n");
132 printf("2) memtester: http://pyropus.ca/software/memtester/\n");
133 exit(0);
134 }