From 3af915aae1c9ce52b71640512c83393774aeb641 Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Fri, 22 Jan 2021 12:10:09 +0000 Subject: [PATCH 1/4] MDTest data verification. Fixed bug: added missing reduce. Add rank into I/O buffer to make individual files unique. --- src/mdtest.c | 52 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/mdtest.c b/src/mdtest.c index 48ca7b8..58d644d 100644 --- a/src/mdtest.c +++ b/src/mdtest.c @@ -219,10 +219,16 @@ void VerboseMessage (int root_level, int any_level, int line, char * format, ... } } -void generate_memory_pattern(char * buffer, size_t bytes){ - // the first byte is set to the item number - for(int i=1; i < bytes; i++){ - buffer[i] = i + 1; +void generate_memory_pattern(char * buf, size_t bytes){ + uint64_t * buffi = (uint64_t*) buf; + // first half of 64 bits use the rank + uint64_t ranki = (uint64_t)(rank + 1) << 32; + // the first 8 bytes are set to item number + for(size_t i=1; i < bytes/8; i++){ + buffi[i] = (i + 1) + ranki; + } + for(size_t i=(bytes/8)*8; i < bytes; i++){ + buf[i] = (char) i; } } @@ -349,19 +355,31 @@ static void remove_file (const char *path, uint64_t itemNum) { } } -void mdtest_verify_data(int item, char * buffer, size_t bytes){ +void mdtest_verify_data(int item, char * buffer, size_t bytes, int pretendRank){ if((bytes >= 8 && ((uint64_t*) buffer)[0] != item) || (bytes < 8 && buffer[0] != (char) item)){ VERBOSE(2, -1, "Error verifying first element for item: %d", item); o.verification_error++; + return; } - size_t i = bytes < 8 ? 1 : 8; // the first byte - - for( ; i < bytes; i++){ - if(buffer[i] != (char) (i + 1)){ + uint64_t * buffi = (uint64_t*) buffer; + // first half of 64 bits use the rank, here need to apply rank shifting + uint64_t rank_mod = (uint64_t)(pretendRank + 1) << 32; + // the first 8 bytes are set to item number + for(size_t i=1; i < bytes/8; i++){ + uint64_t exp = (i + 1) + rank_mod; + if(buffi[i] != exp){ + VERBOSE(5, -1, "Error verifying offset %zu for item %d", i*8, item); + printf("%lld != %lld\n", exp, buffi[i]); + o.verification_error++; + return; + } + } + for(size_t i=(bytes/8)*8; i < bytes; i++){ + if(buffer[i] != (char) i){ VERBOSE(5, -1, "Error verifying byte %zu for item %d", i, item); o.verification_error++; - break; + return; } } } @@ -432,7 +450,7 @@ static void create_file (const char *path, uint64_t itemNum) { if (o.write_bytes != (size_t) o.backend->xfer(READ, aiori_fh, (IOR_size_t *) o.write_buffer, o.write_bytes, 0, o.backend_options)) { EWARNF("unable to verify write (read/back) file %s", curr_item); } - mdtest_verify_data(itemNum, o.write_buffer, o.write_bytes); + mdtest_verify_data(itemNum, o.write_buffer, o.write_bytes, rank); } } @@ -753,7 +771,11 @@ void mdtest_read(int random, int dirs, const long dir_iter, char *path) { continue; } if(o.verify_read){ - mdtest_verify_data(item_num, read_buffer, o.read_bytes); + int pretend_rank = (2 * o.nstride + rank) % o.size; + if (o.shared_file) { + pretend_rank = rank; + } + mdtest_verify_data(item_num, read_buffer, o.read_bytes, pretend_rank); }else if((o.read_bytes >= 8 && ((uint64_t*) read_buffer)[0] != item_num) || (o.read_bytes < 8 && read_buffer[0] != (char) item_num)){ // do a lightweight check, which cost is neglectable o.verification_error++; @@ -2431,8 +2453,10 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * FAIL("Unable to remove test directory path %s", o.testdirpath); } - if(o.verification_error){ - VERBOSE(0, -1, "\nERROR: verifying the data read! Take the performance values with care!\n"); + int total_errors; + MPI_Reduce(& o.verification_error, & total_errors, 1, MPI_INT, MPI_SUM, 0, testComm); + if(total_errors){ + VERBOSE(0, -1, "\nERROR: verifying the data on read (%lld errors)! Take the performance values with care!\n", total_errors); } VERBOSE(0,-1,"-- finished at %s --\n", PrintTimestamp()); From effcb4131c5d15a35b1f5d1a601c3f5df6c17ea3 Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Fri, 22 Jan 2021 12:24:33 +0000 Subject: [PATCH 2/4] MDTest: add randomness to buffers to defend dedup efforts. Allow to set random offset externally. --- src/mdtest.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/mdtest.c b/src/mdtest.c index 58d644d..27e4d7d 100644 --- a/src/mdtest.c +++ b/src/mdtest.c @@ -124,6 +124,7 @@ typedef struct { int leaf_only; unsigned branch_factor; int depth; + int random_buffer_offset; /* user settable value, otherwise random */ /* * This is likely a small value, but it's sometimes computed by @@ -222,7 +223,7 @@ void VerboseMessage (int root_level, int any_level, int line, char * format, ... void generate_memory_pattern(char * buf, size_t bytes){ uint64_t * buffi = (uint64_t*) buf; // first half of 64 bits use the rank - uint64_t ranki = (uint64_t)(rank + 1) << 32; + uint64_t ranki = (uint64_t)(rank + 1) << 32 + o.random_buffer_offset; // the first 8 bytes are set to item number for(size_t i=1; i < bytes/8; i++){ buffi[i] = (i + 1) + ranki; @@ -364,13 +365,12 @@ void mdtest_verify_data(int item, char * buffer, size_t bytes, int pretendRank){ uint64_t * buffi = (uint64_t*) buffer; // first half of 64 bits use the rank, here need to apply rank shifting - uint64_t rank_mod = (uint64_t)(pretendRank + 1) << 32; + uint64_t rank_mod = (uint64_t)(pretendRank + 1) << 32 + o.random_buffer_offset; // the first 8 bytes are set to item number for(size_t i=1; i < bytes/8; i++){ uint64_t exp = (i + 1) + rank_mod; if(buffi[i] != exp){ VERBOSE(5, -1, "Error verifying offset %zu for item %d", i*8, item); - printf("%lld != %lld\n", exp, buffi[i]); o.verification_error++; return; } @@ -2062,7 +2062,8 @@ static void mdtest_iteration(int i, int j, MPI_Group testgroup, mdtest_results_t void mdtest_init_args(){ o = (mdtest_options_t) { .barriers = 1, - .branch_factor = 1 + .branch_factor = 1, + .random_buffer_offset = -1 }; } @@ -2116,6 +2117,7 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * #ifdef HAVE_LUSTRE_LUSTREAPI {'g', NULL, "global default directory layout for test subdirectories (deletes inherited striping layout)", OPTION_FLAG, 'd', & o.global_dir_layout}, #endif /* HAVE_LUSTRE_LUSTREAPI */ + {'G', NULL, "Offset for the data in the read/write buffer, if not set, a random value is used", OPTION_OPTIONAL_ARGUMENT, 'd', & o.random_buffer_offset}, {'i', NULL, "number of iterations the test will run", OPTION_OPTIONAL_ARGUMENT, 'd', & iterations}, {'I', NULL, "number of items per directory in tree", OPTION_OPTIONAL_ARGUMENT, 'l', & o.items_per_dir}, {'k', NULL, "use mknod to create file", OPTION_FLAG, 'd', & o.make_node}, @@ -2202,6 +2204,10 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * } o.random_seed += rank; } + if( o.random_buffer_offset == -1 ){ + o.random_buffer_offset = time(NULL); + MPI_Bcast(& o.random_buffer_offset, 1, MPI_INT, 0, testComm); + } if ((o.items > 0) && (o.items_per_dir > 0) && (! o.unique_dir_per_task)) { o.directory_loops = o.items / o.items_per_dir; }else{ From 7061b60ed8d4853411a8a9b1d8ceff1c8035e8d0 Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Fri, 22 Jan 2021 14:05:58 +0000 Subject: [PATCH 3/4] Extracted memory pattern comparison, added mem check option to md-workbench. --- src/md-workbench.c | 45 +++++++++++++++++++++++++------------- src/mdtest.c | 54 +++++----------------------------------------- src/utilities.c | 47 ++++++++++++++++++++++++++++++++++++++++ src/utilities.h | 5 +++++ 4 files changed, 87 insertions(+), 64 deletions(-) diff --git a/src/md-workbench.c b/src/md-workbench.c index b9b1b23..e7213b9 100644 --- a/src/md-workbench.c +++ b/src/md-workbench.c @@ -115,6 +115,7 @@ struct benchmark_options{ int ignore_precreate_errors; int rank; int size; + int verify_read; float relative_waiting_factor; int adaptive_waiting_mode; @@ -549,7 +550,7 @@ void run_precreate(phase_stat_t * s, int current_index){ } char * buf = malloc(o.file_size); - memset(buf, o.rank % 256, o.file_size); + generate_memory_pattern(buf, o.file_size, 0, o.rank); double op_timer; // timer for individual operations size_t pos = -1; // position inside the individual measurement array double op_time; @@ -565,6 +566,7 @@ void run_precreate(phase_stat_t * s, int current_index){ if (NULL == aiori_fh){ FAIL("Unable to open file %s", obj_name); } + update_write_memory_pattern(f * o.dset_count + d, buf, o.file_size, 0, o.rank); if ( o.file_size == (int) o.backend->xfer(WRITE, aiori_fh, (IOR_size_t *) buf, o.file_size, 0, o.backend_options)) { s->obj_create.suc++; }else{ @@ -643,11 +645,19 @@ void run_benchmark(phase_stat_t * s, int * current_index_p){ if (NULL == aiori_fh){ FAIL("Unable to open file %s", obj_name); } - if ( o.file_size == (int) o.backend->xfer(READ, aiori_fh, (IOR_size_t *) buf, o.file_size, 0, o.backend_options)) { - s->obj_read.suc++; + if ( o.file_size == (int) o.backend->xfer(READ, aiori_fh, (IOR_size_t *) buf, o.file_size, 0, o.backend_options) ) { + if(o.verify_read){ + if(verify_memory_pattern(f * o.dset_count + d, buf, o.file_size, 0, readRank) == 0){ + s->obj_read.suc++; + }else{ + s->obj_read.err++; + } + }else{ + s->obj_read.suc++; + } }else{ s->obj_read.err++; - ERRF("%d: Error while reading the obj: %s\n", o.rank, obj_name); + EWARNF("%d: Error while reading the obj: %s", o.rank, obj_name); } o.backend->close(aiori_fh, o.backend_options); @@ -676,19 +686,23 @@ void run_benchmark(phase_stat_t * s, int * current_index_p){ op_timer = GetTimeStamp(); aiori_fh = o.backend->create(obj_name, IOR_WRONLY | IOR_CREAT, o.backend_options); - if (NULL == aiori_fh){ - FAIL("Unable to open file %s", obj_name); - } - if ( o.file_size == (int) o.backend->xfer(WRITE, aiori_fh, (IOR_size_t *) buf, o.file_size, 0, o.backend_options)) { - s->obj_create.suc++; - }else{ - s->obj_create.err++; - if (! o.ignore_precreate_errors){ - ERRF("%d: Error while creating the obj: %s\n", o.rank, obj_name); + if (NULL != aiori_fh){ + if ( o.file_size == (int) o.backend->xfer(WRITE, aiori_fh, (IOR_size_t *) buf, o.file_size, 0, o.backend_options)) { + s->obj_create.suc++; + }else{ + s->obj_create.err++; + if (! o.ignore_precreate_errors){ + ERRF("%d: Error while creating the obj: %s\n", o.rank, obj_name); + } } + o.backend->close(aiori_fh, o.backend_options); + }else{ + if (! o.ignore_precreate_errors){ + ERRF("Unable to open file %s", obj_name); + } + EWARNF("Unable to open file %s", obj_name); + s->obj_create.err++; } - o.backend->close(aiori_fh, o.backend_options); - bench_runtime = add_timed_result(op_timer, s->phase_start_timer, s->time_create, pos, & s->max_op_time, & op_time); if(o.relative_waiting_factor > 1e-9) { mdw_wait(op_time); @@ -800,6 +814,7 @@ static option_help options [] = { {'3', "run-cleanup", "Run cleanup phase (only run explicit phases)", OPTION_FLAG, 'd', & o.phase_cleanup}, {'w', "stonewall-timer", "Stop each benchmark iteration after the specified seconds (if not used with -W this leads to process-specific progress!)", OPTION_OPTIONAL_ARGUMENT, 'd', & o.stonewall_timer}, {'W', "stonewall-wear-out", "Stop with stonewall after specified time and use a soft wear-out phase -- all processes perform the same number of iterations", OPTION_FLAG, 'd', & o.stonewall_timer_wear_out}, + {'X', "verify-read", "Verify the data on read", OPTION_FLAG, 'd', & o.verify_read}, {0, "start-item", "The iteration number of the item to start with, allowing to offset the operations", OPTION_OPTIONAL_ARGUMENT, 'l', & o.start_item_number}, {0, "print-detailed-stats", "Print detailed machine parsable statistics.", OPTION_FLAG, 'd', & o.print_detailed_stats}, {0, "read-only", "Run read-only during benchmarking phase (no deletes/writes), probably use with -2", OPTION_FLAG, 'd', & o.read_only}, diff --git a/src/mdtest.c b/src/mdtest.c index 27e4d7d..ac9bdc4 100644 --- a/src/mdtest.c +++ b/src/mdtest.c @@ -220,24 +220,10 @@ void VerboseMessage (int root_level, int any_level, int line, char * format, ... } } -void generate_memory_pattern(char * buf, size_t bytes){ - uint64_t * buffi = (uint64_t*) buf; - // first half of 64 bits use the rank - uint64_t ranki = (uint64_t)(rank + 1) << 32 + o.random_buffer_offset; - // the first 8 bytes are set to item number - for(size_t i=1; i < bytes/8; i++){ - buffi[i] = (i + 1) + ranki; - } - for(size_t i=(bytes/8)*8; i < bytes; i++){ - buf[i] = (char) i; - } -} - void offset_timers(double * t, int tcount) { double toffset; int i; - VERBOSE(1,-1,"V-1: Entering offset_timers..." ); toffset = GetTimeStamp() - t[tcount]; @@ -356,33 +342,6 @@ static void remove_file (const char *path, uint64_t itemNum) { } } -void mdtest_verify_data(int item, char * buffer, size_t bytes, int pretendRank){ - if((bytes >= 8 && ((uint64_t*) buffer)[0] != item) || (bytes < 8 && buffer[0] != (char) item)){ - VERBOSE(2, -1, "Error verifying first element for item: %d", item); - o.verification_error++; - return; - } - - uint64_t * buffi = (uint64_t*) buffer; - // first half of 64 bits use the rank, here need to apply rank shifting - uint64_t rank_mod = (uint64_t)(pretendRank + 1) << 32 + o.random_buffer_offset; - // the first 8 bytes are set to item number - for(size_t i=1; i < bytes/8; i++){ - uint64_t exp = (i + 1) + rank_mod; - if(buffi[i] != exp){ - VERBOSE(5, -1, "Error verifying offset %zu for item %d", i*8, item); - o.verification_error++; - return; - } - } - for(size_t i=(bytes/8)*8; i < bytes; i++){ - if(buffer[i] != (char) i){ - VERBOSE(5, -1, "Error verifying byte %zu for item %d", i, item); - o.verification_error++; - return; - } - } -} static void create_file (const char *path, uint64_t itemNum) { char curr_item[MAX_PATHLEN]; @@ -436,11 +395,8 @@ static void create_file (const char *path, uint64_t itemNum) { * offset 0 (zero). */ o.hints.fsyncPerWrite = o.sync_file; - if(o.write_bytes >= 8){ // set the item number as first element of the buffer to be as much unique as possible - ((uint64_t*) o.write_buffer)[0] = itemNum; - }else{ - o.write_buffer[0] = (char) itemNum; - } + update_write_memory_pattern(itemNum, o.write_buffer, o.write_bytes, o.random_buffer_offset, rank); + if ( o.write_bytes != (size_t) o.backend->xfer(WRITE, aiori_fh, (IOR_size_t *) o.write_buffer, o.write_bytes, 0, o.backend_options)) { EWARNF("unable to write file %s", curr_item); } @@ -450,7 +406,7 @@ static void create_file (const char *path, uint64_t itemNum) { if (o.write_bytes != (size_t) o.backend->xfer(READ, aiori_fh, (IOR_size_t *) o.write_buffer, o.write_bytes, 0, o.backend_options)) { EWARNF("unable to verify write (read/back) file %s", curr_item); } - mdtest_verify_data(itemNum, o.write_buffer, o.write_bytes, rank); + o.verification_error += verify_memory_pattern(itemNum, o.write_buffer, o.write_bytes, o.random_buffer_offset, rank); } } @@ -775,7 +731,7 @@ void mdtest_read(int random, int dirs, const long dir_iter, char *path) { if (o.shared_file) { pretend_rank = rank; } - mdtest_verify_data(item_num, read_buffer, o.read_bytes, pretend_rank); + o.verification_error += verify_memory_pattern(item_num, read_buffer, o.read_bytes, o.random_buffer_offset, pretend_rank); }else if((o.read_bytes >= 8 && ((uint64_t*) read_buffer)[0] != item_num) || (o.read_bytes < 8 && read_buffer[0] != (char) item_num)){ // do a lightweight check, which cost is neglectable o.verification_error++; @@ -2333,7 +2289,7 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * if (alloc_res) { FAIL("out of memory"); } - generate_memory_pattern(o.write_buffer, o.write_bytes); + generate_memory_pattern(o.write_buffer, o.write_bytes, o.random_buffer_offset, rank); } /* setup directory path to work in */ diff --git a/src/utilities.c b/src/utilities.c index 6b0871f..16a31b0 100755 --- a/src/utilities.c +++ b/src/utilities.c @@ -71,6 +71,53 @@ enum OutputFormat_t outputFormat; /***************************** F U N C T I O N S ******************************/ +void update_write_memory_pattern(uint64_t item, char * buf, size_t bytes, int buff_offset, int rank){ + if(bytes >= 8){ // set the item number as first element of the buffer to be as much unique as possible + ((uint64_t*) buf)[0] = item; + }else{ + buf[0] = (char) item; + } +} + +void generate_memory_pattern(char * buf, size_t bytes, int buff_offset, int rank){ + uint64_t * buffi = (uint64_t*) buf; + // first half of 64 bits use the rank + const uint64_t ranki = (uint64_t)(rank + 1) << 32 + buff_offset; + const size_t size = bytes / 8; + // the first 8 bytes are set to item number + for(size_t i=1; i < size; i++){ + buffi[i] = (i + 1) + ranki; + } + for(size_t i=(bytes/8)*8; i < bytes; i++){ + buf[i] = (char) i; + } +} + +int verify_memory_pattern(int item, char * buffer, size_t bytes, int buff_offset, int pretendRank){ + int error = 0; + // always read all data to ensure that performance numbers stay the same + if((bytes >= 8 && ((uint64_t*) buffer)[0] != item) || (bytes < 8 && buffer[0] != (char) item)){ + error = 1; + } + + uint64_t * buffi = (uint64_t*) buffer; + // first half of 64 bits use the rank, here need to apply rank shifting + uint64_t rank_mod = (uint64_t)(pretendRank + 1) << 32 + buff_offset; + // the first 8 bytes are set to item number + for(size_t i=1; i < bytes/8; i++){ + uint64_t exp = (i + 1) + rank_mod; + if(buffi[i] != exp){ + error = 1; + } + } + for(size_t i=(bytes/8)*8; i < bytes; i++){ + if(buffer[i] != (char) i){ + error = 1; + } + } + return error; +} + void* safeMalloc(uint64_t size){ void * d = malloc(size); if (d == NULL){ diff --git a/src/utilities.h b/src/utilities.h index b0be545..202bcad 100755 --- a/src/utilities.h +++ b/src/utilities.h @@ -35,6 +35,11 @@ extern enum OutputFormat_t outputFormat; /* format of the output */ void* safeMalloc(uint64_t size); void set_o_direct_flag(int *fd); +void update_write_memory_pattern(uint64_t item, char * buf, size_t bytes, int buff_offset, int rank); +void generate_memory_pattern(char * buf, size_t bytes, int buff_offset, int rank); +/* check a data buffer, @return 0 if all is correct, otherwise 1 */ +int verify_memory_pattern(int item, char * buffer, size_t bytes, int buff_offset, int pretendRank); + char *CurrentTimeString(void); int Regex(char *, char *); void ShowFileSystemSize(char * filename, const struct ior_aiori * backend, void * backend_options); From 0a066d8285fbbe8f0843a1b98745c58c280d5465 Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Fri, 22 Jan 2021 14:38:36 +0000 Subject: [PATCH 4/4] MD-Worbench: add -G option to set parameter. --- src/md-workbench.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/md-workbench.c b/src/md-workbench.c index e7213b9..672a73a 100644 --- a/src/md-workbench.c +++ b/src/md-workbench.c @@ -116,6 +116,7 @@ struct benchmark_options{ int rank; int size; int verify_read; + int random_buffer_offset; float relative_waiting_factor; int adaptive_waiting_mode; @@ -134,16 +135,17 @@ static void def_obj_name(char * out_name, int n, int d, int i){ } void init_options(){ - memset(& o, 0, sizeof(o)); - o.interface = "POSIX"; - o.prefix = "./out"; - o.num = 1000; - o.precreate = 3000; - o.dset_count = 10; - o.offset = 1; - o.iterations = 3; - o.file_size = 3901; - o.run_info_file = "md-workbench.status"; + o = (struct benchmark_options){ + .interface = "POSIX", + .prefix = "./out", + .num = 1000, + .random_buffer_offset = -1, + .precreate = 3000, + .dset_count = 10, + .offset = 1, + .iterations = 3, + .file_size = 3901, + .run_info_file = "md-workbench.status"}; } static void mdw_wait(double runtime){ @@ -550,7 +552,7 @@ void run_precreate(phase_stat_t * s, int current_index){ } char * buf = malloc(o.file_size); - generate_memory_pattern(buf, o.file_size, 0, o.rank); + generate_memory_pattern(buf, o.file_size, o.random_buffer_offset, o.rank); double op_timer; // timer for individual operations size_t pos = -1; // position inside the individual measurement array double op_time; @@ -566,7 +568,7 @@ void run_precreate(phase_stat_t * s, int current_index){ if (NULL == aiori_fh){ FAIL("Unable to open file %s", obj_name); } - update_write_memory_pattern(f * o.dset_count + d, buf, o.file_size, 0, o.rank); + update_write_memory_pattern(f * o.dset_count + d, buf, o.file_size, o.random_buffer_offset, o.rank); if ( o.file_size == (int) o.backend->xfer(WRITE, aiori_fh, (IOR_size_t *) buf, o.file_size, 0, o.backend_options)) { s->obj_create.suc++; }else{ @@ -647,7 +649,7 @@ void run_benchmark(phase_stat_t * s, int * current_index_p){ } if ( o.file_size == (int) o.backend->xfer(READ, aiori_fh, (IOR_size_t *) buf, o.file_size, 0, o.backend_options) ) { if(o.verify_read){ - if(verify_memory_pattern(f * o.dset_count + d, buf, o.file_size, 0, readRank) == 0){ + if(verify_memory_pattern(f * o.dset_count + d, buf, o.file_size, o.random_buffer_offset, readRank) == 0){ s->obj_read.suc++; }else{ s->obj_read.err++; @@ -801,6 +803,7 @@ static option_help options [] = { {0, "latency-all", "Keep the latency files from all ranks.", OPTION_FLAG, 'd', & o.latency_keep_all}, {'P', "precreate-per-set", "Number of object to precreate per data set.", OPTION_OPTIONAL_ARGUMENT, 'd', & o.precreate}, {'D', "data-sets", "Number of data sets covered per process and iteration.", OPTION_OPTIONAL_ARGUMENT, 'd', & o.dset_count}, + {'G', NULL, "Offset for the data in the read/write buffer, if not set, a random value is used", OPTION_OPTIONAL_ARGUMENT, 'd', & o.random_buffer_offset}, {'o', NULL, "Output directory", OPTION_OPTIONAL_ARGUMENT, 's', & o.prefix}, {'q', "quiet", "Avoid irrelevant printing.", OPTION_FLAG, 'd', & o.quiet_output}, //{'m', "lim-free-mem", "Allocate memory until this limit (in MiB) is reached.", OPTION_OPTIONAL_ARGUMENT, 'd', & o.limit_memory}, @@ -906,6 +909,10 @@ mdworkbench_results_t* md_workbench_run(int argc, char ** argv, MPI_Comm world_c ERR("Invalid options, if running only the benchmark phase using -2 with stonewall option then use stonewall wear-out"); exit(1); } + if( o.random_buffer_offset == -1 ){ + o.random_buffer_offset = time(NULL); + MPI_Bcast(& o.random_buffer_offset, 1, MPI_INT, 0, o.com); + } if(o.backend->xfer_hints){ o.backend->xfer_hints(& o.hints);