2 * Author: Kent Overstreet <kmo@daterainc.com>
7 #define _FILE_OFFSET_BITS 64
8 #define _XOPEN_SOURCE 500
19 #include <sys/ioctl.h>
21 #include <sys/param.h>
22 #include <sys/types.h>
28 #include <openssl/rc4.h>
29 #include <openssl/md4.h>
31 static const unsigned char bcache_magic[] = {
32 0xc6, 0x85, 0x73, 0xf6, 0x4e, 0x1a, 0x45, 0xca,
33 0x82, 0x65, 0xf5, 0x7f, 0x48, 0xba, 0x6d, 0x81 };
35 unsigned char zero[4096];
39 #define Pread(fd, buf, size, offset) do { \
41 while (_read < size) { \
42 _r = pread(fd, buf, (size) - _read, (offset) + _read); \
49 #define Pwrite(fd, buf, size, offset) do { \
51 while (_write < size) { \
52 _r = pwrite(fd, buf, (size) - _write, offset + _write); \
59 /* Marsaglia polar method
64 static double n = 0 / (double) 0;
73 x = random() / (double) (RAND_MAX / 2) - 1;
74 y = random() / (double) (RAND_MAX / 2) - 1;
79 s = sqrt(-2 * log(s) / s);
84 long getblocks(int fd)
88 if (fstat(fd, &statbuf)) {
92 ret = statbuf.st_size / 512;
93 if (S_ISBLK(statbuf.st_mode))
94 if (ioctl(fd, BLKGETSIZE, &ret)) {
95 perror("ioctl error");
102 unsigned char csum[16];
103 unsigned char oldcsum[16];
110 char logbuf[1 << 21];
120 sprintf(logbuf, "log.%i", abs(random()) % 1000);
121 fd = open(logbuf, O_WRONLY|O_CREAT|O_TRUNC, 0644);
124 perror("Error opening log file");
129 len = klogctl(4, logbuf, 1 << 21);
132 perror("Error reading kernel log");
137 int r = write(fd, logbuf + w, len - w);
139 perror("Error writing log");
146 void aio_loop(int nr)
156 int main(int argc, char **argv)
158 bool walk = false, randsize = false, verbose = false, csum = false, rtest = false, wtest = false;
159 int fd1, fd2 = 0, direct = 0, nbytes = 4096, j, o;
160 unsigned long size, i, offset = 0, done = 0, unique = 0, benchmark = 0;
161 void *buf1 = NULL, *buf2 = NULL;
162 struct pagestuff *pages, *p;
164 time_t last_printed = 0;
168 RC4_set_key(&writedata, 16, bcache_magic);
170 while ((o = getopt(argc, argv, "dnwvscwlb:")) != EOF)
197 benchmark = atol(optarg);
206 if (!rtest && !wtest)
210 printf("Please enter a device to test\n");
214 if (!csum && !benchmark && argc < 2) {
215 printf("Please enter a device to compare against\n");
219 fd1 = open(argv[0], (wtest ? O_RDWR : O_RDONLY)|direct);
220 if (!csum && !benchmark)
221 fd2 = open(argv[1], (wtest ? O_RDWR : O_RDONLY)|direct);
223 if (fd1 == -1 || fd2 == -1) {
224 perror("Error opening device");
228 size = getblocks(fd1);
229 if (!csum && !benchmark)
230 size = MIN(size, getblocks(fd2));
232 size = size / 8 - 16;
233 pages = calloc(size + 16, sizeof(*pages));
234 printf("size %li\n", size);
236 if (posix_memalign(&buf1, 4096, 4096 * 16) ||
237 posix_memalign(&buf2, 4096, 4096 * 16)) {
238 printf("Could not allocate buffers\n");
241 //setvbuf(stdout, NULL, _IONBF, 0);
243 for (i = 0; !benchmark || i < benchmark; i++) {
244 bool writing = (wtest && (i & 1)) || !rtest;
245 nbytes = randsize ? drand48() * 16 + 1 : 1;
249 offset += walk ? normal() * 20 : random();
257 time_t now = time(NULL);
258 if (now - last_printed >= 2) {
263 print: printf("Loop %6li offset %9li sectors %3i, %6lu mb done, %6lu mb unique\n",
264 i, offset >> 9, nbytes >> 9, done >> 11, unique >> 11);
269 Pread(fd1, buf1, nbytes, offset);
270 if (!writing && !csum && !benchmark)
271 Pread(fd2, buf2, nbytes, offset);
273 for (j = 0; j < nbytes; j += 4096) {
274 p = &pages[(offset + j) / 4096];
277 RC4(&writedata, 4096, zero, buf1 + j);
280 MD4(buf1 + j, 4096, &c[0]);
283 (!p->readcount && !p->writecount)) {
284 memcpy(&p->oldcsum[0], &p->csum[0], 16);
285 memcpy(&p->csum[0], c, 16);
286 } else if (memcmp(&p->csum[0], c, 16))
288 } else if (!writing && !benchmark &&
294 if (!p->writecount && !p->readcount)
297 writing ? p->writecount++ : p->readcount++;
300 Pwrite(fd1, buf1, nbytes, offset);
301 if (writing && !csum && !benchmark)
302 Pwrite(fd2, buf2, nbytes, offset);
304 printf("Loop %6li offset %9li sectors %3i, %6lu mb done, %6lu mb unique\n",
305 i, offset >> 9, nbytes >> 9, done >> 11, unique >> 11);
312 printf("Bad read! loop %li offset %li readcount %i writecount %i\n",
313 i, (offset + j) >> 9, p->readcount, p->writecount);
315 if (!memcmp(&p->oldcsum[0], c, 16))
316 printf("Matches previous csum\n");