/*
* memtester version 4
*
* Very simple but very effective user-space memory tester.
* Originally by Simon Kirby <sim@stormix.com> <sim@neato.org>
* Version 2 by Charles Cazabon <memtest@discworld.dyndns.org>
* Version 3 not publicly released.
* Version 4 rewrite:
* Copyright (C) 2006 Charles Cazabon <memtest@discworld.dyndns.org>
* Licensed under the terms of the GNU General Public License version 2 (only).
* See the file COPYING for details.
*
*/
#define __version__ "4.0.7"
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include "types.h"
#include "sizes.h"
#include "tests.h"
#define EXIT_FAIL_NONSTARTER 0x01
#define EXIT_FAIL_ADDRESSLINES 0x02
#define EXIT_FAIL_OTHERTEST 0x04
struct test tests[] = {
{ "Random Value", test_random_value },
{ "Compare XOR", test_xor_comparison },
{ "Compare SUB", test_sub_comparison },
{ "Compare MUL", test_mul_comparison },
{ "Compare DIV",test_div_comparison },
{ "Compare OR", test_or_comparison },
{ "Compare AND", test_and_comparison },
{ "Sequential Increment", test_seqinc_comparison },
{ "Solid Bits", test_solidbits_comparison },
{ "Block Sequential", test_blockseq_comparison },
{ "Checkerboard", test_checkerboard_comparison },
{ "Bit Spread", test_bitspread_comparison },
{ "Bit Flip", test_bitflip_comparison },
{ "Walking Ones", test_walkbits1_comparison },
{ "Walking Zeroes", test_walkbits0_comparison },
{ NULL, NULL }
};
#ifdef _SC_VERSION
void check_posix_system(void) {
if (sysconf(_SC_VERSION) < 198808L) {
fprintf(stderr, "A POSIX system is required. Don't be surprised if "
"this craps out.\n");
fprintf(stderr, "_SC_VERSION is %lu\n", sysconf(_SC_VERSION));
}
}
#else
#define check_posix_system()
#endif
#ifdef _SC_PAGE_SIZE
int memtester_pagesize(void) {
int pagesize = sysconf(_SC_PAGE_SIZE);
if (pagesize == -1) {
perror("get page size failed");
exit(EXIT_FAIL_NONSTARTER);
}
printf("pagesize is %ld\n", pagesize);
return pagesize;
}
#else
int memtester_pagesize(void) {
printf("sysconf(_SC_PAGE_SIZE) not supported; using pagesize of 8192\n");
return 8192;
}
#endif
int main(int argc, char **argv) {
ul loops, loop, i;
size_t pagesize, wantmb, wantbytes, wantbytes_orig, bufsize, halflen, count;
ptrdiff_t pagesizemask;
void volatile *buf, *aligned;
ulv *bufa, *bufb;
int do_mlock = 1, done_mem = 0;
int exit_code = 0;
printf("memtester version " __version__ " (%d-bit)\n", UL_LEN);
printf("Copyright (C) 2006 Charles Cazabon.\n");
printf("Licensed under the GNU General Public License version 2 (only).\n");
printf("\n");
check_posix_system();
pagesize = memtester_pagesize();
pagesizemask = (ptrdiff_t) ~(pagesize - 1);
printf("pagesizemask is 0x%tx\n", pagesizemask);
if (argc < 2) {
fprintf(stderr, "need memory argument, in MB\n");
exit(EXIT_FAIL_NONSTARTER);
}
wantmb = (size_t) strtoul(argv[1], NULL, 0);
wantbytes_orig = wantbytes = (size_t) (wantmb << 20);
if (wantbytes < pagesize) {
fprintf(stderr, "bytes < pagesize -- memory argument too large?\n");
exit(EXIT_FAIL_NONSTARTER);
}
if (argc < 3) {
loops = 0;
} else {
loops = strtoul(argv[2], NULL, 0);
}
printf("want %lluMB (%llu bytes)\n", (ull) wantmb, (ull) wantbytes);
buf = NULL;
while (!done_mem) {
while (!buf && wantbytes) {
buf = (void volatile *) malloc(wantbytes);
if (!buf) wantbytes -= pagesize;
}
bufsize = wantbytes;
printf("got %lluMB (%llu bytes)", (ull) wantbytes >> 20,
(ull) wantbytes);
fflush(stdout);
if (do_mlock) {
printf(", trying mlock ...");
fflush(stdout);
if ((size_t) buf % pagesize) {
/* printf("aligning to page -- was 0x%tx\n", buf); */
aligned = (void volatile *) ((size_t) buf & pagesizemask) + pagesize;
/* printf(" now 0x%tx -- lost %d bytes\n", aligned,
* (size_t) aligned - (size_t) buf);
*/
bufsize -= ((size_t) aligned - (size_t) buf);
} else {
aligned = buf;
}
/* Try memlock */
if (mlock((void *) aligned, bufsize) < 0) {
switch(errno) {
case ENOMEM:
printf("too many pages, reducing...\n");
free((void *) buf);
buf = NULL;
wantbytes -= pagesize;
break;
case EPERM:
printf("insufficient permission.\n");
printf("Trying again, unlocked:\n");
do_mlock = 0;
free((void *) buf);
buf = NULL;
wantbytes = wantbytes_orig;
break;
default:
printf("failed for unknown reason.\n");
do_mlock = 0;
done_mem = 1;
}
} else {
printf("locked.\n");
done_mem = 1;
}
} else {
done_mem = 1;
printf("\n");
}
}
if (!do_mlock) fprintf(stderr, "Continuing with unlocked memory; testing "
"will be slower and less reliable.\n");
halflen = bufsize / 2;
count = halflen / sizeof(ul);
bufa = (ulv *) aligned;
bufb = (ulv *) ((size_t) aligned + halflen);
for(loop=1; ((!loops) || loop <= loops); loop++) {
printf("Loop %lu", loop);
if (loops) {
printf("/%lu", loops);
}
printf(":\n");
printf(" %-20s: ", "Stuck Address");
fflush(stdout);
if (!test_stuck_address(aligned, bufsize / sizeof(ul))) {
printf("ok\n");
} else {
exit_code |= EXIT_FAIL_ADDRESSLINES;
}
for (i=0;;i++) {
if (!tests[i].name) break;
printf(" %-20s: ", tests[i].name);
if (!tests[i].fp(bufa, bufb, count)) {
printf("ok\n");
} else {
exit_code |= EXIT_FAIL_OTHERTEST;
}
fflush(stdout);
}
printf("\n");
fflush(stdout);
}
if (do_mlock) munlock((void *) aligned, bufsize);
printf("Done.\n");
fflush(stdout);
exit(exit_code);
}
syntax highlighted by Code2HTML, v. 0.9.1