summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <clm@fb.com>2019-12-09 16:11:45 -0800
committerChris Mason <clm@fb.com>2019-12-29 12:39:28 -0800
commita03797b8e45d78cdd7a73f743c34d4d1e4bef063 (patch)
tree85e983c9a6d4d202996b470b06ba538c8d76cbce
parent598cd23d74b9c31939c520ba80a6b418b5143e1e (diff)
downloadsimoop-a03797b8e45d78cdd7a73f743c34d4d1e4bef063.tar.gz
simoop: rework the verification code
This makes a few changes to simoop's verifier and general IO patterns. First we have a few new options: -v -- verify files immediately after writing them -I -- ignore crcs completely -e -- truncate all files to zero length on startup We're now using sync_file_range to force file writes down to disk and fadvise to drop caches before reads. Header checks output more information about which offsets in the file were corrupted, and also verify the inode number in the file matches the inode number we expect. I'll have to rework this if we start exercising reflink'd extents but for now it helps detect misplaced writes. All of these changes make simoop more useful for finding memory corruptions and file data corruptions. Signed-off-by: Chris Mason <clm@fb.com>
-rw-r--r--simoop.c341
1 files changed, 224 insertions, 117 deletions
diff --git a/simoop.c b/simoop.c
index 1bb0c67..7d3f326 100644
--- a/simoop.c
+++ b/simoop.c
@@ -39,7 +39,7 @@
#define DIR_LEVEL 64
/* buffer size for reads and writes during filler */
-#define BUF_SIZE (10 * 1024 * 1024)
+#define BUF_SIZE (1 * 1024 * 1024)
#define NAME_LEN 256
#define FILES_SPLIT 8
@@ -64,7 +64,7 @@ int total_paths = 0;
/* -t number of workers thread */
static int worker_threads = 16;
/* -r seconds */
-static int runtime = 30;
+static unsigned long runtime = 30;
/* -c usec */
static unsigned long long cputime = 3000000;
/* -f size of the files we create */
@@ -76,15 +76,18 @@ static unsigned long read_size = 2 * 1024 * 1024;
/* -W write size */
static unsigned long write_size = 2 * 1024 * 1024;
/* -T number of files to read */
-static int rw_threads = 8;
+static unsigned long rw_threads = 8;
/* -D number of threads running du */
static int du_threads = 0;
/* memory to allocate and use during each task */
-static int thinking_mem = 128 * 1024 * 1024;
+static unsigned long thinking_mem = 128 * 1024 * 1024UL;
/* should we fsync sometimes? */
static int funksync = 0;
/* are we just appending bytes onto the ends of the working set files */
static int append_mode = 0;
+static int truncate_original = 0;
+/* dont do any crc checks -I */
+static int ignore_crcs = 0;
/* randomize the write size */
static int oddsizes = 0;
/* use odirect sometimes */
@@ -92,9 +95,12 @@ static int odirect = 0;
/* check contents at startup */
static int check_initial_files = 0;
+/* verify files immediately after writing */
+static int verify_writes = 0;
+
/* -M how much memory we allocate to benchmark allocations */
-static int mmap_size = 64 * 1024 * 1024;
+static unsigned long mmap_size = 64 * 1024 * 1024;
/* these do nothing but spin */
static int cpu_threads = 24;
@@ -114,10 +120,10 @@ static uint64_t global_rand_seed = 0x89ABCEF;
* after warmup_seconds, we reset the counters to get rid of noise from
* early in the run
*/
-static int warmup_seconds = 60;
+static unsigned long warmup_seconds = 60;
/* reporting interval */
-static int interval_seconds = 120;
+static unsigned long interval_seconds = 120;
/* the master thread flips this to true when runtime is up */
static volatile unsigned long stopping = 0;
@@ -186,7 +192,7 @@ struct vmstat_info {
#define VERIFY_MAGIC_LEN 8
/* our verify blocks are pretty small, which allows us to sub-page writes */
-#define VERIFY_ALIGNMENT ((loff_t)1024)
+#define VERIFY_ALIGNMENT ((loff_t)512)
char pattern_buffer[VERIFY_ALIGNMENT];
struct verify_header {
@@ -197,7 +203,8 @@ struct verify_header {
uint64_t offset;
/* seed for recreating the random data */
uint64_t rand_seed;
- uint64_t spare[2];
+ uint64_t inode;
+ uint64_t spare[1];
/* VERIFY_MAGIC above (zero filled first) */
char magic[VERIFY_MAGIC_LEN];
};
@@ -243,8 +250,14 @@ static void init_pattern_buffer(char *buffer, uint64_t seed)
char *p = buffer;
srand(seed);
- for (i = 0; i < 128; i++)
- pattern[i] = rand();
+ pattern[0] = rand();
+ for (i = 1; i < 128; i++) {
+ /*
+ * we originally used data here, but this is easier for
+ * debugging memory corruptions
+ */
+ pattern[i] = 'd';
+ }
while(length > 0) {
if (length > 128)
@@ -258,7 +271,7 @@ static void init_pattern_buffer(char *buffer, uint64_t seed)
}
static void crc_block(void *xxhash_state, char *block, uint64_t offset,
- uint64_t length, uint64_t rand_seed)
+ uint64_t length, uint64_t rand_seed, uint64_t ino)
{
struct verify_header *verify_header = (struct verify_header *)block;
@@ -271,6 +284,7 @@ static void crc_block(void *xxhash_state, char *block, uint64_t offset,
verify_header->length = length;
verify_header->offset = offset;
verify_header->rand_seed = rand_seed;
+ verify_header->inode = ino;
strncpy(verify_header->magic, VERIFY_MAGIC, VERIFY_MAGIC_LEN);
verify_header->crc = __calc_crc(xxhash_state, verify_header);
@@ -313,30 +327,50 @@ static void dump_bad_block(char *block, uint64_t offset)
}
static void check_block_headers(void *xxhash_state, char *filename,
- char *block, uint64_t offset, uint64_t length)
+ char *block, uint64_t offset, uint64_t length,
+ uint64_t ino)
{
struct verify_header *verify_header = (struct verify_header *)block;
uint64_t crc;
+ int i;
+ int failed = 0;
+
+ if (ignore_crcs)
+ return;
+
+ if (verify_header->inode != ino) {
+ fprintf(stderr, "bad buffer inode file %s inode %lu found %lu offset %lu\n",
+ filename, ino, verify_header->inode, offset);
+ failed++;
+ }
if (strncmp(verify_header->magic, VERIFY_MAGIC, VERIFY_MAGIC_LEN)) {
fprintf(stderr, "bad magic file %s offset %lu\n", filename, offset);
- exit(1);
+ fprintf(stderr, "found: ");
+ for (i = 0; i < VERIFY_MAGIC_LEN; i++) {
+ fprintf(stderr, "[%x %x] ", verify_header->magic[i], VERIFY_MAGIC[i]);
+ }
+ fprintf(stderr, "\n");
+ failed++;
}
if (verify_header->offset != offset) {
fprintf(stderr, "bad offset file %s offset %lu found %lu\n",
filename, offset, verify_header->offset);
- exit(1);
+ failed++;
}
if (verify_header->length != length) {
- fprintf(stderr, "bad buffer length file %s length %lu found %lu\n",
- filename, length, verify_header->length);
- exit(1);
+ fprintf(stderr, "bad buffer length file %s length %lu found %lu offset %lu\n",
+ filename, length, verify_header->length, offset);
+ failed++;
}
crc = __calc_crc(xxhash_state, verify_header);
if (crc != verify_header->crc) {
fprintf(stderr, "bad crc file %s crc %lx found %lx\n",
filename, crc, verify_header->crc);
dump_bad_block(block, offset);
+ failed++;
+ }
+ if (failed) {
exit(1);
}
}
@@ -425,7 +459,7 @@ unsigned long long parse_size(char *s)
return ret;
}
-char *option_string = "t:s:C:c:r:n:f:FR:T:m:W:M:w:i:D:oaOVzN";
+char *option_string = "t:s:C:c:r:n:f:FR:T:m:W:M:w:i:D:oaOVzNIev";
static struct option long_options[] = {
{"appendmode", required_argument, 0, 'a'},
{"mmapsize", required_argument, 0, 'M'},
@@ -440,15 +474,18 @@ static struct option long_options[] = {
{"warmuptime", required_argument, 0, 'w'},
{"sleeptime", required_argument, 0, 's'},
{"interval", required_argument, 0, 'i'},
+ {"ignorecrcs", required_argument, 0, 'I'},
{"cputime", required_argument, 0, 'c'},
{"cputhreads", required_argument, 0, 'C'},
{"memory", required_argument, 0, 'm'},
{"funksync", no_argument, 0, 'F'},
{"oddsizes", no_argument, 0, 'o'},
{"odirect", no_argument, 0, 'O'},
- {"verifystartup", no_argument, 0, 'V'},
+ {"verify-writes", no_argument, 0, 'v'},
+ {"verify-startup", no_argument, 0, 'V'},
{"zallocate", no_argument, 0, 'z'},
{"nocleanup", no_argument, 0, 'N'},
+ {"erase", no_argument, 0, 'e'},
{"help", no_argument, 0, HELP_LONG_OPT},
{0, 0, 0, 0}
};
@@ -463,6 +500,8 @@ static void print_usage(void)
"\t-r (--runtime): How long to run before exiting (seconds, def: 30)\n"
"\t-w (--warmuptime): How long to warmup before resetting the stats (seconds, def: 60)\n"
"\t-i (--interval): Sleep time in seconds between latency reports (sec, def: 120\n"
+ "\t-I (--ignorecrcs): don't verify crcs\n"
+ "\t-v (--verify-writes): immediately verify files written (def: no)\n"
"\t-V (--verify-startup): Verify all files on startup (def: no)\n"
"\t-s (--sleeptime): Sleep time in usecs between worker loops (usec, def: 10000\n"
"\t-c (--cputime): How long to think during each worker loop (seconds, def: 3)\n"
@@ -478,6 +517,7 @@ static void print_usage(void)
"\t-O (--odirect): use O_DIRECT sometimes\n"
"\t-z (--zallocate): use fallocate for initial file creation\n"
"\t-N (--nocleanup): don't cleanup temp files from the last run\n"
+ "\t-e (--erase): delete the data files at the start of the run\n"
"\t dir1 [dir2 ... dirN]\n"
"\nall sizes are in bytes k,m,g,t modifiers can be used\n"
);
@@ -504,11 +544,15 @@ static void parse_options(int ac, char **av)
case 'a':
append_mode = 1;
break;
+ case 'e':
+ truncate_original = 1;
+ break;
case 's':
found_sleeptime = atoi(optarg);
break;
case 'm':
thinking_mem = parse_size(optarg);
+ fprintf(stderr, "thinking_mem %lu\n", thinking_mem);
break;
case 'M':
mmap_size = parse_size(optarg);
@@ -531,6 +575,9 @@ static void parse_options(int ac, char **av)
case 'i':
interval_seconds = atoi(optarg);
break;
+ case 'I':
+ ignore_crcs = 1;
+ break;
case 'F':
funksync = 1;
break;
@@ -562,6 +609,9 @@ static void parse_options(int ac, char **av)
case 'O':
odirect = 1;
break;
+ case 'v':
+ verify_writes = 1;
+ break;
case 'V':
check_initial_files = 1;
break;
@@ -904,6 +954,7 @@ static void join_path(char *name, char *path, int seq, char *postfix)
static void read_whole_file(char *path, int seq, char *postfix,
char *buf, size_t buf_size);
+static void read_whole_fd(int fd, char *name, char *buf, size_t buf_size);
/* unlink working files not part of the main dataset for a given filename. */
static void unlink_extra(char *path, int seq, char *buf, size_t buf_size)
@@ -941,13 +992,15 @@ static int open_path(char *path, int seq, char *postfix, int flags)
join_path(name, path, seq, postfix);
fd = open(name, O_RDWR | O_CREAT | flags, 0600);
if (fd < 0) {
+ if (errno == EEXIST)
+ return -EEXIST;
perror("open");
exit(1);
}
return fd;
}
-static loff_t randomize_size(int sz)
+static loff_t randomize_size(loff_t sz)
{
if (!oddsizes)
return sz;
@@ -1000,7 +1053,7 @@ static void maybe_toggle_odirect(int fd, unsigned long start,
return;
}
- if ((rand() % 3) != 0)
+ if ((rand() % 128) != 0)
return;
if (flags & O_DIRECT) {
@@ -1019,8 +1072,6 @@ static void send_pwrite(int fd, char *buf, loff_t start, ssize_t bytes)
{
ssize_t this_write;
int ret;
- int num_headers = bytes / VERIFY_ALIGNMENT;
- int index;
int i;
for (i = 0; i < 3; i++) {
@@ -1029,22 +1080,32 @@ static void send_pwrite(int fd, char *buf, loff_t start, ssize_t bytes)
* the goal here is to break up our huge IO into
* something that isn't completely page aligned.
*/
- index = rand() % num_headers;
- num_headers -= index;
- this_write = index * VERIFY_ALIGNMENT;
- bytes -= this_write;
+ this_write = VERIFY_ALIGNMENT;
while (this_write > 0) {
+ int ret2;
+
+ if (this_write > bytes)
+ break;
+
ret = pwrite(fd, buf, this_write, start);
if (ret <= 0) {
perror("pwrite");
exit(1);
}
+
+ ret2 = sync_file_range(fd, start, this_write, SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER);
+ if (ret2) {
+ perror("sync_file_range");
+ exit(1);
+ }
+
start += ret;
this_write -= ret;
buf += ret;
+ bytes -= ret;
}
maybe_fsync(fd);
- if (bytes == 0)
+ if (bytes <= 0)
break;
}
@@ -1058,11 +1119,17 @@ static void send_pwrite(int fd, char *buf, loff_t start, ssize_t bytes)
bytes -= ret;
buf += ret;
}
+ ret = sync_file_range(fd, start, bytes, SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER);
+ if (ret) {
+ perror("sync_file_range");
+ exit(1);
+ }
maybe_fsync(fd);
}
static void write_pattern(int fd, void *xxhash_state, char *buf,
- int buffer_len, loff_t start, off_t length)
+ int buffer_len, loff_t start, off_t length,
+ uint64_t ino)
{
loff_t aligned_start;
char *p;
@@ -1088,7 +1155,7 @@ static void write_pattern(int fd, void *xxhash_state, char *buf,
while (cur_len < this_write) {
memcpy(p, pattern_buffer, VERIFY_ALIGNMENT);
crc_block(xxhash_state, p, aligned_start + cur_len,
- VERIFY_ALIGNMENT, global_rand_seed);
+ VERIFY_ALIGNMENT, global_rand_seed, ino);
cur_len += VERIFY_ALIGNMENT;
p += VERIFY_ALIGNMENT;
}
@@ -1102,7 +1169,7 @@ static void write_pattern(int fd, void *xxhash_state, char *buf,
static void read_and_crc(int fd, char *filename,
void **xxhash_state, char *buf,
- int buffer_len, loff_t start, off_t length)
+ int buffer_len, loff_t start, off_t length, uint64_t ino)
{
ssize_t ret;
loff_t aligned_start;
@@ -1123,19 +1190,22 @@ static void read_and_crc(int fd, char *filename,
else
this_read = length;
maybe_toggle_odirect(fd, aligned_start, this_read);
+ ret = posix_fadvise(fd, aligned_start, this_read, POSIX_FADV_DONTNEED);
+ if (ret) {
+ perror("fadvise");
+ }
ret = pread(fd, buf, this_read, aligned_start);
if (ret != this_read) {
- /* someone is deleting this file at the same time
- * we're reading it
- */
- break;
+ fprintf(stderr, "bad read length %ld wanted %ld offset %lu file %s\n", ret, this_read, aligned_start, filename);
+ exit(1);
}
+
p = buf;
cur_len = 0;
while (cur_len < this_read) {
check_block_headers(xxhash_state, filename,
p, aligned_start + cur_len,
- VERIFY_ALIGNMENT);
+ VERIFY_ALIGNMENT, ino);
cur_len += VERIFY_ALIGNMENT;
p += VERIFY_ALIGNMENT;
}
@@ -1160,10 +1230,12 @@ static void fill_one_file(int fd, void *xxhash_state, char *buf, size_t buf_size
}
cur_size = st.st_size;
- if (cur_size >= this_size)
+ if (cur_size >= this_size) {
+ ftruncate(fd, this_size);
return;
+ }
- write_pattern(fd, xxhash_state, buf, buf_size, cur_size, this_size - cur_size);
+ write_pattern(fd, xxhash_state, buf, buf_size, cur_size, this_size - cur_size, st.st_ino);
}
/*
@@ -1261,7 +1333,7 @@ static void read_from_file(char *path, int seq, char *buf)
read_bytes = verify_align(st.st_size);
read_and_crc(fd, name, xxhash_state, buf, read_bytes, offset,
- read_bytes);
+ read_bytes, st.st_ino);
/* if we don't have writers making dirty inodes, make some here */
if (!write_size) {
@@ -1272,26 +1344,17 @@ static void read_from_file(char *path, int seq, char *buf)
XXH32_digest(xxhash_state);
}
-static void read_whole_file(char *path, int seq, char *postfix,
- char *buf, size_t buf_size)
+static void read_whole_fd(int fd, char *name, char *buf, size_t buf_size)
{
- int fd;
int ret;
- int i;
off_t offset;
ssize_t read_bytes = buf_size;
struct stat st;
void *xxhash_state;
- char name[NAME_LEN];
if (read_size == 0)
return;
- join_path(name, path, seq, postfix);
- fd = open(name, O_RDONLY, 0600);
- if (fd < 0)
- return;
-
ret = fstat(fd, &st);
if (ret < 0)
return;
@@ -1300,17 +1363,29 @@ static void read_whole_file(char *path, int seq, char *postfix,
offset = 0;
read_and_crc(fd, name, xxhash_state, buf, read_bytes, offset,
- st.st_size);
+ st.st_size, st.st_ino);
- /* if we don't have writers making dirty inodes, make some here */
- if (!write_size) {
- for (i = 0; i < 8; i++)
- dirty_an_inode(path);
- }
- close(fd);
XXH32_digest(xxhash_state);
}
+static void read_whole_file(char *path, int seq, char *postfix,
+ char *buf, size_t buf_size)
+{
+ int fd;
+ char name[NAME_LEN];
+
+ if (buf_size == 0)
+ return;
+
+ join_path(name, path, seq, postfix);
+ fd = open(name, O_RDONLY, 0600);
+ if (fd < 0)
+ return;
+
+ read_whole_fd(fd, name, buf, buf_size);
+ close(fd);
+}
+
/* creates a temp file in one of the subdirs and sends down write_bytes to it */
static void write_to_file(char *path, int seq, char *buf)
{
@@ -1321,20 +1396,24 @@ static void write_to_file(char *path, int seq, char *buf)
loff_t offset;
void *xxhash_state = XXH32_init(global_rand_seed);
char *postfix;
+ struct stat st;
char name[NAME_LEN];
if (append_mode) {
postfix = DATA_FILE;
- fd = open_path(path, seq, DATA_FILE, O_APPEND|O_CREAT);
- offset = lseek(fd, 0, SEEK_CUR);
+ fd = open_path(path, seq, DATA_FILE, O_CREAT);
+ offset = lseek(fd, 0, SEEK_END);
if (offset < 0) {
perror("lseek");
exit(1);
}
+ join_path(name, path, seq, postfix);
+
} else {
postfix = RESULT_FILE;
join_path(name, path, seq, postfix);
- /* make sure that we're making new inodes for the result
+ /*
+ * make sure that we're making new inodes for the result
* files
*/
ret = unlink(name);
@@ -1342,15 +1421,19 @@ static void write_to_file(char *path, int seq, char *buf)
perror("unlink");
exit(1);
}
- fd = open_path(path, seq, RESULT_FILE, 0);
+ fd = open_path(path, seq, RESULT_FILE, O_CREAT|O_EXCL);
+ if (fd < 0) {
+ return;
+ }
offset = 0;
}
+ ret = fstat(fd, &st);
+ if (ret < 0) {
+ perror("stat");
+ exit(1);
+ }
- write_pattern(fd, xxhash_state, buf, write_size, offset, write_bytes * 4);
-
- join_path(name, path, seq, postfix);
- read_and_crc(fd, name, xxhash_state, buf, write_size, offset,
- write_bytes * 4);
+ write_pattern(fd, xxhash_state, buf, write_size, offset, write_bytes * 4, st.st_ino);
XXH32_digest(xxhash_state);
@@ -1358,31 +1441,11 @@ static void write_to_file(char *path, int seq, char *buf)
if (!append_mode) {
for (i = 0; i < 8; i++)
dirty_an_inode(path);
- } else if (rand() % 10 == 0) {
- /* delete some files */
- ftruncate(fd, 0);
}
+ sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER);
+ if (verify_writes && write_size >= BUF_SIZE)
+ read_whole_fd(fd, name, buf, BUF_SIZE);
- /*
- * lets create some churn of inodes coming in and out and abuse
- * the orphan code while we're here
- */
- if (rand() % 3 == 0) {
- /*
- * make sure the extents actually get allocated and work
- * is done
- */
- ret = sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WRITE);
- if (ret < 0) {
- perror("sync_file_range");
- exit(1);
- }
- ret = unlink(name);
- if (ret < 0 && errno != ENOENT) {
- perror("unlink");
- exit(1);
- }
- }
close(fd);
}
@@ -1408,15 +1471,25 @@ static void make_files(char *path, unsigned long seq_start,
read_whole_file(path, seq, DATA_FILE, buf, BUF_SIZE);
if (zallocate) {
+ char *kind;
loff_t this_size = randomize_size(file_size);
- fd = open_path(path, seq, FILL_FILE, O_CREAT);
+
+ if (ignore_crcs)
+ kind = DATA_FILE;
+ else
+ kind = FILL_FILE;
+
+ fd = open_path(path, seq, kind, O_CREAT);
ret = fallocate(fd, 0, 0, this_size);
if (ret) {
perror("fallocate");
exit(1);
}
} else {
- fd = open_path(path, seq, DATA_FILE, O_APPEND);
+ int flags = O_CREAT|O_APPEND;
+ if (truncate_original)
+ flags |= O_TRUNC;
+ fd = open_path(path, seq, DATA_FILE, flags);
fill_one_file(fd, xxhash_state, buf, BUF_SIZE);
}
close(fd);
@@ -1493,19 +1566,22 @@ void run_filler_threads(void)
void *read_thread(void *arg)
{
- int index = rand() % total_paths;
- int seq = rand() % num_files;
- char *path = paths[index];
+ int i;
char *buf = arg;
- read_from_file(path, seq, buf);
+ for (i = 0; i < 4; i++) {
+ int index = rand() % total_paths;
+ int seq = rand() % num_files;
+ char *path = paths[index];
+ read_from_file(path, seq, buf);
+ }
return NULL;
}
/* startup reader threads, returns the tids for later waiting */
void read_some_files(char *buf, pthread_t *tids)
{
- int i;
+ unsigned long i;
int ret;
for (i = 0; i < rw_threads; i++) {
@@ -1522,19 +1598,22 @@ void read_some_files(char *buf, pthread_t *tids)
void *write_thread(void *arg)
{
- int index = rand() % total_paths;
- int seq = rand() % num_files;
- char *path = paths[index];
char *buf = arg;
+ int i;
- write_to_file(path, seq, buf);
+ for (i = 0; i < 4; i++) {
+ int index = rand() % total_paths;
+ int seq = rand() % num_files;
+ char *path = paths[index];
+ write_to_file(path, seq, buf);
+ }
return NULL;
}
/* startup writer threads, returns the tids for later waiting */
void write_some_files(char *buf, pthread_t *tids)
{
- int i;
+ unsigned long i;
int ret;
for (i = 0; i < rw_threads; i++) {
@@ -1549,6 +1628,34 @@ void write_some_files(char *buf, pthread_t *tids)
}
}
+char *aligned_memory_alloc(unsigned long size)
+{
+ char *ptr;
+ unsigned long aligned_size = (size + 4095) & ~4095UL;
+ int ret;
+
+ ptr = mmap(NULL, aligned_size,
+ PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (ptr == MAP_FAILED) {
+ perror("mmap");
+ exit(1);
+ }
+ ret = madvise(ptr, aligned_size, MADV_HUGEPAGE);
+ if (ret) {
+ perror("madvise huge");
+ exit(1);
+ }
+ return ptr;
+}
+
+void aligned_memory_free(char *ptr, unsigned long size)
+{
+ unsigned long aligned_size = (size + 4095) & ~4095UL;
+
+ if (ptr)
+ munmap(ptr, aligned_size);
+}
+
/* main work loop */
void *worker_thread(void *arg)
{
@@ -1562,8 +1669,7 @@ void *worker_thread(void *arg)
pthread_t *write_tids;
char *mmap_ptr;
int warmup_zerod = 0;
- int i;
- int ret;
+ unsigned long i;
read_tids = malloc(sizeof(*read_tids) * rw_threads);
write_tids = malloc(sizeof(*write_tids) * rw_threads);
@@ -1584,13 +1690,14 @@ void *worker_thread(void *arg)
memset(td->stats, 0, sizeof(*td->stats) * TOTAL_STATS);
warmup_zerod = 1;
}
- ret = posix_memalign((void **)(&read_buf), getpagesize(), rw_threads * read_size);
- ret |= posix_memalign((void **)(&write_buf), getpagesize(), rw_threads * write_size);
-
- if (ret) {
- perror("allocation");
- exit(1);
- }
+ if (read_size)
+ read_buf = aligned_memory_alloc(rw_threads * read_size);
+ else
+ read_buf = NULL;
+ if (write_size)
+ write_buf = aligned_memory_alloc(rw_threads * write_size);
+ else
+ write_buf = NULL;
/* if someone swapped out our thinking mem, bring it back */
if (thinking_mem)
@@ -1637,7 +1744,6 @@ void *worker_thread(void *arg)
*/
if (mmap_size) {
gettimeofday(&start, NULL);
-
mmap_ptr = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE,
-1, 0);
@@ -1656,13 +1762,12 @@ void *worker_thread(void *arg)
gettimeofday(&now, NULL);
record_one_lat(&td->stats[ALLOC_STATS], &start, &now);
- /* think again, pretending we've done something useful */
munmap(mmap_ptr, mmap_size);
}
usec_spin(cputime);
- free(read_buf);
- free(write_buf);
+ aligned_memory_free(read_buf, rw_threads * read_size);
+ aligned_memory_free(write_buf, rw_threads * write_size);
td->work_done++;
if (sleeptime)
@@ -1856,7 +1961,7 @@ static void sleep_for_runtime(struct thread_data *worker_threads_mem)
delta = tvdelta(&start, &now);
if (!warmup_done && delta > warmup_usec) {
- printf("Warmup complete (%d seconds)\n", warmup_seconds);
+ printf("Warmup complete (%lu seconds)\n", warmup_seconds);
__sync_synchronize();
warmup_done = 1;
memset(&work_done_stats, 0, sizeof(work_done_stats));
@@ -1894,9 +1999,10 @@ static void sleep_for_runtime(struct thread_data *worker_threads_mem)
}
__sync_synchronize();
stopping = 1;
+ fprintf(stderr, "stopping, runtime_usec %Lu delta %Lu\n", runtime_usec, delta);
- for (i = 0; i < cpu_threads; i++) {
- pthread_join(worker_threads_mem[i + worker_threads].tid, NULL);
+ for (i = 0; i < cpu_threads + worker_threads; i++) {
+ pthread_join(worker_threads_mem[i].tid, NULL);
}
work_done = 0;
@@ -1993,5 +2099,6 @@ int main(int ac, char **av)
}
free(worker_threads_mem);
+ fprintf(stderr, "normal exit\n");
return 0;
}