]> git.saurik.com Git - redis.git/blame_incremental - src/memtest.c
Memory test function now less boring thanks to screen-wide progress bar.
[redis.git] / src / memtest.c
... / ...
CommitLineData
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
18static struct winsize ws;
19size_t progress_printed; /* Printed chars in screen-wide progress bar. */
20size_t progress_full; /* How many chars to write to fill the progress bar. */
21
22void 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
35void memtest_progress_end(void) {
36 printf("\x1b[H\x1b[2J"); /* Cursor home, clear screen. */
37}
38
39void 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. */
53void 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
81void 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
100void 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
123void 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}