From 20bb99e1b76aacb43ac4f59e255e7c9fc3291c9d Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Sat, 19 Jan 2019 17:00:49 +0000 Subject: [PATCH 01/27] Potential fix for #127 => Segmentation fault due to memory protection. --- src/mdtest.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mdtest.c b/src/mdtest.c index afc4fc6..f1eb08d 100644 --- a/src/mdtest.c +++ b/src/mdtest.c @@ -215,6 +215,8 @@ void parse_dirpath(char *dirpath_arg) { FAIL("out of memory"); } + // prevent changes to the original dirpath_arg + dirpath_arg = strdup(dirpath_arg); token = strtok(dirpath_arg, delimiter_string); while (token != NULL) { filenames[i] = token; From 4c1c73ecae16cb7ae03d3cbd0a3567502ad03b84 Mon Sep 17 00:00:00 2001 From: "Glenn K. Lockwood" Date: Wed, 23 Jan 2019 16:02:58 -0800 Subject: [PATCH 02/27] add malloc check to fix --- src/mdtest.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mdtest.c b/src/mdtest.c index f1eb08d..6ae6838 100644 --- a/src/mdtest.c +++ b/src/mdtest.c @@ -210,13 +210,13 @@ void parse_dirpath(char *dirpath_arg) { } tmp++; } + // prevent changes to the original dirpath_arg + dirpath_arg = strdup(dirpath_arg); filenames = (char **)malloc(path_count * sizeof(char **)); - if (filenames == NULL) { + if (filenames == NULL || dirpath_arg == NULL) { FAIL("out of memory"); } - // prevent changes to the original dirpath_arg - dirpath_arg = strdup(dirpath_arg); token = strtok(dirpath_arg, delimiter_string); while (token != NULL) { filenames[i] = token; From c6abf85378ede3c3fd61363fc7166909b7d2251f Mon Sep 17 00:00:00 2001 From: Jean-Yves VET Date: Mon, 11 Feb 2019 14:42:30 +0100 Subject: [PATCH 03/27] aiori-IME: Add support of statfs in IME backend This patch adds the support of statfs in the IME backend. It uses ime_native_statvfs call to fill the ior_aiori_statfs_t structure. --- src/aiori-IME.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/aiori-IME.c b/src/aiori-IME.c index 107b321..95c48f2 100755 --- a/src/aiori-IME.c +++ b/src/aiori-IME.c @@ -269,20 +269,35 @@ static char *IME_GetVersion() return ver; } -/* - * XXX: statfs call is currently not exposed by IME native interface. - */ static int IME_StatFS(const char *path, ior_aiori_statfs_t *stat_buf, IOR_param_t *param) { + (void)param; + +#if (IME_NATIVE_API_VERSION >= 130) + struct statvfs statfs_buf; + + int ret = ime_native_statvfs(path, &statfs_buf); + if (ret) + return ret; + + stat_buf->f_bsize = statfs_buf.f_bsize; + stat_buf->f_blocks = statfs_buf.f_blocks; + stat_buf->f_bfree = statfs_buf.f_bfree; + stat_buf->f_files = statfs_buf.f_files; + stat_buf->f_ffree = statfs_buf.f_ffree; + + return 0; +#else (void)path; (void)stat_buf; - (void)param; WARN("statfs is currently not supported in IME backend!"); return -1; +#endif } + static int IME_MkDir(const char *path, mode_t mode, IOR_param_t *param) { (void)param; From 110153cf3ab88b034c8b1d7b05121d38b4616a0a Mon Sep 17 00:00:00 2001 From: Jean-Yves VET Date: Mon, 11 Feb 2019 14:49:14 +0100 Subject: [PATCH 04/27] mdtest: Enable IME native interface This patch makes mdtest allow IME native interface. It also defines a generic way to enable mdtest with each backend. --- src/aiori-DUMMY.c | 37 +++++++++++++++++++------------------ src/aiori-IME.c | 1 + src/aiori-POSIX.c | 1 + src/aiori.c | 37 ++++++++++++++++++++++++++----------- src/aiori.h | 9 ++++++++- src/mdtest.c | 10 +++------- src/parse_options.c | 2 +- 7 files changed, 59 insertions(+), 38 deletions(-) diff --git a/src/aiori-DUMMY.c b/src/aiori-DUMMY.c index a378c2c..675a91b 100755 --- a/src/aiori-DUMMY.c +++ b/src/aiori-DUMMY.c @@ -138,22 +138,23 @@ static int DUMMY_stat (const char *path, struct stat *buf, IOR_param_t * param){ } ior_aiori_t dummy_aiori = { - "DUMMY", - NULL, - DUMMY_Create, - DUMMY_Open, - DUMMY_Xfer, - DUMMY_Close, - DUMMY_Delete, - DUMMY_getVersion, - DUMMY_Fsync, - DUMMY_GetFileSize, - DUMMY_statfs, - DUMMY_mkdir, - DUMMY_rmdir, - DUMMY_access, - DUMMY_stat, - NULL, - NULL, - DUMMY_options + .name = "DUMMY", + .name_legacy = NULL, + .create = DUMMY_Create, + .open = DUMMY_Open, + .xfer = DUMMY_Xfer, + .close = DUMMY_Close, + .delete = DUMMY_Delete, + .get_version = DUMMY_getVersion, + .fsync = DUMMY_Fsync, + .get_file_size = DUMMY_GetFileSize, + .statfs = DUMMY_statfs, + .mkdir = DUMMY_mkdir, + .rmdir = DUMMY_rmdir, + .access = DUMMY_access, + .stat = DUMMY_stat, + .initialize = NULL, + .finalize = NULL, + .get_options = DUMMY_options, + .enable_mdtest = true, }; diff --git a/src/aiori-IME.c b/src/aiori-IME.c index 95c48f2..ef7b3cf 100755 --- a/src/aiori-IME.c +++ b/src/aiori-IME.c @@ -79,6 +79,7 @@ ior_aiori_t ime_aiori = { .stat = IME_Stat, .initialize = IME_Initialize, .finalize = IME_Finalize, + .enable_mdtest = true, }; /***************************** F U N C T I O N S ******************************/ diff --git a/src/aiori-POSIX.c b/src/aiori-POSIX.c index 94d0a7e..ca7c4a2 100755 --- a/src/aiori-POSIX.c +++ b/src/aiori-POSIX.c @@ -90,6 +90,7 @@ ior_aiori_t posix_aiori = { .rmdir = aiori_posix_rmdir, .access = aiori_posix_access, .stat = aiori_posix_stat, + .enable_mdtest = true, }; /***************************** F U N C T I O N S ******************************/ diff --git a/src/aiori.c b/src/aiori.c index f483435..11f11b4 100644 --- a/src/aiori.c +++ b/src/aiori.c @@ -92,17 +92,32 @@ void airoi_parse_options(int argc, char ** argv, option_help * global_options){ free(opt.modules); } -void aiori_supported_apis(char * APIs, char * APIs_legacy){ - ior_aiori_t **tmp = available_aiori; - if(*tmp != NULL){ - APIs += sprintf(APIs, "%s", (*tmp)->name); - tmp++; - for (; *tmp != NULL; ++tmp) { - APIs += sprintf(APIs, "|%s", (*tmp)->name); - if ((*tmp)->name_legacy != NULL) - APIs_legacy += sprintf(APIs_legacy, "|%s", (*tmp)->name_legacy); - } - } +void aiori_supported_apis(char * APIs, char * APIs_legacy, enum bench_type type) +{ + ior_aiori_t **tmp = available_aiori; + char delimiter = ' '; + + while (*tmp != NULL) + { + if ((type == MDTEST) && !(*tmp)->enable_mdtest) + { + tmp++; + continue; + } + + if (delimiter == ' ') + { + APIs += sprintf(APIs, "%s", (*tmp)->name); + delimiter = '|'; + } + else + APIs += sprintf(APIs, "%c%s", delimiter, (*tmp)->name); + + if ((*tmp)->name_legacy != NULL) + APIs_legacy += sprintf(APIs_legacy, "%c%s", + delimiter, (*tmp)->name_legacy); + tmp++; + } } /** diff --git a/src/aiori.h b/src/aiori.h index 7fb013d..727af58 100755 --- a/src/aiori.h +++ b/src/aiori.h @@ -22,6 +22,7 @@ #endif /* not MPI_FILE_NULL */ #include +#include #include "ior.h" #include "iordef.h" /* IOR Definitions */ @@ -83,8 +84,14 @@ typedef struct ior_aiori { void (*initialize)(); /* called once per program before MPI is started */ void (*finalize)(); /* called once per program after MPI is shutdown */ option_help * (*get_options)(); + bool enable_mdtest; } ior_aiori_t; +enum bench_type { + IOR, + MDTEST +}; + extern ior_aiori_t dummy_aiori; extern ior_aiori_t hdf5_aiori; extern ior_aiori_t hdfs_aiori; @@ -102,7 +109,7 @@ void aiori_initialize(IOR_test_t * tests); void aiori_finalize(IOR_test_t * tests); const ior_aiori_t *aiori_select (const char *api); int aiori_count (void); -void aiori_supported_apis(char * APIs, char * APIs_legacy); +void aiori_supported_apis(char * APIs, char * APIs_legacy, enum bench_type type); void airoi_parse_options(int argc, char ** argv, option_help * global_options); const char *aiori_default (void); diff --git a/src/mdtest.c b/src/mdtest.c index 6ae6838..8a81979 100644 --- a/src/mdtest.c +++ b/src/mdtest.c @@ -150,7 +150,7 @@ static mdtest_results_t * summary_table; static pid_t pid; static uid_t uid; -/* just use the POSIX backend for now */ +/* Use the POSIX backend by default */ static const char *backend_name = "POSIX"; static const ior_aiori_t *backend; @@ -1323,7 +1323,7 @@ void print_help (void) { char APIs[1024]; char APIs_legacy[1024]; - aiori_supported_apis(APIs, APIs_legacy); + aiori_supported_apis(APIs, APIs_legacy, MDTEST); char apiStr[1024]; sprintf(apiStr, "API for I/O [%s]", APIs); @@ -1573,10 +1573,6 @@ void valid_tests() { FAIL("-c not compatible with -B"); } - if (strcasecmp(backend_name, "POSIX") != 0 && strcasecmp(backend_name, "DUMMY") != 0) { - FAIL("-a only supported interface is POSIX (and DUMMY) right now!"); - } - /* check for shared file incompatibilities */ if (unique_dir_per_task && shared_file && rank == 0) { FAIL("-u not compatible with -S"); @@ -2131,7 +2127,7 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * int randomize = 0; char APIs[1024]; char APIs_legacy[1024]; - aiori_supported_apis(APIs, APIs_legacy); + aiori_supported_apis(APIs, APIs_legacy, MDTEST); char apiStr[1024]; sprintf(apiStr, "API for I/O [%s]", APIs); diff --git a/src/parse_options.c b/src/parse_options.c index b265953..5a093b8 100755 --- a/src/parse_options.c +++ b/src/parse_options.c @@ -467,7 +467,7 @@ IOR_test_t *ParseCommandLine(int argc, char **argv) char APIs[1024]; char APIs_legacy[1024]; - aiori_supported_apis(APIs, APIs_legacy); + aiori_supported_apis(APIs, APIs_legacy, IOR); char apiStr[1024]; sprintf(apiStr, "API for I/O [%s]", APIs); From fabb1f4d3bca62dff5dcb930f7cf66bba03f96fb Mon Sep 17 00:00:00 2001 From: Sylvain Didelot Date: Thu, 14 Mar 2019 18:37:00 +0100 Subject: [PATCH 05/27] Fix segfault with option memoryPerNode optarg contains a NULL address, which causes a segfault in NodeMemoryStringToBytes(). --- src/parse_options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parse_options.c b/src/parse_options.c index a8f81b0..45be0ba 100755 --- a/src/parse_options.c +++ b/src/parse_options.c @@ -537,7 +537,7 @@ IOR_test_t *ParseCommandLine(int argc, char **argv) } } if (memoryPerNode){ - initialTestParams.memoryPerNode = NodeMemoryStringToBytes(optarg); + initialTestParams.memoryPerNode = NodeMemoryStringToBytes(memoryPerNode); } const ior_aiori_t * backend = aiori_select(initialTestParams.api); From 20e960d0205acb4d8bda8ea50bc4f9f65b16494a Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Wed, 27 Mar 2019 20:04:48 +0000 Subject: [PATCH 06/27] Support the setting of module-specific options per test. --- src/aiori-DUMMY.c | 52 ++++---- src/aiori-POSIX.c | 36 +++++- src/aiori.c | 47 ++++--- src/aiori.h | 7 +- src/ior-output.c | 1 - src/ior.c | 21 +--- src/ior.h | 12 +- src/mdtest.c | 16 +-- src/option.c | 247 ++++++++++++++++++++----------------- src/option.h | 8 +- src/parse_options.c | 293 +++++++++++++++++++------------------------- src/utilities.c | 77 ++++++++++++ src/utilities.h | 3 + 13 files changed, 463 insertions(+), 357 deletions(-) diff --git a/src/aiori-DUMMY.c b/src/aiori-DUMMY.c index 675a91b..0494cb4 100755 --- a/src/aiori-DUMMY.c +++ b/src/aiori-DUMMY.c @@ -17,29 +17,33 @@ /************************** O P T I O N S *****************************/ -struct dummy_options{ +typedef struct { uint64_t delay_creates; uint64_t delay_xfer; int delay_rank_0_only; -}; - -static struct dummy_options o = { - .delay_creates = 0, - .delay_xfer = 0, - .delay_rank_0_only = 0, -}; - -static option_help options [] = { - {0, "dummy.delay-create", "Delay per create in usec", OPTION_OPTIONAL_ARGUMENT, 'l', & o.delay_creates}, - {0, "dummy.delay-xfer", "Delay per xfer in usec", OPTION_OPTIONAL_ARGUMENT, 'l', & o.delay_xfer}, - {0, "dummy.delay-only-rank0", "Delay only Rank0", OPTION_FLAG, 'd', & o.delay_rank_0_only}, - LAST_OPTION -}; +} dummy_options_t; static char * current = (char*) 1; -static option_help * DUMMY_options(){ - return options; +static option_help * DUMMY_options(void ** init_backend_options, void * init_values){ + dummy_options_t * o = malloc(sizeof(dummy_options_t)); + if (init_values != NULL){ + memcpy(o, init_values, sizeof(dummy_options_t)); + }else{ + memset(o, 0, sizeof(dummy_options_t)); + } + + *init_backend_options = o; + + option_help h [] = { + {0, "dummy.delay-create", "Delay per create in usec", OPTION_OPTIONAL_ARGUMENT, 'l', & o->delay_creates}, + {0, "dummy.delay-xfer", "Delay per xfer in usec", OPTION_OPTIONAL_ARGUMENT, 'l', & o->delay_xfer}, + {0, "dummy.delay-only-rank0", "Delay only Rank0", OPTION_FLAG, 'd', & o->delay_rank_0_only}, + LAST_OPTION + }; + option_help * help = malloc(sizeof(h)); + memcpy(help, h, sizeof(h)); + return help; } static void *DUMMY_Create(char *testFileName, IOR_param_t * param) @@ -47,9 +51,10 @@ static void *DUMMY_Create(char *testFileName, IOR_param_t * param) if(verbose > 4){ fprintf(out_logfile, "DUMMY create: %s = %p\n", testFileName, current); } - if (o.delay_creates){ - if (! o.delay_rank_0_only || (o.delay_rank_0_only && rank == 0)){ - struct timespec wait = { o.delay_creates / 1000 / 1000, 1000l * (o.delay_creates % 1000000)}; + dummy_options_t * o = (dummy_options_t*) param->backend_options; + if (o->delay_creates){ + if (! o->delay_rank_0_only || (o->delay_rank_0_only && rank == 0)){ + struct timespec wait = { o->delay_creates / 1000 / 1000, 1000l * (o->delay_creates % 1000000)}; nanosleep( & wait, NULL); } } @@ -102,9 +107,10 @@ static IOR_offset_t DUMMY_Xfer(int access, void *file, IOR_size_t * buffer, IOR_ if(verbose > 4){ fprintf(out_logfile, "DUMMY xfer: %p\n", file); } - if (o.delay_xfer){ - if (! o.delay_rank_0_only || (o.delay_rank_0_only && rank == 0)){ - struct timespec wait = {o.delay_xfer / 1000 / 1000, 1000l * (o.delay_xfer % 1000000)}; + dummy_options_t * o = (dummy_options_t*) param->backend_options; + if (o->delay_xfer){ + if (! o->delay_rank_0_only || (o->delay_rank_0_only && rank == 0)){ + struct timespec wait = {o->delay_xfer / 1000 / 1000, 1000l * (o->delay_xfer % 1000000)}; nanosleep( & wait, NULL); } } diff --git a/src/aiori-POSIX.c b/src/aiori-POSIX.c index ca7c4a2..1d41c64 100755 --- a/src/aiori-POSIX.c +++ b/src/aiori-POSIX.c @@ -72,8 +72,36 @@ static IOR_offset_t POSIX_Xfer(int, void *, IOR_size_t *, IOR_offset_t, IOR_param_t *); static void POSIX_Fsync(void *, IOR_param_t *); +/************************** O P T I O N S *****************************/ +typedef struct{ + int direct_io; +} posix_options_t; + + +static option_help * posix_options(void ** init_backend_options, void * init_values){ + posix_options_t * o = malloc(sizeof(posix_options_t)); + + if (init_values != NULL){ + memcpy(o, init_values, sizeof(posix_options_t)); + }else{ + o->direct_io = 0; + } + + *init_backend_options = o; + + option_help h [] = { + {0, "posix.odirect", "Direct I/O Mode", OPTION_FLAG, 'd', & o->direct_io}, + LAST_OPTION + }; + option_help * help = malloc(sizeof(h)); + memcpy(help, h, sizeof(h)); + return help; +} + + /************************** D E C L A R A T I O N S ***************************/ + ior_aiori_t posix_aiori = { .name = "POSIX", .name_legacy = NULL, @@ -90,6 +118,7 @@ ior_aiori_t posix_aiori = { .rmdir = aiori_posix_rmdir, .access = aiori_posix_access, .stat = aiori_posix_stat, + .get_options = posix_options, .enable_mdtest = true, }; @@ -274,8 +303,8 @@ void *POSIX_Create(char *testFileName, IOR_param_t * param) fd = (int *)malloc(sizeof(int)); if (fd == NULL) ERR("Unable to malloc file descriptor"); - - if (param->useO_DIRECT == TRUE) + posix_options_t * o = (posix_options_t*) param->backend_options; + if (o->direct_io == TRUE) set_o_direct_flag(&fd_oflag); if(param->dryRun) @@ -389,7 +418,8 @@ void *POSIX_Open(char *testFileName, IOR_param_t * param) if (fd == NULL) ERR("Unable to malloc file descriptor"); - if (param->useO_DIRECT == TRUE) + posix_options_t * o = (posix_options_t*) param->backend_options; + if (o->direct_io == TRUE) set_o_direct_flag(&fd_oflag); fd_oflag |= O_RDWR; diff --git a/src/aiori.c b/src/aiori.c index 11f11b4..52001c8 100644 --- a/src/aiori.c +++ b/src/aiori.c @@ -72,24 +72,37 @@ ior_aiori_t *available_aiori[] = { NULL }; -void airoi_parse_options(int argc, char ** argv, option_help * global_options){ - int airoi_c = aiori_count(); - options_all opt; - opt.module_count = airoi_c + 1; - opt.modules = malloc(sizeof(option_module) * (airoi_c + 1)); - opt.modules[0].prefix = NULL; - opt.modules[0].options = global_options; - ior_aiori_t **tmp = available_aiori; - for (int i=1; *tmp != NULL; ++tmp, i++) { - opt.modules[i].prefix = (*tmp)->name; - if((*tmp)->get_options != NULL){ - opt.modules[i].options = (*tmp)->get_options(); - }else{ - opt.modules[i].options = NULL; - } +void * airoi_update_module_options(const ior_aiori_t * backend, options_all_t * opt){ + if (backend->get_options == NULL) + return NULL; + char * name = backend->name; + ior_aiori_t **tmp = available_aiori; + for (int i=1; *tmp != NULL; ++tmp, i++) { + if (strcmp(opt->modules[i].prefix, name) == 0){ + opt->modules[i].options = (*tmp)->get_options(& opt->modules[i].defaults, opt->modules[i].defaults); + return opt->modules[i].defaults; } - option_parse(argc, argv, &opt); - free(opt.modules); + } + return NULL; +} + +options_all_t * airoi_create_all_module_options(option_help * global_options){ + int airoi_c = aiori_count(); + options_all_t * opt = malloc(sizeof(options_all_t)); + opt->module_count = airoi_c + 1; + opt->modules = malloc(sizeof(option_module) * (airoi_c + 1)); + opt->modules[0].prefix = NULL; + opt->modules[0].options = global_options; + ior_aiori_t **tmp = available_aiori; + for (int i=1; *tmp != NULL; ++tmp, i++) { + opt->modules[i].prefix = (*tmp)->name; + if((*tmp)->get_options != NULL){ + opt->modules[i].options = (*tmp)->get_options(& opt->modules[i].defaults, NULL); + }else{ + opt->modules[i].options = NULL; + } + } + return opt; } void aiori_supported_apis(char * APIs, char * APIs_legacy, enum bench_type type) diff --git a/src/aiori.h b/src/aiori.h index 727af58..782d1ac 100755 --- a/src/aiori.h +++ b/src/aiori.h @@ -83,7 +83,7 @@ typedef struct ior_aiori { int (*stat) (const char *path, struct stat *buf, IOR_param_t * param); void (*initialize)(); /* called once per program before MPI is started */ void (*finalize)(); /* called once per program after MPI is shutdown */ - option_help * (*get_options)(); + option_help * (*get_options)(void ** init_backend_options, void* init_values); /* initializes the backend options as well and returns the pointer to the option help structure */ bool enable_mdtest; } ior_aiori_t; @@ -110,7 +110,10 @@ void aiori_finalize(IOR_test_t * tests); const ior_aiori_t *aiori_select (const char *api); int aiori_count (void); void aiori_supported_apis(char * APIs, char * APIs_legacy, enum bench_type type); -void airoi_parse_options(int argc, char ** argv, option_help * global_options); +options_all_t * airoi_create_all_module_options(option_help * global_options); + +void * airoi_update_module_options(const ior_aiori_t * backend, options_all_t * module_defaults); + const char *aiori_default (void); /* some generic POSIX-based backend calls */ diff --git a/src/ior-output.c b/src/ior-output.c index 32a6054..40764ff 100644 --- a/src/ior-output.c +++ b/src/ior-output.c @@ -367,7 +367,6 @@ void ShowTestStart(IOR_param_t *test) PrintKeyValInt("setAlignment", test->setAlignment); PrintKeyValInt("storeFileOffset", test->storeFileOffset); PrintKeyValInt("useSharedFilePointer", test->useSharedFilePointer); - PrintKeyValInt("useO_DIRECT", test->useO_DIRECT); PrintKeyValInt("useStridedDatatype", test->useStridedDatatype); PrintKeyValInt("keepFile", test->keepFile); PrintKeyValInt("keepFileWithError", test->keepFileWithError); diff --git a/src/ior.c b/src/ior.c index 12b9390..a1dc321 100755 --- a/src/ior.c +++ b/src/ior.c @@ -493,20 +493,13 @@ static void aligned_buffer_free(void *buf) free(*(void **)((char *)buf - sizeof(char *))); } -static void* safeMalloc(uint64_t size){ - void * d = malloc(size); - if (d == NULL){ - ERR("Could not malloc an array"); - } - memset(d, 0, size); - return d; -} - void AllocResults(IOR_test_t *test) { int reps; if (test->results != NULL) - return; + return; + + IOR_param_t * params = & test->params; reps = test->params.repetitions; test->results = (IOR_results_t *) safeMalloc(sizeof(IOR_results_t) * reps); @@ -1235,13 +1228,7 @@ static void TestIoSys(IOR_test_t *test) fflush(out_logfile); } params->tasksPerNode = CountTasksPerNode(testComm); - - /* bind I/O calls to specific API */ - backend = aiori_select(params->api); - if (backend == NULL) - ERR_SIMPLE("unrecognized I/O API"); - - + backend = params->backend; /* show test setup */ if (rank == 0 && verbose >= VERBOSE_0) ShowSetup(params); diff --git a/src/ior.h b/src/ior.h index ad543ff..acf3a7d 100755 --- a/src/ior.h +++ b/src/ior.h @@ -36,6 +36,8 @@ typedef void *rados_ioctx_t; #endif +#include "option.h" + #include "iordef.h" /******************** DATA Packet Type ***************************************/ /* Holds the types of data packets: generic, offset, timestamp, incompressible */ @@ -93,6 +95,7 @@ typedef struct char * testFileName_fppReadCheck;/* filename for fpp read check */ char * hintsFileName; /* full name for hints file */ char * options; /* options string */ + // intermediate options int dryRun; /* do not perform any I/Os just run evtl. inputs print dummy output */ int numTasks; /* number of tasks for test */ int nodes; /* number of nodes for test */ @@ -126,7 +129,6 @@ typedef struct int useFileView; /* use MPI_File_set_view */ int useSharedFilePointer; /* use shared file pointer */ int useStridedDatatype; /* put strided access into datatype */ - int useO_DIRECT; /* use O_DIRECT, bypassing I/O buffers */ int showHints; /* show hints */ int summary_every_test; /* flag to print summary every test, not just at end */ int uniqueDir; /* use unique directory for each fpp */ @@ -148,8 +150,12 @@ typedef struct int randomOffset; /* access is to random offsets */ size_t memoryPerTask; /* additional memory used per task */ size_t memoryPerNode; /* additional memory used per node */ - enum PACKET_TYPE dataPacketType; /* The type of data packet. */ + char * memoryPerNodeStr; /* for parsing */ + char * testscripts; /* for parsing */ + char * buffer_type; /* for parsing */ + enum PACKET_TYPE dataPacketType; /* The type of data packet. */ + void * backend_options; /* Backend-specific options */ /* POSIX variables */ int singleXferAttempt; /* do not retry transfer if incomplete */ @@ -180,7 +186,7 @@ typedef struct size_t part_number; /* multi-part upload increment (PER-RANK!) */ char* UploadId; /* key for multi-part-uploads */ int collective_md; /* use collective metatata optimization */ - + /* RADOS variables */ rados_t rados_cluster; /* RADOS cluster handle */ diff --git a/src/mdtest.c b/src/mdtest.c index 8a81979..387bd86 100644 --- a/src/mdtest.c +++ b/src/mdtest.c @@ -151,7 +151,6 @@ static pid_t pid; static uid_t uid; /* Use the POSIX backend by default */ -static const char *backend_name = "POSIX"; static const ior_aiori_t *backend; static IOR_param_t param; @@ -2099,7 +2098,6 @@ void mdtest_init_args(){ nstride = 0; } - mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * world_out) { testComm = world_com; out_logfile = world_out; @@ -2132,7 +2130,7 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * sprintf(apiStr, "API for I/O [%s]", APIs); option_help options [] = { - {'a', NULL, apiStr, OPTION_OPTIONAL_ARGUMENT, 's', & backend_name}, + {'a', NULL, apiStr, OPTION_OPTIONAL_ARGUMENT, 's', & param.api}, {'b', NULL, "branching factor of hierarchical directory structure", OPTION_OPTIONAL_ARGUMENT, 'd', & branch_factor}, {'d', NULL, "the directory in which the tests will run", OPTION_OPTIONAL_ARGUMENT, 's', & path}, {'B', NULL, "no barriers between phases", OPTION_OPTIONAL_ARGUMENT, 'd', & no_barriers}, @@ -2168,12 +2166,10 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * {'Z', NULL, "print time instead of rate", OPTION_FLAG, 'd', & print_time}, LAST_OPTION }; - airoi_parse_options(argc, argv, options); - - backend = aiori_select(backend_name); - if (NULL == backend) { - FAIL("Could not find suitable backend to use"); - } + options_all_t * global_options = airoi_create_all_module_options(options); + option_parse(argc, argv, global_options); + updateParsedOptions(& param, global_options); + backend = param.backend; MPI_Comm_rank(testComm, &rank); MPI_Comm_size(testComm, &size); @@ -2222,7 +2218,7 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * if (( rank == 0 ) && ( verbose >= 1 )) { // option_print_current(options); - fprintf (out_logfile, "api : %s\n", backend_name); + fprintf (out_logfile, "api : %s\n", param.api); fprintf( out_logfile, "barriers : %s\n", ( barriers ? "True" : "False" )); fprintf( out_logfile, "collective_creates : %s\n", ( collective_creates ? "True" : "False" )); fprintf( out_logfile, "create_only : %s\n", ( create_only ? "True" : "False" )); diff --git a/src/option.c b/src/option.c index 4e88055..08833da 100644 --- a/src/option.c +++ b/src/option.c @@ -220,7 +220,136 @@ void option_print_current(option_help * args){ print_current_option_section(args, OPTION_FLAG); } -int option_parse(int argc, char ** argv, options_all * opt_all){ +static void option_parse_token(char ** argv, int * flag_parsed_next, int * requiredArgsSeen, options_all_t * opt_all, int * error, int * print_help){ + int foundOption = 0; + char * txt = argv[0]; + char * arg = strstr(txt, "="); + int replaced_equal = 0; + int i = 0; + if(arg != NULL){ + arg[0] = 0; + arg++; + replaced_equal = 1; + } + *flag_parsed_next = 0; + + for(int m = 0; m < opt_all->module_count; m++ ){ + option_help * args = opt_all->modules[m].options; + if(args == NULL) continue; + // try to find matching option help + for(option_help * o = args; o->shortVar != 0 || o->longVar != 0 || o->help != NULL ; o++ ){ + if( o->shortVar == 0 && o->longVar == 0 ){ + // section + continue; + } + if ( (txt[0] == '-' && o->shortVar == txt[1]) || (strlen(txt) > 2 && txt[0] == '-' && txt[1] == '-' && o->longVar != NULL && strcmp(txt + 2, o->longVar) == 0)){ + foundOption = 1; + + // now process the option. + switch(o->arg){ + case (OPTION_FLAG):{ + assert(o->type == 'd'); + (*(int*) o->variable)++; + break; + } + case (OPTION_OPTIONAL_ARGUMENT): + case (OPTION_REQUIRED_ARGUMENT):{ + // check if next is an argument + if(arg == NULL){ + if(o->shortVar == txt[1] && txt[2] != 0){ + arg = & txt[2]; + }else{ + // simply take the next value as argument + i++; + arg = argv[1]; + *flag_parsed_next = 1; + } + } + + if(arg == NULL){ + const char str[] = {o->shortVar, 0}; + printf("Error, argument missing for option %s\n", (o->longVar != NULL) ? o->longVar : str); + exit(1); + } + + switch(o->type){ + case('p'):{ + // call the function in the variable + void(*fp)() = o->variable; + fp(arg); + break; + } + case('F'):{ + *(double*) o->variable = atof(arg); + break; + } + case('f'):{ + *(float*) o->variable = atof(arg); + break; + } + case('d'):{ + int64_t val = string_to_bytes(arg); + if (val > INT_MAX || val < INT_MIN){ + printf("WARNING: parsing the number %s to integer, this produced an overflow!\n", arg); + } + *(int*) o->variable = val; + break; + } + case('H'): + case('s'):{ + (*(char **) o->variable) = strdup(arg); + break; + } + case('c'):{ + (*(char *)o->variable) = arg[0]; + if(strlen(arg) > 1){ + printf("Error, ignoring remainder of string for option %c (%s).\n", o->shortVar, o->longVar); + } + break; + } + case('l'):{ + *(long long*) o->variable = string_to_bytes(arg); + break; + } + default: + printf("ERROR: Unknown option type %c\n", o->type); + } + } + } + if(replaced_equal){ + arg[-1] = '='; + } + + if(o->arg == OPTION_REQUIRED_ARGUMENT){ + (*requiredArgsSeen)++; + } + + break; + } + } + } + + + if (! foundOption){ + if(strcmp(txt, "-h") == 0 || strcmp(txt, "--help") == 0){ + *print_help = 1; + }else{ + *error = 1; + } + } +} + +int option_parse_key_value(char * key, char * value, options_all_t * opt_all){ + int flag_parsed_next; + char * argv[2] = {key, value}; + int error = 0; + int requiredArgsSeen = 0; + int print_help = 0; + option_parse_token(argv, & flag_parsed_next, & requiredArgsSeen, opt_all, & error, & print_help); + return error; +} + +int option_parse(int argc, char ** argv, options_all_t * opt_all){ int error = 0; int requiredArgsSeen = 0; int requiredArgsNeeded = 0; @@ -238,117 +367,13 @@ int option_parse(int argc, char ** argv, options_all * opt_all){ } for(i=1; i < argc; i++){ - char * txt = argv[i]; - int foundOption = 0; - char * arg = strstr(txt, "="); - int replaced_equal = 0; - if(arg != NULL){ - arg[0] = 0; - arg++; - replaced_equal = 1; + int flag_parsed_next; + option_parse_token(& argv[i], & flag_parsed_next, & requiredArgsSeen, opt_all, & error, & printhelp); + if (flag_parsed_next){ + i++; } - - for(int m = 0; m < opt_all->module_count; m++ ){ - option_help * args = opt_all->modules[m].options; - if(args == NULL) continue; - // try to find matching option help - for(option_help * o = args; o->shortVar != 0 || o->longVar != 0 || o->help != NULL ; o++ ){ - if( o->shortVar == 0 && o->longVar == 0 ){ - // section - continue; - } - if ( (txt[0] == '-' && o->shortVar == txt[1]) || (strlen(txt) > 2 && txt[0] == '-' && txt[1] == '-' && o->longVar != NULL && strcmp(txt + 2, o->longVar) == 0)){ - foundOption = 1; - - // now process the option. - switch(o->arg){ - case (OPTION_FLAG):{ - assert(o->type == 'd'); - (*(int*) o->variable)++; - break; - } - case (OPTION_OPTIONAL_ARGUMENT): - case (OPTION_REQUIRED_ARGUMENT):{ - // check if next is an argument - if(arg == NULL){ - if(o->shortVar == txt[1] && txt[2] != 0){ - arg = & txt[2]; - }else{ - // simply take the next value as argument - i++; - arg = argv[i]; - } - } - - if(arg == NULL){ - const char str[] = {o->shortVar, 0}; - printf("Error, argument missing for option %s\n", (o->longVar != NULL) ? o->longVar : str); - exit(1); - } - - switch(o->type){ - case('p'):{ - // call the function in the variable - void(*fp)() = o->variable; - fp(arg); - break; - } - case('F'):{ - *(double*) o->variable = atof(arg); - break; - } - case('f'):{ - *(float*) o->variable = atof(arg); - break; - } - case('d'):{ - int64_t val = string_to_bytes(arg); - if (val > INT_MAX || val < INT_MIN){ - printf("WARNING: parsing the number %s to integer, this produced an overflow!\n", arg); - } - *(int*) o->variable = val; - break; - } - case('H'): - case('s'):{ - (*(char **) o->variable) = strdup(arg); - break; - } - case('c'):{ - (*(char *)o->variable) = arg[0]; - if(strlen(arg) > 1){ - printf("Error, ignoring remainder of string for option %c (%s).\n", o->shortVar, o->longVar); - } - break; - } - case('l'):{ - *(long long*) o->variable = string_to_bytes(arg); - break; - } - default: - printf("ERROR: Unknown option type %c\n", o->type); - } - } - } - if(replaced_equal){ - arg[-1] = '='; - } - - if(o->arg == OPTION_REQUIRED_ARGUMENT){ - requiredArgsSeen++; - } - - break; - } - } - } - if (! foundOption){ - if(strcmp(txt, "-h") == 0 || strcmp(txt, "--help") == 0){ - printhelp = 1; - }else{ - printf("Error invalid argument: %s\n", txt); - error = 1; - } + if(error){ + printf("Error invalid argument: %s\n", argv[i]); } } diff --git a/src/option.h b/src/option.h index 53a3732..7225921 100644 --- a/src/option.h +++ b/src/option.h @@ -26,12 +26,13 @@ typedef struct{ typedef struct{ char * prefix; // may be NULL to include it in the standard name option_help * options; + void * defaults; // these default values are taken from the command line } option_module; typedef struct{ int module_count; option_module * modules; -} options_all; +} options_all_t; #define LAST_OPTION {0, 0, 0, (option_value_type) 0, 0, NULL} @@ -39,6 +40,9 @@ int64_t string_to_bytes(char *size_str); void option_print_current(option_help * args); //@return the number of parsed arguments -int option_parse(int argc, char ** argv, options_all * args); +int option_parse(int argc, char ** argv, options_all_t * args); + +/* Parse a single line */ +int option_parse_key_value(char * key, char * value, options_all_t * opt_all); #endif diff --git a/src/parse_options.c b/src/parse_options.c index ea6dd63..f92e239 100755 --- a/src/parse_options.c +++ b/src/parse_options.c @@ -36,38 +36,11 @@ IOR_param_t initialTestParams; +option_help * createGlobalOptions(IOR_param_t * params); -static size_t NodeMemoryStringToBytes(char *size_str) -{ - int percent; - int rc; - long page_size; - long num_pages; - long long mem; - rc = sscanf(size_str, " %d %% ", &percent); - if (rc == 0) - return (size_t) string_to_bytes(size_str); - if (percent > 100 || percent < 0) - ERR("percentage must be between 0 and 100"); - -#ifdef HAVE_SYSCONF - page_size = sysconf(_SC_PAGESIZE); -#else - page_size = getpagesize(); -#endif - -#ifdef _SC_PHYS_PAGES - num_pages = sysconf(_SC_PHYS_PAGES); - if (num_pages == -1) - ERR("sysconf(_SC_PHYS_PAGES) is not supported"); -#else - ERR("sysconf(_SC_PHYS_PAGES) is not supported"); -#endif - mem = page_size * num_pages; - - return mem / 100 * percent; -} +static IOR_param_t * parameters; +static options_all_t * global_options; /* @@ -113,7 +86,7 @@ static void CheckRunSettings(IOR_test_t *tests) /* * Set flags from commandline string/value pairs. */ -void DecodeDirective(char *line, IOR_param_t *params) +void DecodeDirective(char *line, IOR_param_t *params, options_all_t * module_options) { char option[MAX_STR]; char value[MAX_STR]; @@ -132,6 +105,14 @@ void DecodeDirective(char *line, IOR_param_t *params) } if (strcasecmp(option, "api") == 0) { params->api = strdup(value); + + params->backend = aiori_select(params->api); + if (params->backend == NULL){ + fprintf(out_logfile, "Could not load backend API %s\n", params->api); + exit(-1); + } + /* copy the actual module options into the test */ + params->backend_options = airoi_update_module_options(params->backend, global_options); } else if (strcasecmp(option, "summaryFile") == 0) { if (rank == 0){ out_resultfile = fopen(value, "w"); @@ -240,8 +221,6 @@ void DecodeDirective(char *line, IOR_param_t *params) params->useFileView = atoi(value); } else if (strcasecmp(option, "usesharedfilepointer") == 0) { params->useSharedFilePointer = atoi(value); - } else if (strcasecmp(option, "useo_direct") == 0) { - params->useO_DIRECT = atoi(value); } else if (strcasecmp(option, "usestrideddatatype") == 0) { params->useStridedDatatype = atoi(value); } else if (strcasecmp(option, "showhints") == 0) { @@ -314,21 +293,28 @@ void DecodeDirective(char *line, IOR_param_t *params) } else if (strcasecmp(option, "summaryalways") == 0) { params->summary_every_test = atoi(value); } else { - if (rank == 0) - fprintf(out_logfile, "Unrecognized parameter \"%s\"\n", - option); - MPI_CHECK(MPI_Initialized(&initialized), "MPI_Initialized() error"); - if (initialized) - MPI_CHECK(MPI_Abort(MPI_COMM_WORLD, -1), "MPI_Abort() error"); - else - exit(-1); + int parsing_error = option_parse_key_value(option, value, module_options); + if(parsing_error){ + if (rank == 0) + fprintf(out_logfile, "Unrecognized parameter \"%s\"\n", + option); + MPI_CHECK(MPI_Initialized(&initialized), "MPI_Initialized() error"); + if (initialized) + MPI_CHECK(MPI_Abort(MPI_COMM_WORLD, -1), "MPI_Abort() error"); + else + exit(-1); + } } } +static void decodeDirectiveWrapper(char *line){ + DecodeDirective(line, parameters, global_options); +} + /* * Parse a single line, which may contain multiple comma-seperated directives */ -void ParseLine(char *line, IOR_param_t * test) +void ParseLine(char *line, IOR_param_t * test, options_all_t * module_options) { char *start, *end; @@ -337,7 +323,7 @@ void ParseLine(char *line, IOR_param_t * test) end = strchr(start, ','); if (end != NULL) *end = '\0'; - DecodeDirective(start, test); + DecodeDirective(start, test, module_options); start = end + 1; } while (end != NULL); } @@ -383,9 +369,12 @@ IOR_test_t *ReadConfigScript(char *scriptName) IOR_test_t *head = NULL; IOR_test_t *tail = NULL; + option_help ** option_p = & global_options->modules[0].options; + /* Initialize the first test */ - head = CreateTest(&initialTestParams, test_num++); + head = CreateTest(& initialTestParams, test_num++); tail = head; + *option_p = createGlobalOptions(& ((IOR_test_t*) head)->params); /* The current options */ /* open the script */ file = fopen(scriptName, "r"); @@ -423,6 +412,7 @@ IOR_test_t *ReadConfigScript(char *scriptName) tail->next = CreateTest(&tail->params, test_num++); AllocResults(tail); tail = tail->next; + *option_p = createGlobalOptions(& ((IOR_test_t*) tail->next)->params); } runflag = 1; } else if (runflag) { @@ -430,11 +420,12 @@ IOR_test_t *ReadConfigScript(char *scriptName) create and initialize a new test structure */ runflag = 0; tail->next = CreateTest(&tail->params, test_num++); + *option_p = createGlobalOptions(& ((IOR_test_t*) tail->next)->params); AllocResults(tail); tail = tail->next; - ParseLine(ptr, &tail->params); + ParseLine(ptr, &tail->params, global_options); } else { - ParseLine(ptr, &tail->params); + ParseLine(ptr, &tail->params, global_options); } } @@ -447,139 +438,105 @@ IOR_test_t *ReadConfigScript(char *scriptName) } -static IOR_param_t * parameters; +option_help * createGlobalOptions(IOR_param_t * params){ + char APIs[1024]; + char APIs_legacy[1024]; + aiori_supported_apis(APIs, APIs_legacy, IOR); + char apiStr[1024]; + sprintf(apiStr, "API for I/O [%s]", APIs); -static void decodeDirectiveWrapper(char *line){ - DecodeDirective(line, parameters); + option_help o [] = { + {'a', NULL, apiStr, OPTION_OPTIONAL_ARGUMENT, 's', & params->api}, + {'A', NULL, "refNum -- user supplied reference number to include in the summary", OPTION_OPTIONAL_ARGUMENT, 'd', & params->referenceNumber}, + {'b', NULL, "blockSize -- contiguous bytes to write per task (e.g.: 8, 4k, 2m, 1g)", OPTION_OPTIONAL_ARGUMENT, 'l', & params->blockSize}, + {'c', NULL, "collective -- collective I/O", OPTION_FLAG, 'd', & params->collective}, + {'C', NULL, "reorderTasks -- changes task ordering to n+1 ordering for readback", OPTION_FLAG, 'd', & params->reorderTasks}, + {'d', NULL, "interTestDelay -- delay between reps in seconds", OPTION_OPTIONAL_ARGUMENT, 'd', & params->interTestDelay}, + {'D', NULL, "deadlineForStonewalling -- seconds before stopping write or read phase", OPTION_OPTIONAL_ARGUMENT, 'd', & params->deadlineForStonewalling}, + {.help=" -O stoneWallingWearOut=1 -- once the stonewalling timout is over, all process finish to access the amount of data", .arg = OPTION_OPTIONAL_ARGUMENT}, + {.help=" -O stoneWallingWearOutIterations=N -- stop after processing this number of iterations, needed for reading data back written with stoneWallingWearOut", .arg = OPTION_OPTIONAL_ARGUMENT}, + {.help=" -O stoneWallingStatusFile=FILE -- this file keeps the number of iterations from stonewalling during write and allows to use them for read", .arg = OPTION_OPTIONAL_ARGUMENT}, + {'e', NULL, "fsync -- perform sync operation after each block write", OPTION_FLAG, 'd', & params->fsync}, + {'E', NULL, "useExistingTestFile -- do not remove test file before write access", OPTION_FLAG, 'd', & params->useExistingTestFile}, + {'f', NULL, "scriptFile -- test script name", OPTION_OPTIONAL_ARGUMENT, 's', & params->testscripts}, + {'F', NULL, "filePerProc -- file-per-process", OPTION_FLAG, 'd', & params->filePerProc}, + {'g', NULL, "intraTestBarriers -- use barriers between open, write/read, and close", OPTION_FLAG, 'd', & params->intraTestBarriers}, + /* This option toggles between Incompressible Seed and Time stamp sig based on -l, + * so we'll toss the value in both for now, and sort it out in initialization + * after all the arguments are in and we know which it keep. + */ + {'G', NULL, "setTimeStampSignature -- set value for time stamp signature/random seed", OPTION_OPTIONAL_ARGUMENT, 'd', & params->setTimeStampSignature}, + {'H', NULL, "showHints -- show hints", OPTION_FLAG, 'd', & params->showHints}, + {'i', NULL, "repetitions -- number of repetitions of test", OPTION_OPTIONAL_ARGUMENT, 'd', & params->repetitions}, + {'I', NULL, "individualDataSets -- datasets not shared by all procs [not working]", OPTION_FLAG, 'd', & params->individualDataSets}, + {'j', NULL, "outlierThreshold -- warn on outlier N seconds from mean", OPTION_OPTIONAL_ARGUMENT, 'd', & params->outlierThreshold}, + {'J', NULL, "setAlignment -- HDF5 alignment in bytes (e.g.: 8, 4k, 2m, 1g)", OPTION_OPTIONAL_ARGUMENT, 'd', & params->setAlignment}, + {'k', NULL, "keepFile -- don't remove the test file(s) on program exit", OPTION_FLAG, 'd', & params->keepFile}, + {'K', NULL, "keepFileWithError -- keep error-filled file(s) after data-checking", OPTION_FLAG, 'd', & params->keepFileWithError}, + {'l', NULL, "datapacket type-- type of packet that will be created [offset|incompressible|timestamp|o|i|t]", OPTION_OPTIONAL_ARGUMENT, 's', & params->buffer_type}, + {'m', NULL, "multiFile -- use number of reps (-i) for multiple file count", OPTION_FLAG, 'd', & params->multiFile}, + {'M', NULL, "memoryPerNode -- hog memory on the node (e.g.: 2g, 75%)", OPTION_OPTIONAL_ARGUMENT, 's', & params->memoryPerNodeStr}, + {'n', NULL, "noFill -- no fill in HDF5 file creation", OPTION_FLAG, 'd', & params->noFill}, + {'N', NULL, "numTasks -- number of tasks that should participate in the test", OPTION_OPTIONAL_ARGUMENT, 'd', & params->numTasks}, + {'o', NULL, "testFile -- full name for test", OPTION_OPTIONAL_ARGUMENT, 's', & params->testFileName}, + {'O', NULL, "string of IOR directives (e.g. -O checkRead=1,lustreStripeCount=32)", OPTION_OPTIONAL_ARGUMENT, 'p', & decodeDirectiveWrapper}, + {'p', NULL, "preallocate -- preallocate file size", OPTION_FLAG, 'd', & params->preallocate}, + {'P', NULL, "useSharedFilePointer -- use shared file pointer [not working]", OPTION_FLAG, 'd', & params->useSharedFilePointer}, + {'q', NULL, "quitOnError -- during file error-checking, abort on error", OPTION_FLAG, 'd', & params->quitOnError}, + {'Q', NULL, "taskPerNodeOffset for read tests use with -C & -Z options (-C constant N, -Z at least N)", OPTION_OPTIONAL_ARGUMENT, 'd', & params->taskPerNodeOffset}, + {'r', NULL, "readFile -- read existing file", OPTION_FLAG, 'd', & params->readFile}, + {'R', NULL, "checkRead -- verify that the output of read matches the expected signature (used with -G)", OPTION_FLAG, 'd', & params->checkRead}, + {'s', NULL, "segmentCount -- number of segments", OPTION_OPTIONAL_ARGUMENT, 'd', & params->segmentCount}, + {'S', NULL, "useStridedDatatype -- put strided access into datatype [not working]", OPTION_FLAG, 'd', & params->useStridedDatatype}, + {'t', NULL, "transferSize -- size of transfer in bytes (e.g.: 8, 4k, 2m, 1g)", OPTION_OPTIONAL_ARGUMENT, 'l', & params->transferSize}, + {'T', NULL, "maxTimeDuration -- max time in minutes executing repeated test; it aborts only between iterations and not within a test!", OPTION_OPTIONAL_ARGUMENT, 'd', & params->maxTimeDuration}, + {'u', NULL, "uniqueDir -- use unique directory name for each file-per-process", OPTION_FLAG, 'd', & params->uniqueDir}, + {'U', NULL, "hintsFileName -- full name for hints file", OPTION_OPTIONAL_ARGUMENT, 's', & params->hintsFileName}, + {'v', NULL, "verbose -- output information (repeating flag increases level)", OPTION_FLAG, 'd', & params->verbose}, + {'V', NULL, "useFileView -- use MPI_File_set_view", OPTION_FLAG, 'd', & params->useFileView}, + {'w', NULL, "writeFile -- write file", OPTION_FLAG, 'd', & params->writeFile}, + {'W', NULL, "checkWrite -- check read after write", OPTION_FLAG, 'd', & params->checkWrite}, + {'x', NULL, "singleXferAttempt -- do not retry transfer if incomplete", OPTION_FLAG, 'd', & params->singleXferAttempt}, + {'X', NULL, "reorderTasksRandomSeed -- random seed for -Z option", OPTION_OPTIONAL_ARGUMENT, 'd', & params->reorderTasksRandomSeed}, + {'Y', NULL, "fsyncPerWrite -- perform sync operation after every write operation", OPTION_FLAG, 'd', & params->fsyncPerWrite}, + {'z', NULL, "randomOffset -- access is to random, not sequential, offsets within a file", OPTION_FLAG, 'd', & params->randomOffset}, + {'Z', NULL, "reorderTasksRandom -- changes task ordering to random ordering for readback", OPTION_FLAG, 'd', & params->reorderTasksRandom}, + {.help=" -O summaryFile=FILE -- store result data into this file", .arg = OPTION_OPTIONAL_ARGUMENT}, + {.help=" -O summaryFormat=[default,JSON,CSV] -- use the format for outputing the summary", .arg = OPTION_OPTIONAL_ARGUMENT}, + {0, "dryRun", "do not perform any I/Os just run evtl. inputs print dummy output", OPTION_FLAG, 'd', & params->dryRun}, + LAST_OPTION, + }; + option_help * options = malloc(sizeof(o)); + memcpy(options, & o, sizeof(o)); + return options; } + /* * Parse Commandline. */ IOR_test_t *ParseCommandLine(int argc, char **argv) { - char * testscripts = NULL; - int toggleG = FALSE; - char * buffer_type = ""; - char * memoryPerNode = NULL; init_IOR_Param_t(& initialTestParams); + + IOR_test_t *tests = NULL; + + GetPlatformName(initialTestParams.platform); + + option_help * options = createGlobalOptions( & initialTestParams); parameters = & initialTestParams; + global_options = airoi_create_all_module_options(options); + option_parse(argc, argv, global_options); + updateParsedOptions(& initialTestParams, global_options); - char APIs[1024]; - char APIs_legacy[1024]; - aiori_supported_apis(APIs, APIs_legacy, IOR); - char apiStr[1024]; - sprintf(apiStr, "API for I/O [%s]", APIs); + if (initialTestParams.testscripts){ + tests = ReadConfigScript(initialTestParams.testscripts); + }else{ + tests = CreateTest(&initialTestParams, 0); + AllocResults(tests); + } - option_help options [] = { - {'a', NULL, apiStr, OPTION_OPTIONAL_ARGUMENT, 's', & initialTestParams.api}, - {'A', NULL, "refNum -- user supplied reference number to include in the summary", OPTION_OPTIONAL_ARGUMENT, 'd', & initialTestParams.referenceNumber}, - {'b', NULL, "blockSize -- contiguous bytes to write per task (e.g.: 8, 4k, 2m, 1g)", OPTION_OPTIONAL_ARGUMENT, 'l', & initialTestParams.blockSize}, - {'B', NULL, "useO_DIRECT -- uses O_DIRECT for POSIX, bypassing I/O buffers", OPTION_FLAG, 'd', & initialTestParams.useO_DIRECT}, - {'c', NULL, "collective -- collective I/O", OPTION_FLAG, 'd', & initialTestParams.collective}, - {'C', NULL, "reorderTasks -- changes task ordering to n+1 ordering for readback", OPTION_FLAG, 'd', & initialTestParams.reorderTasks}, - {'d', NULL, "interTestDelay -- delay between reps in seconds", OPTION_OPTIONAL_ARGUMENT, 'd', & initialTestParams.interTestDelay}, - {'D', NULL, "deadlineForStonewalling -- seconds before stopping write or read phase", OPTION_OPTIONAL_ARGUMENT, 'd', & initialTestParams.deadlineForStonewalling}, - {.help=" -O stoneWallingWearOut=1 -- once the stonewalling timout is over, all process finish to access the amount of data", .arg = OPTION_OPTIONAL_ARGUMENT}, - {.help=" -O stoneWallingWearOutIterations=N -- stop after processing this number of iterations, needed for reading data back written with stoneWallingWearOut", .arg = OPTION_OPTIONAL_ARGUMENT}, - {.help=" -O stoneWallingStatusFile=FILE -- this file keeps the number of iterations from stonewalling during write and allows to use them for read", .arg = OPTION_OPTIONAL_ARGUMENT}, - {'e', NULL, "fsync -- perform sync operation after each block write", OPTION_FLAG, 'd', & initialTestParams.fsync}, - {'E', NULL, "useExistingTestFile -- do not remove test file before write access", OPTION_FLAG, 'd', & initialTestParams.useExistingTestFile}, - {'f', NULL, "scriptFile -- test script name", OPTION_OPTIONAL_ARGUMENT, 's', & testscripts}, - {'F', NULL, "filePerProc -- file-per-process", OPTION_FLAG, 'd', & initialTestParams.filePerProc}, - {'g', NULL, "intraTestBarriers -- use barriers between open, write/read, and close", OPTION_FLAG, 'd', & initialTestParams.intraTestBarriers}, - /* This option toggles between Incompressible Seed and Time stamp sig based on -l, - * so we'll toss the value in both for now, and sort it out in initialization - * after all the arguments are in and we know which it keep. - */ - {'G', NULL, "setTimeStampSignature -- set value for time stamp signature/random seed", OPTION_OPTIONAL_ARGUMENT, 'd', & toggleG}, - {'H', NULL, "showHints -- show hints", OPTION_FLAG, 'd', & initialTestParams.showHints}, - {'i', NULL, "repetitions -- number of repetitions of test", OPTION_OPTIONAL_ARGUMENT, 'd', & initialTestParams.repetitions}, - {'I', NULL, "individualDataSets -- datasets not shared by all procs [not working]", OPTION_FLAG, 'd', & initialTestParams.individualDataSets}, - {'j', NULL, "outlierThreshold -- warn on outlier N seconds from mean", OPTION_OPTIONAL_ARGUMENT, 'd', & initialTestParams.outlierThreshold}, - {'J', NULL, "setAlignment -- HDF5 alignment in bytes (e.g.: 8, 4k, 2m, 1g)", OPTION_OPTIONAL_ARGUMENT, 'd', & initialTestParams.setAlignment}, - {'k', NULL, "keepFile -- don't remove the test file(s) on program exit", OPTION_FLAG, 'd', & initialTestParams.keepFile}, - {'K', NULL, "keepFileWithError -- keep error-filled file(s) after data-checking", OPTION_FLAG, 'd', & initialTestParams.keepFileWithError}, - {'l', NULL, "datapacket type-- type of packet that will be created [offset|incompressible|timestamp|o|i|t]", OPTION_OPTIONAL_ARGUMENT, 's', & buffer_type}, - {'m', NULL, "multiFile -- use number of reps (-i) for multiple file count", OPTION_FLAG, 'd', & initialTestParams.multiFile}, - {'M', NULL, "memoryPerNode -- hog memory on the node (e.g.: 2g, 75%)", OPTION_OPTIONAL_ARGUMENT, 's', & memoryPerNode}, - {'n', NULL, "noFill -- no fill in HDF5 file creation", OPTION_FLAG, 'd', & initialTestParams.noFill}, - {'N', NULL, "numTasks -- number of tasks that should participate in the test", OPTION_OPTIONAL_ARGUMENT, 'd', & initialTestParams.numTasks}, - {'o', NULL, "testFile -- full name for test", OPTION_OPTIONAL_ARGUMENT, 's', & initialTestParams.testFileName}, - {'O', NULL, "string of IOR directives (e.g. -O checkRead=1,lustreStripeCount=32)", OPTION_OPTIONAL_ARGUMENT, 'p', & decodeDirectiveWrapper}, - {'p', NULL, "preallocate -- preallocate file size", OPTION_FLAG, 'd', & initialTestParams.preallocate}, - {'P', NULL, "useSharedFilePointer -- use shared file pointer [not working]", OPTION_FLAG, 'd', & initialTestParams.useSharedFilePointer}, - {'q', NULL, "quitOnError -- during file error-checking, abort on error", OPTION_FLAG, 'd', & initialTestParams.quitOnError}, - {'Q', NULL, "taskPerNodeOffset for read tests use with -C & -Z options (-C constant N, -Z at least N)", OPTION_OPTIONAL_ARGUMENT, 'd', & initialTestParams.taskPerNodeOffset}, - {'r', NULL, "readFile -- read existing file", OPTION_FLAG, 'd', & initialTestParams.readFile}, - {'R', NULL, "checkRead -- verify that the output of read matches the expected signature (used with -G)", OPTION_FLAG, 'd', & initialTestParams.checkRead}, - {'s', NULL, "segmentCount -- number of segments", OPTION_OPTIONAL_ARGUMENT, 'd', & initialTestParams.segmentCount}, - {'S', NULL, "useStridedDatatype -- put strided access into datatype [not working]", OPTION_FLAG, 'd', & initialTestParams.useStridedDatatype}, - {'t', NULL, "transferSize -- size of transfer in bytes (e.g.: 8, 4k, 2m, 1g)", OPTION_OPTIONAL_ARGUMENT, 'l', & initialTestParams.transferSize}, - {'T', NULL, "maxTimeDuration -- max time in minutes executing repeated test; it aborts only between iterations and not within a test!", OPTION_OPTIONAL_ARGUMENT, 'd', & initialTestParams.maxTimeDuration}, - {'u', NULL, "uniqueDir -- use unique directory name for each file-per-process", OPTION_FLAG, 'd', & initialTestParams.uniqueDir}, - {'U', NULL, "hintsFileName -- full name for hints file", OPTION_OPTIONAL_ARGUMENT, 's', & initialTestParams.hintsFileName}, - {'v', NULL, "verbose -- output information (repeating flag increases level)", OPTION_FLAG, 'd', & initialTestParams.verbose}, - {'V', NULL, "useFileView -- use MPI_File_set_view", OPTION_FLAG, 'd', & initialTestParams.useFileView}, - {'w', NULL, "writeFile -- write file", OPTION_FLAG, 'd', & initialTestParams.writeFile}, - {'W', NULL, "checkWrite -- check read after write", OPTION_FLAG, 'd', & initialTestParams.checkWrite}, - {'x', NULL, "singleXferAttempt -- do not retry transfer if incomplete", OPTION_FLAG, 'd', & initialTestParams.singleXferAttempt}, - {'X', NULL, "reorderTasksRandomSeed -- random seed for -Z option", OPTION_OPTIONAL_ARGUMENT, 'd', & initialTestParams.reorderTasksRandomSeed}, - {'Y', NULL, "fsyncPerWrite -- perform sync operation after every write operation", OPTION_FLAG, 'd', & initialTestParams.fsyncPerWrite}, - {'z', NULL, "randomOffset -- access is to random, not sequential, offsets within a file", OPTION_FLAG, 'd', & initialTestParams.randomOffset}, - {'Z', NULL, "reorderTasksRandom -- changes task ordering to random ordering for readback", OPTION_FLAG, 'd', & initialTestParams.reorderTasksRandom}, - {.help=" -O summaryFile=FILE -- store result data into this file", .arg = OPTION_OPTIONAL_ARGUMENT}, - {.help=" -O summaryFormat=[default,JSON,CSV] -- use the format for outputing the summary", .arg = OPTION_OPTIONAL_ARGUMENT}, - {0, "dryRun", "do not perform any I/Os just run evtl. inputs print dummy output", OPTION_FLAG, 'd', & initialTestParams.dryRun}, - LAST_OPTION, - }; + CheckRunSettings(tests); - IOR_test_t *tests = NULL; - - GetPlatformName(initialTestParams.platform); - airoi_parse_options(argc, argv, options); - - if (toggleG){ - initialTestParams.setTimeStampSignature = toggleG; - initialTestParams.incompressibleSeed = toggleG; - } - - if (buffer_type[0] != 0){ - switch(buffer_type[0]) { - case 'i': /* Incompressible */ - initialTestParams.dataPacketType = incompressible; - break; - case 't': /* timestamp */ - initialTestParams.dataPacketType = timestamp; - break; - case 'o': /* offset packet */ - initialTestParams.storeFileOffset = TRUE; - initialTestParams.dataPacketType = offset; - break; - default: - fprintf(out_logfile, - "Unknown arguement for -l %s; generic assumed\n", buffer_type); - break; - } - } - if (memoryPerNode){ - initialTestParams.memoryPerNode = NodeMemoryStringToBytes(memoryPerNode); - } - const ior_aiori_t * backend = aiori_select(initialTestParams.api); - if (backend == NULL) - ERR_SIMPLE("unrecognized I/O API"); - - initialTestParams.backend = backend; - initialTestParams.apiVersion = backend->get_version(); - - if (testscripts){ - tests = ReadConfigScript(testscripts); - }else{ - tests = CreateTest(&initialTestParams, 0); - AllocResults(tests); - } - - CheckRunSettings(tests); - - return (tests); + return (tests); } diff --git a/src/utilities.c b/src/utilities.c index b71ce41..cc0918c 100755 --- a/src/utilities.c +++ b/src/utilities.c @@ -66,6 +66,83 @@ enum OutputFormat_t outputFormat; /***************************** F U N C T I O N S ******************************/ +void* safeMalloc(uint64_t size){ + void * d = malloc(size); + if (d == NULL){ + ERR("Could not malloc an array"); + } + memset(d, 0, size); + return d; +} + + +size_t NodeMemoryStringToBytes(char *size_str) +{ + int percent; + int rc; + long page_size; + long num_pages; + long long mem; + + rc = sscanf(size_str, " %d %% ", &percent); + if (rc == 0) + return (size_t) string_to_bytes(size_str); + if (percent > 100 || percent < 0) + ERR("percentage must be between 0 and 100"); + +#ifdef HAVE_SYSCONF + page_size = sysconf(_SC_PAGESIZE); +#else + page_size = getpagesize(); +#endif + +#ifdef _SC_PHYS_PAGES + num_pages = sysconf(_SC_PHYS_PAGES); + if (num_pages == -1) + ERR("sysconf(_SC_PHYS_PAGES) is not supported"); +#else + ERR("sysconf(_SC_PHYS_PAGES) is not supported"); +#endif + mem = page_size * num_pages; + + return mem / 100 * percent; +} + +void updateParsedOptions(IOR_param_t * options, options_all_t * global_options){ + if (options->setTimeStampSignature){ + options->incompressibleSeed = options->setTimeStampSignature; + } + + if (options->buffer_type && options->buffer_type[0] != 0){ + switch(options->buffer_type[0]) { + case 'i': /* Incompressible */ + options->dataPacketType = incompressible; + break; + case 't': /* timestamp */ + options->dataPacketType = timestamp; + break; + case 'o': /* offset packet */ + options->storeFileOffset = TRUE; + options->dataPacketType = offset; + break; + default: + fprintf(out_logfile, + "Unknown argument for -l %s; generic assumed\n", options->buffer_type); + break; + } + } + if (options->memoryPerNodeStr){ + options->memoryPerNode = NodeMemoryStringToBytes(options->memoryPerNodeStr); + } + const ior_aiori_t * backend = aiori_select(options->api); + if (backend == NULL) + ERR_SIMPLE("unrecognized I/O API"); + + options->backend = backend; + /* copy the actual module options into the test */ + options->backend_options = airoi_update_module_options(backend, global_options); + options->apiVersion = backend->get_version(); +} /* Used in aiori-POSIX.c and aiori-PLFS.c */ diff --git a/src/utilities.h b/src/utilities.h index 7933cbc..b646174 100755 --- a/src/utilities.h +++ b/src/utilities.h @@ -53,6 +53,7 @@ extern enum OutputFormat_t outputFormat; /* format of the output */ } while(0) #endif +void* safeMalloc(uint64_t size); void set_o_direct_flag(int *fd); char *CurrentTimeString(void); @@ -65,6 +66,8 @@ void ShowHints (MPI_Info *); char *HumanReadable(IOR_offset_t value, int base); int CountTasksPerNode(MPI_Comm comm); void DelaySecs(int delay); +void updateParsedOptions(IOR_param_t * options, options_all_t * global_options); +size_t NodeMemoryStringToBytes(char *size_str); /* Returns -1, if cannot be read */ int64_t ReadStoneWallingIterations(char * const filename); From 07ca5247d7255d50fa2ec9730e56cf3e4df81799 Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Wed, 27 Mar 2019 20:37:46 +0000 Subject: [PATCH 07/27] Checked proper IOR behavior for -f option. --- src/aiori-POSIX.c | 5 +++-- src/option.c | 16 +++++----------- src/parse_options.c | 9 ++++++--- testing/test_comments.ior | 2 ++ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/aiori-POSIX.c b/src/aiori-POSIX.c index 1d41c64..a446459 100755 --- a/src/aiori-POSIX.c +++ b/src/aiori-POSIX.c @@ -304,8 +304,9 @@ void *POSIX_Create(char *testFileName, IOR_param_t * param) if (fd == NULL) ERR("Unable to malloc file descriptor"); posix_options_t * o = (posix_options_t*) param->backend_options; - if (o->direct_io == TRUE) - set_o_direct_flag(&fd_oflag); + if (o->direct_io == TRUE){ + set_o_direct_flag(&fd_oflag); + } if(param->dryRun) return 0; diff --git a/src/option.c b/src/option.c index 08833da..f940cee 100644 --- a/src/option.c +++ b/src/option.c @@ -221,7 +221,6 @@ void option_print_current(option_help * args){ } static void option_parse_token(char ** argv, int * flag_parsed_next, int * requiredArgsSeen, options_all_t * opt_all, int * error, int * print_help){ - int foundOption = 0; char * txt = argv[0]; char * arg = strstr(txt, "="); int replaced_equal = 0; @@ -243,8 +242,6 @@ static void option_parse_token(char ** argv, int * flag_parsed_next, int * requi continue; } if ( (txt[0] == '-' && o->shortVar == txt[1]) || (strlen(txt) > 2 && txt[0] == '-' && txt[1] == '-' && o->longVar != NULL && strcmp(txt + 2, o->longVar) == 0)){ - foundOption = 1; - // now process the option. switch(o->arg){ case (OPTION_FLAG):{ @@ -324,18 +321,15 @@ static void option_parse_token(char ** argv, int * flag_parsed_next, int * requi (*requiredArgsSeen)++; } - break; + return; } } } - - if (! foundOption){ - if(strcmp(txt, "-h") == 0 || strcmp(txt, "--help") == 0){ - *print_help = 1; - }else{ - *error = 1; - } + if(strcmp(txt, "-h") == 0 || strcmp(txt, "--help") == 0){ + *print_help = 1; + }else{ + *error = 1; } } diff --git a/src/parse_options.c b/src/parse_options.c index f92e239..dd6e68b 100755 --- a/src/parse_options.c +++ b/src/parse_options.c @@ -111,8 +111,6 @@ void DecodeDirective(char *line, IOR_param_t *params, options_all_t * module_opt fprintf(out_logfile, "Could not load backend API %s\n", params->api); exit(-1); } - /* copy the actual module options into the test */ - params->backend_options = airoi_update_module_options(params->backend, global_options); } else if (strcasecmp(option, "summaryFile") == 0) { if (rank == 0){ out_resultfile = fopen(value, "w"); @@ -411,6 +409,8 @@ IOR_test_t *ReadConfigScript(char *scriptName) create duplicate test */ tail->next = CreateTest(&tail->params, test_num++); AllocResults(tail); + ((IOR_test_t*) tail)->params.backend_options = airoi_update_module_options(((IOR_test_t*) tail)->params.backend, global_options); + tail = tail->next; *option_p = createGlobalOptions(& ((IOR_test_t*) tail->next)->params); } @@ -422,6 +422,8 @@ IOR_test_t *ReadConfigScript(char *scriptName) tail->next = CreateTest(&tail->params, test_num++); *option_p = createGlobalOptions(& ((IOR_test_t*) tail->next)->params); AllocResults(tail); + ((IOR_test_t*) tail)->params.backend_options = airoi_update_module_options(((IOR_test_t*) tail)->params.backend, global_options); + tail = tail->next; ParseLine(ptr, &tail->params, global_options); } else { @@ -432,7 +434,8 @@ IOR_test_t *ReadConfigScript(char *scriptName) /* close the script */ if (fclose(file) != 0) ERR("fclose() of script file failed"); - AllocResults(tail); + AllocResults(tail); /* copy the actual module options into the test */ + ((IOR_test_t*) tail)->params.backend_options = airoi_update_module_options(((IOR_test_t*) tail)->params.backend, global_options); return head; } diff --git a/testing/test_comments.ior b/testing/test_comments.ior index b48b36f..bd2efa8 100644 --- a/testing/test_comments.ior +++ b/testing/test_comments.ior @@ -14,4 +14,6 @@ transferSize=100k blockSize=100k # space-prefixed comment run +--dummy.delay-create=1000 +api=dummy ior stop From b4fb80a69e33af50ee6306e2df7d8a48f581c4af Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Wed, 27 Mar 2019 22:32:38 +0000 Subject: [PATCH 08/27] Allowed option parser to reset flags (needed in scriptfiles). --- src/option.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/option.c b/src/option.c index f940cee..d5b76c3 100644 --- a/src/option.c +++ b/src/option.c @@ -246,7 +246,12 @@ static void option_parse_token(char ** argv, int * flag_parsed_next, int * requi switch(o->arg){ case (OPTION_FLAG):{ assert(o->type == 'd'); - (*(int*) o->variable)++; + if(arg != NULL){ + int val = atoi(arg); + (*(int*) o->variable) = (val < 0) ? 0 : val; + }else{ + (*(int*) o->variable)++; + } break; } case (OPTION_OPTIONAL_ARGUMENT): From 21405ed92434b9687235e6a01083b434a101a4af Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Wed, 27 Mar 2019 22:32:59 +0000 Subject: [PATCH 09/27] Updated MMap module to option parser. --- src/aiori-MMAP.c | 65 +++++++++++++++++++++++++++++++++++++---------- src/aiori-POSIX.c | 5 ++-- src/aiori.h | 2 ++ src/ior.c | 2 -- src/ior.h | 2 -- 5 files changed, 57 insertions(+), 19 deletions(-) diff --git a/src/aiori-MMAP.c b/src/aiori-MMAP.c index f812bdd..dd6c649 100644 --- a/src/aiori-MMAP.c +++ b/src/aiori-MMAP.c @@ -32,6 +32,7 @@ static IOR_offset_t MMAP_Xfer(int, void *, IOR_size_t *, IOR_offset_t, IOR_param_t *); static void MMAP_Close(void *, IOR_param_t *); static void MMAP_Fsync(void *, IOR_param_t *); +static option_help * MMAP_options(void ** init_backend_options, void * init_values); /************************** D E C L A R A T I O N S ***************************/ @@ -45,9 +46,38 @@ ior_aiori_t mmap_aiori = { .get_version = aiori_get_version, .fsync = MMAP_Fsync, .get_file_size = POSIX_GetFileSize, + .get_options = MMAP_options, }; /***************************** F U N C T I O N S ******************************/ +typedef struct{ + int direct_io_ignored; /* this option is ignored */ + void* mmap_ptr; /* for internal usage */ + + int madv_dont_need; + int madv_pattern; +} mmap_options_t; + +static option_help * MMAP_options(void ** init_backend_options, void * init_values){ + mmap_options_t * o = malloc(sizeof(mmap_options_t)); + + if (init_values != NULL){ + memcpy(o, init_values, sizeof(mmap_options_t)); + }else{ + o->direct_io_ignored = 0; + } + + *init_backend_options = o; + + option_help h [] = { + {0, "mmap.madv_dont_need", "Use advise don't need", OPTION_FLAG, 'd', & o->madv_dont_need}, + {0, "mmap.madv_pattern", "Use advise to indicate the pattern random/sequential", OPTION_FLAG, 'd', & o->madv_pattern}, + LAST_OPTION + }; + option_help * help = malloc(sizeof(h)); + memcpy(help, h, sizeof(h)); + return help; +} static void ior_mmap_file(int *file, IOR_param_t *param) { @@ -56,21 +86,27 @@ static void ior_mmap_file(int *file, IOR_param_t *param) if (param->open == WRITE) flags |= PROT_WRITE; + mmap_options_t *o = (mmap_options_t*) param->backend_options; - param->mmap_ptr = mmap(NULL, size, flags, MAP_SHARED, + o->mmap_ptr = mmap(NULL, size, flags, MAP_SHARED, *file, 0); - if (param->mmap_ptr == MAP_FAILED) + if (o->mmap_ptr == MAP_FAILED) ERR("mmap() failed"); if (param->randomOffset) flags = POSIX_MADV_RANDOM; else flags = POSIX_MADV_SEQUENTIAL; - if (posix_madvise(param->mmap_ptr, size, flags) != 0) - ERR("madvise() failed"); + + if(o->madv_pattern){ + if (posix_madvise(o->mmap_ptr, size, flags) != 0) + ERR("madvise() failed"); + } - if (posix_madvise(param->mmap_ptr, size, POSIX_MADV_DONTNEED) != 0) - ERR("madvise() failed"); + if (o->madv_dont_need){ + if (posix_madvise(o->mmap_ptr, size, POSIX_MADV_DONTNEED) != 0) + ERR("madvise() failed"); + } return; } @@ -107,16 +143,17 @@ static void *MMAP_Open(char *testFileName, IOR_param_t * param) static IOR_offset_t MMAP_Xfer(int access, void *file, IOR_size_t * buffer, IOR_offset_t length, IOR_param_t * param) { + mmap_options_t *o = (mmap_options_t*) param->backend_options; if (access == WRITE) { - memcpy(param->mmap_ptr + param->offset, buffer, length); + memcpy(o->mmap_ptr + param->offset, buffer, length); } else { - memcpy(buffer, param->mmap_ptr + param->offset, length); + memcpy(buffer, o->mmap_ptr + param->offset, length); } if (param->fsyncPerWrite == TRUE) { - if (msync(param->mmap_ptr + param->offset, length, MS_SYNC) != 0) + if (msync(o->mmap_ptr + param->offset, length, MS_SYNC) != 0) ERR("msync() failed"); - if (posix_madvise(param->mmap_ptr + param->offset, length, + if (posix_madvise(o->mmap_ptr + param->offset, length, POSIX_MADV_DONTNEED) != 0) ERR("madvise() failed"); } @@ -128,7 +165,8 @@ static IOR_offset_t MMAP_Xfer(int access, void *file, IOR_size_t * buffer, */ static void MMAP_Fsync(void *fd, IOR_param_t * param) { - if (msync(param->mmap_ptr, param->expectedAggFileSize, MS_SYNC) != 0) + mmap_options_t *o = (mmap_options_t*) param->backend_options; + if (msync(o->mmap_ptr, param->expectedAggFileSize, MS_SYNC) != 0) EWARN("msync() failed"); } @@ -137,8 +175,9 @@ static void MMAP_Fsync(void *fd, IOR_param_t * param) */ static void MMAP_Close(void *fd, IOR_param_t * param) { - if (munmap(param->mmap_ptr, param->expectedAggFileSize) != 0) + mmap_options_t *o = (mmap_options_t*) param->backend_options; + if (munmap(o->mmap_ptr, param->expectedAggFileSize) != 0) ERR("munmap failed"); - param->mmap_ptr = NULL; + o->mmap_ptr = NULL; POSIX_Close(fd, param); } diff --git a/src/aiori-POSIX.c b/src/aiori-POSIX.c index a446459..9e85fa7 100755 --- a/src/aiori-POSIX.c +++ b/src/aiori-POSIX.c @@ -74,11 +74,12 @@ static void POSIX_Fsync(void *, IOR_param_t *); /************************** O P T I O N S *****************************/ typedef struct{ + /* in case of a change, please update depending MMAP module too */ int direct_io; } posix_options_t; -static option_help * posix_options(void ** init_backend_options, void * init_values){ +option_help * POSIX_options(void ** init_backend_options, void * init_values){ posix_options_t * o = malloc(sizeof(posix_options_t)); if (init_values != NULL){ @@ -118,7 +119,7 @@ ior_aiori_t posix_aiori = { .rmdir = aiori_posix_rmdir, .access = aiori_posix_access, .stat = aiori_posix_stat, - .get_options = posix_options, + .get_options = POSIX_options, .enable_mdtest = true, }; diff --git a/src/aiori.h b/src/aiori.h index 782d1ac..d8cabb5 100755 --- a/src/aiori.h +++ b/src/aiori.h @@ -129,6 +129,8 @@ void *POSIX_Open(char *testFileName, IOR_param_t * param); IOR_offset_t POSIX_GetFileSize(IOR_param_t * test, MPI_Comm testComm, char *testFileName); void POSIX_Delete(char *testFileName, IOR_param_t * param); void POSIX_Close(void *fd, IOR_param_t * param); +option_help * POSIX_options(void ** init_backend_options, void * init_values); + /* NOTE: these 3 MPI-IO functions are exported for reuse by HDF5/PNetCDF */ void MPIIO_Delete(char *testFileName, IOR_param_t * param); diff --git a/src/ior.c b/src/ior.c index a1dc321..3ef411c 100755 --- a/src/ior.c +++ b/src/ior.c @@ -218,8 +218,6 @@ void init_IOR_Param_t(IOR_param_t * p) p->beegfs_numTargets = -1; p->beegfs_chunkSize = -1; - - p->mmap_ptr = NULL; } static void diff --git a/src/ior.h b/src/ior.h index acf3a7d..da4e5c1 100755 --- a/src/ior.h +++ b/src/ior.h @@ -162,8 +162,6 @@ typedef struct int fsyncPerWrite; /* fsync() after each write */ int fsync; /* fsync() after write */ - void* mmap_ptr; - /* MPI variables */ MPI_Comm testComm; /* MPI communicator */ MPI_Datatype transferType; /* datatype for transfer */ From 07217c93aabc42d0a81d03af00b1ae7e39c3d2ed Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Tue, 2 Apr 2019 12:08:31 +0100 Subject: [PATCH 10/27] Bugfix for the parsing of flags. Backwards compatibility for direct IO. --- src/aiori-POSIX.c | 1 + src/option.c | 7 +++++-- src/parse_options.c | 6 +++++- testing/test_comments.ior | 2 ++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/aiori-POSIX.c b/src/aiori-POSIX.c index 9e85fa7..6f865b3 100755 --- a/src/aiori-POSIX.c +++ b/src/aiori-POSIX.c @@ -306,6 +306,7 @@ void *POSIX_Create(char *testFileName, IOR_param_t * param) ERR("Unable to malloc file descriptor"); posix_options_t * o = (posix_options_t*) param->backend_options; if (o->direct_io == TRUE){ + printf("ODIREC\n"); set_o_direct_flag(&fd_oflag); } diff --git a/src/option.c b/src/option.c index d5b76c3..99f696c 100644 --- a/src/option.c +++ b/src/option.c @@ -223,6 +223,7 @@ void option_print_current(option_help * args){ static void option_parse_token(char ** argv, int * flag_parsed_next, int * requiredArgsSeen, options_all_t * opt_all, int * error, int * print_help){ char * txt = argv[0]; char * arg = strstr(txt, "="); + int replaced_equal = 0; int i = 0; if(arg != NULL){ @@ -338,12 +339,14 @@ static void option_parse_token(char ** argv, int * flag_parsed_next, int * requi } } -int option_parse_key_value(char * key, char * value, options_all_t * opt_all){ +int option_parse_key_value(char * key, char *val, options_all_t * opt_all){ int flag_parsed_next; - char * argv[2] = {key, value}; int error = 0; int requiredArgsSeen = 0; int print_help = 0; + char value[1024]; + sprintf(value, "%s=%s", key, val); + char * argv[2] = {value, NULL}; option_parse_token(argv, & flag_parsed_next, & requiredArgsSeen, opt_all, & error, & print_help); return error; } diff --git a/src/parse_options.c b/src/parse_options.c index dd6e68b..71af8e5 100755 --- a/src/parse_options.c +++ b/src/parse_options.c @@ -291,6 +291,10 @@ void DecodeDirective(char *line, IOR_param_t *params, options_all_t * module_opt } else if (strcasecmp(option, "summaryalways") == 0) { params->summary_every_test = atoi(value); } else { + // backward compatibility for now + if (strcasecmp(option, "useo_direct") == 0) { + strcpy(option, "--posix.odirect"); + } int parsing_error = option_parse_key_value(option, value, module_options); if(parsing_error){ if (rank == 0) @@ -410,7 +414,7 @@ IOR_test_t *ReadConfigScript(char *scriptName) tail->next = CreateTest(&tail->params, test_num++); AllocResults(tail); ((IOR_test_t*) tail)->params.backend_options = airoi_update_module_options(((IOR_test_t*) tail)->params.backend, global_options); - + tail = tail->next; *option_p = createGlobalOptions(& ((IOR_test_t*) tail->next)->params); } diff --git a/testing/test_comments.ior b/testing/test_comments.ior index bd2efa8..eaf7997 100644 --- a/testing/test_comments.ior +++ b/testing/test_comments.ior @@ -15,5 +15,7 @@ blockSize=100k # space-prefixed comment run --dummy.delay-create=1000 +useo_direct=0 +#--posix.odirect=0 api=dummy ior stop From 27ac1b88af7a282ea25c07581447e1887a4c31b5 Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Tue, 2 Apr 2019 12:34:35 +0100 Subject: [PATCH 11/27] Removed verbose output. --- src/aiori-POSIX.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/aiori-POSIX.c b/src/aiori-POSIX.c index 6f865b3..9e85fa7 100755 --- a/src/aiori-POSIX.c +++ b/src/aiori-POSIX.c @@ -306,7 +306,6 @@ void *POSIX_Create(char *testFileName, IOR_param_t * param) ERR("Unable to malloc file descriptor"); posix_options_t * o = (posix_options_t*) param->backend_options; if (o->direct_io == TRUE){ - printf("ODIREC\n"); set_o_direct_flag(&fd_oflag); } From 8fd755147a17512f09b98a837a2f0a6997c10b6b Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Fri, 19 Apr 2019 10:20:04 +0100 Subject: [PATCH 12/27] Fix for #144 --- src/parse_options.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/parse_options.c b/src/parse_options.c index 71af8e5..8a569a5 100755 --- a/src/parse_options.c +++ b/src/parse_options.c @@ -322,9 +322,12 @@ void ParseLine(char *line, IOR_param_t * test, options_all_t * module_options) start = line; do { + end = strchr(start, '#'); + if (end != NULL) + *end = '\0'; end = strchr(start, ','); if (end != NULL) - *end = '\0'; + *end = '\0'; DecodeDirective(start, test, module_options); start = end + 1; } while (end != NULL); From e3afdb5ed55aa27d5cfffa4d2f0163d577274855 Mon Sep 17 00:00:00 2001 From: Oliver Steffen Date: Mon, 29 Apr 2019 15:49:57 +0200 Subject: [PATCH 13/27] beegfs: don't fail if output exists Use existing output file if it has the desired stripe settings (number of targets, chunk size) --- src/aiori-POSIX.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/aiori-POSIX.c b/src/aiori-POSIX.c index ca7c4a2..7c8c9ea 100755 --- a/src/aiori-POSIX.c +++ b/src/aiori-POSIX.c @@ -201,6 +201,24 @@ bool beegfs_isOptionSet(int opt) { return opt != -1; } +bool beegfs_compatibleFileExists(char* filepath, int numTargets, int chunkSize) +{ + int fd = open(filepath, O_RDWR); + + if (fd == -1) + return false; + + unsigned read_stripePattern = 0; + u_int16_t read_numTargets = 0; + int read_chunkSize = 0; + + bool retVal = beegfs_getStripeInfo(fd, &read_stripePattern, &read_chunkSize, &read_numTargets); + + close(fd); + + return retVal && read_numTargets == numTargets && read_chunkSize == chunkSize; +} + /* * Create a file on a BeeGFS file system with striping parameters */ @@ -247,8 +265,9 @@ bool beegfs_createFilePath(char* filepath, mode_t mode, int numTargets, int chun char* filenameTmp = strdup(filepath); char* filename = basename(filepath); - bool isFileCreated = beegfs_createFile(parentDirFd, filename, - mode, numTargets, chunkSize); + bool isFileCreated = beegfs_compatibleFileExists(filepath, numTargets, chunkSize) + || beegfs_createFile(parentDirFd, filename, + mode, numTargets, chunkSize); if (!isFileCreated) ERR("Could not create file"); retVal = true; From a9b0bf35bca95637244d9759f28de704c0c9b78f Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Thu, 2 May 2019 09:58:35 +0100 Subject: [PATCH 14/27] Support MDTest verbosity >=5 prints behavior for all ranks instead of just rank 0 (which is enabled with verbosity level 3 as before) --- src/mdtest.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/mdtest.c b/src/mdtest.c index 8a81979..6592e5d 100644 --- a/src/mdtest.c +++ b/src/mdtest.c @@ -273,7 +273,7 @@ static void create_remove_dirs (const char *path, bool create, uint64_t itemNum) //create dirs sprintf(curr_item, "%s/dir.%s%" PRIu64, path, create ? mk_name : rm_name, itemNum); - if (rank == 0 && verbose >= 3) { + if (verbose >= 5 || (rank == 0 && verbose >= 3)) { fprintf(out_logfile, "V-3: create_remove_items_helper (dirs %s): curr_item is \"%s\"\n", operation, curr_item); fflush(out_logfile); } @@ -302,7 +302,7 @@ static void remove_file (const char *path, uint64_t itemNum) { //remove files sprintf(curr_item, "%s/file.%s"LLU"", path, rm_name, itemNum); - if (rank == 0 && verbose >= 3) { + if (verbose >= 5 || (rank == 0 && verbose >= 3)) { fprintf(out_logfile, "V-3: create_remove_items_helper (non-dirs remove): curr_item is \"%s\"\n", curr_item); fflush(out_logfile); } @@ -333,7 +333,7 @@ static void create_file (const char *path, uint64_t itemNum) { if (collective_creates) { param.openFlags = IOR_WRONLY; - if (rank == 0 && verbose >= 3) { + if (verbose >= 5 || (rank == 0 && verbose >= 3)) { fprintf(out_logfile, "V-3: create_remove_items_helper (collective): open...\n" ); fflush( out_logfile ); } @@ -350,7 +350,7 @@ static void create_file (const char *path, uint64_t itemNum) { param.openFlags = IOR_CREAT | IOR_WRONLY; param.filePerProc = !shared_file; - if (rank == 0 && verbose >= 3) { + if (verbose >= 5 || (rank == 0 && verbose >= 3)) { fprintf(out_logfile, "V-3: create_remove_items_helper (non-collective, shared): open...\n" ); fflush( out_logfile ); } @@ -362,7 +362,7 @@ static void create_file (const char *path, uint64_t itemNum) { } if (write_bytes > 0) { - if (rank == 0 && verbose >= 3) { + if (verbose >= 5 || (rank == 0 && verbose >= 3)) { fprintf(out_logfile, "V-3: create_remove_items_helper: write...\n" ); fflush( out_logfile ); } @@ -378,7 +378,7 @@ static void create_file (const char *path, uint64_t itemNum) { } } - if (rank == 0 && verbose >= 3) { + if (verbose >= 5 || (rank == 0 && verbose >= 3)) { fprintf(out_logfile, "V-3: create_remove_items_helper: close...\n" ); fflush( out_logfile ); } @@ -430,7 +430,7 @@ void collective_helper(const int dirs, const int create, const char* path, uint6 } sprintf(curr_item, "%s/file.%s"LLU"", path, create ? mk_name : rm_name, itemNum+i); - if (rank == 0 && verbose >= 3) { + if (verbose >= 5 || (rank == 0 && verbose >= 3)) { fprintf(out_logfile, "V-3: create file: %s\n", curr_item); fflush(out_logfile); } @@ -476,7 +476,7 @@ void create_remove_items(int currDepth, const int dirs, const int create, const memset(dir, 0, MAX_PATHLEN); strcpy(temp_path, path); - if (rank == 0 && verbose >= 3) { + if (verbose >= 5 || (rank == 0 && verbose >= 3)) { fprintf(out_logfile, "V-3: create_remove_items (start): temp_path is \"%s\"\n", temp_path ); fflush(out_logfile); } @@ -505,7 +505,7 @@ void create_remove_items(int currDepth, const int dirs, const int create, const strcat(temp_path, "/"); strcat(temp_path, dir); - if (rank == 0 && verbose >= 3) { + if (verbose >= 5 || (rank == 0 && verbose >= 3)) { fprintf(out_logfile, "V-3: create_remove_items (for loop): temp_path is \"%s\"\n", temp_path ); fflush(out_logfile); } @@ -583,13 +583,13 @@ void mdtest_stat(const int random, const int dirs, const long dir_iter, const ch /* create name of file/dir to stat */ if (dirs) { - if (rank == 0 && verbose >= 3 && (i%ITEM_COUNT == 0) && (i != 0)) { + if ((verbose >= 5 || (rank == 0 && verbose >= 3)) && (i%ITEM_COUNT == 0) && (i != 0)) { fprintf(out_logfile, "V-3: stat dir: "LLU"\n", i); fflush(out_logfile); } sprintf(item, "dir.%s"LLU"", stat_name, item_num); } else { - if (rank == 0 && verbose >= 3 && (i%ITEM_COUNT == 0) && (i != 0)) { + if ((verbose >= 5 || (rank == 0 && verbose >= 3)) && (i%ITEM_COUNT == 0) && (i != 0)) { fprintf(out_logfile, "V-3: stat file: "LLU"\n", i); fflush(out_logfile); } @@ -618,7 +618,7 @@ void mdtest_stat(const int random, const int dirs, const long dir_iter, const ch strcpy( item, temp ); /* below temp used to be hiername */ - if (rank == 0 && verbose >= 3) { + if (verbose >= 5 || (rank == 0 && verbose >= 3)) { if (dirs) { fprintf(out_logfile, "V-3: mdtest_stat dir : %s\n", item); } else { @@ -700,7 +700,7 @@ void mdtest_read(int random, int dirs, const long dir_iter, char *path) { /* create name of file to read */ if (!dirs) { - if (rank == 0 && verbose >= 3 && (i%ITEM_COUNT == 0) && (i != 0)) { + if ((verbose >= 5 || (rank == 0 && verbose >= 3)) && (i%ITEM_COUNT == 0) && (i != 0)) { fprintf(out_logfile, "V-3: read file: "LLU"\n", i); fflush(out_logfile); } @@ -729,7 +729,7 @@ void mdtest_read(int random, int dirs, const long dir_iter, char *path) { strcpy( item, temp ); /* below temp used to be hiername */ - if (rank == 0 && verbose >= 3) { + if (verbose >= 5 || (rank == 0 && verbose >= 3)) { if (!dirs) { fprintf(out_logfile, "V-3: mdtest_read file: %s\n", item); } @@ -805,7 +805,7 @@ void collective_create_remove(const int create, const int dirs, const int ntasks } /* Now that everything is set up as it should be, do the create or remove */ - if (rank == 0 && verbose >= 3) { + if (verbose >= 5 || (rank == 0 && verbose >= 3)) { fprintf(out_logfile, "V-3: collective_create_remove (create_remove_items): temp is \"%s\"\n", temp); fflush( out_logfile ); } From 54522315ec92f6f2228df1af853eebab06a61a0c Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Wed, 8 May 2019 14:02:40 +0100 Subject: [PATCH 15/27] Fix #146; handling of hints. Why are GPFS hints special, remains unclear. --- src/utilities.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/utilities.c b/src/utilities.c index cc0918c..c0c7c61 100755 --- a/src/utilities.c +++ b/src/utilities.c @@ -292,21 +292,23 @@ int CountTasksPerNode(MPI_Comm comm) { */ void ExtractHint(char *settingVal, char *valueVal, char *hintString) { - char *settingPtr, *valuePtr, *tmpPtr1, *tmpPtr2; + char *settingPtr, *valuePtr, *tmpPtr2; + /* find the value */ settingPtr = (char *)strtok(hintString, " ="); valuePtr = (char *)strtok(NULL, " =\t\r\n"); - tmpPtr1 = settingPtr; - tmpPtr2 = (char *)strstr(settingPtr, "IOR_HINT__MPI__"); - if (tmpPtr1 == tmpPtr2) { + /* is this an MPI hint? */ + tmpPtr2 = (char *) strstr(settingPtr, "IOR_HINT__MPI__"); + if (settingPtr == tmpPtr2) { settingPtr += strlen("IOR_HINT__MPI__"); - } else { - tmpPtr2 = (char *)strstr(settingPtr, "IOR_HINT__GPFS__"); - if (tmpPtr1 == tmpPtr2) { - settingPtr += strlen("IOR_HINT__GPFS__"); - fprintf(out_logfile, - "WARNING: Unable to set GPFS hints (not implemented.)\n"); + tmpPtr2 = (char *) strstr(hintString, "IOR_HINT__GPFS__"); + /* is it an GPFS hint? */ + if (settingPtr == tmpPtr2) { + settingPtr += strlen("IOR_HINT__GPFS__"); + }else{ + fprintf(out_logfile, "WARNING: Unable to set unknown hint type (not implemented.)\n"); + return; } } strcpy(settingVal, settingPtr); From 30a1ca187bc0373ca3e90b87f97b7b34a49e2250 Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Tue, 14 May 2019 14:55:11 +0100 Subject: [PATCH 16/27] Bugfix by rmn1 for #147 and #112. --- src/mdtest.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mdtest.c b/src/mdtest.c index 6592e5d..263b18a 100644 --- a/src/mdtest.c +++ b/src/mdtest.c @@ -551,7 +551,7 @@ void mdtest_stat(const int random, const int dirs, const long dir_iter, const ch uint64_t stop_items = items; - if( directory_loops != 1 || leaf_only ){ + if( directory_loops != 1 ){ stop_items = items_per_dir; } @@ -2270,7 +2270,11 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * } if (items_per_dir > 0) { if(items == 0){ - items = items_per_dir * num_dirs_in_tree; + if (leaf_only) { + items = items_per_dir * (uint64_t) pow(branch_factor, depth); + } else { + items = items_per_dir * num_dirs_in_tree; + } }else{ num_dirs_in_tree_calc = num_dirs_in_tree; } From 6abdcc363a3114fcfca40ee40d0a64adde12e7b7 Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Thu, 16 May 2019 12:56:56 +0100 Subject: [PATCH 17/27] Trivial fix for #149 --- src/parse_options.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/parse_options.c b/src/parse_options.c index 8a569a5..153fef8 100755 --- a/src/parse_options.c +++ b/src/parse_options.c @@ -92,7 +92,7 @@ void DecodeDirective(char *line, IOR_param_t *params, options_all_t * module_opt char value[MAX_STR]; int rc; int initialized; - + rc = sscanf(line, " %[^=# \t\r\n] = %[^# \t\r\n] ", option, value); if (rc != 2 && rank == 0) { fprintf(out_logfile, "Syntax error in configuration options: %s\n", @@ -309,9 +309,6 @@ void DecodeDirective(char *line, IOR_param_t *params, options_all_t * module_opt } } -static void decodeDirectiveWrapper(char *line){ - DecodeDirective(line, parameters, global_options); -} /* * Parse a single line, which may contain multiple comma-seperated directives @@ -333,6 +330,11 @@ void ParseLine(char *line, IOR_param_t * test, options_all_t * module_options) } while (end != NULL); } + +static void decodeDirectiveWrapper(char *line){ + ParseLine(line, parameters, global_options); +} + /* * Determines if the string "haystack" contains only the string "needle", and * possibly whitespace before and after needle. Function is case insensitive. From 3a873ea2b0702967f99067b82c05f887ac0757b1 Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Thu, 16 May 2019 19:35:00 +0100 Subject: [PATCH 18/27] Fix #150. --- src/ior-output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ior-output.c b/src/ior-output.c index 40764ff..eaf5bab 100644 --- a/src/ior-output.c +++ b/src/ior-output.c @@ -450,7 +450,7 @@ void ShowSetup(IOR_param_t *params) if (params->lustre_set_striping) { PrintKeyVal("Lustre stripe size", ((params->lustre_stripe_size == 0) ? "Use default" : HumanReadable(params->lustre_stripe_size, BASE_TWO))); - PrintKeyVal("stripe count", (params->lustre_stripe_count == 0 ? "Use default" : HumanReadable(params->lustre_stripe_count, BASE_TWO))); + PrintKeyVal("stripe count", (params->lustre_stripe_count == 0 ? "Use default" : params->lustre_stripe_count) ); } #endif /* HAVE_LUSTRE_LUSTRE_USER_H */ if (params->deadlineForStonewalling > 0) { From c5c43c4f3cc89cf9f08c6c3d16b4f7ff58f583ea Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Thu, 16 May 2019 21:25:34 +0100 Subject: [PATCH 19/27] Changed the version name to alpha to differentiate. Now mdtest has the version number from IOR. --- META | 2 +- src/mdtest.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/META b/META index a4ea873..af848f6 100755 --- a/META +++ b/META @@ -1,3 +1,3 @@ Package: ior -Version: 3.2.0 +Version: 3.3alpha1 Release: 0 diff --git a/src/mdtest.c b/src/mdtest.c index ef5db1e..d65d6f9 100644 --- a/src/mdtest.c +++ b/src/mdtest.c @@ -77,7 +77,7 @@ #define FILEMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH #define DIRMODE S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH -#define RELEASE_VERS "1.9.3" +#define RELEASE_VERS META_VERSION #define TEST_DIR "#test-dir" #define ITEM_COUNT 25000 From eb2f4c6a017697ec93db68d65fc1e56aba9fc6e2 Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Thu, 16 May 2019 21:36:26 +0100 Subject: [PATCH 20/27] Added NEWS stub for new version. --- NEWS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/NEWS b/NEWS index 00cbf43..a420ded 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,13 @@ +Version 3.3 +-------------------------------------------------------------------------------- + +New major features: + +New minor features: + +Bugfixes: + + Version 3.2.0 -------------------------------------------------------------------------------- From c21744d893e4d0b93e5d8327b191b505fe6cbe70 Mon Sep 17 00:00:00 2001 From: "Glenn K. Lockwood" Date: Sun, 19 May 2019 09:35:53 -0700 Subject: [PATCH 21/27] updated version after 3.2 was frozen this should've been done when we did the 3.2 feature freeze --- META | 2 +- NEWS | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/META b/META index af848f6..782f846 100755 --- a/META +++ b/META @@ -1,3 +1,3 @@ Package: ior -Version: 3.3alpha1 +Version: 3.3.0+dev Release: 0 diff --git a/NEWS b/NEWS index a420ded..1f2cc74 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -Version 3.3 +Version 3.3.0+dev -------------------------------------------------------------------------------- New major features: @@ -7,6 +7,12 @@ New minor features: Bugfixes: +Version 3.2.1 +-------------------------------------------------------------------------------- + +- Fixed a memory protection bug in mdtest (Julian Kunkel) +- Fixed correctness bugs in mdtest leaf-only mode (#147) (rmn1) +- Fixed bug where mdtest attempted to stat uncreated files (Julian Kunkel) Version 3.2.0 -------------------------------------------------------------------------------- From cf197d5e381f2e1ee4074373399a85c6dc06f083 Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Wed, 22 May 2019 10:21:18 +0100 Subject: [PATCH 22/27] Moved broken collectiveMetadata option into HDF5 backend module. #154 --- doc/sphinx/userDoc/options.rst | 3 +-- src/aiori-HDF5.c | 32 +++++++++++++++++++++++++++++++- src/ior.h | 2 -- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/doc/sphinx/userDoc/options.rst b/doc/sphinx/userDoc/options.rst index 8b44126..2272830 100644 --- a/doc/sphinx/userDoc/options.rst +++ b/doc/sphinx/userDoc/options.rst @@ -289,8 +289,7 @@ HDF5-ONLY * setAlignment - HDF5 alignment in bytes (e.g.: 8, 4k, 2m, 1g) [1] - * collectiveMetadata - enable HDF5 collective metadata (available since - HDF5-1.10.0) + * hdf5.collectiveMetadata - enable HDF5 collective metadata (available since HDF5-1.10.0) MPIIO-, HDF5-, AND NCMPI-ONLY ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/aiori-HDF5.c b/src/aiori-HDF5.c index 250f93d..ab329db 100755 --- a/src/aiori-HDF5.c +++ b/src/aiori-HDF5.c @@ -94,6 +94,34 @@ static void HDF5_Fsync(void *, IOR_param_t *); static IOR_offset_t HDF5_GetFileSize(IOR_param_t *, MPI_Comm, char *); static int HDF5_Access(const char *, int, IOR_param_t *); +/************************** O P T I O N S *****************************/ +typedef struct{ + int collective_md; +} HDF5_options_t; +/***************************** F U N C T I O N S ******************************/ + +static option_help * HDF5_options(void ** init_backend_options, void * init_values){ + HDF5_options_t * o = malloc(sizeof(HDF5_options_t)); + + if (init_values != NULL){ + memcpy(o, init_values, sizeof(HDF5_options_t)); + }else{ + /* initialize the options properly */ + o->collective_md = 0; + } + + *init_backend_options = o; + + option_help h [] = { + {0, "hdf5.collectiveMetadata", "Use collectiveMetadata (available since HDF5-1.10.0)", OPTION_FLAG, 'd', & o->collective_md}, + LAST_OPTION + }; + option_help * help = malloc(sizeof(h)); + memcpy(help, h, sizeof(h)); + return help; +} + + /************************** D E C L A R A T I O N S ***************************/ ior_aiori_t hdf5_aiori = { @@ -112,6 +140,7 @@ ior_aiori_t hdf5_aiori = { .rmdir = aiori_posix_rmdir, .access = HDF5_Access, .stat = aiori_posix_stat, + .get_options = HDF5_options }; static hid_t xferPropList; /* xfer property list */ @@ -230,7 +259,8 @@ static void *HDF5_Open(char *testFileName, IOR_param_t * param) "cannot set alignment"); #ifdef HAVE_H5PSET_ALL_COLL_METADATA_OPS - if (param->collective_md) { + HDF5_options_t *o = (HDF5_options_t*) param->backend_options; + if (o->collective_md) { /* more scalable metadata */ HDF5_CHECK(H5Pset_all_coll_metadata_ops(accessPropList, 1), diff --git a/src/ior.h b/src/ior.h index da4e5c1..5c46efe 100755 --- a/src/ior.h +++ b/src/ior.h @@ -183,8 +183,6 @@ typedef struct char* URI; /* "path" to target object */ size_t part_number; /* multi-part upload increment (PER-RANK!) */ char* UploadId; /* key for multi-part-uploads */ - int collective_md; /* use collective metatata optimization */ - /* RADOS variables */ rados_t rados_cluster; /* RADOS cluster handle */ From 3d8893e507ef0c0e129bf6bd517fbb985330469e Mon Sep 17 00:00:00 2001 From: Vaclav Hapla Date: Wed, 22 May 2019 15:25:21 +0200 Subject: [PATCH 23/27] Fix #155. Fixup 3a873ea fixing #150. --- src/ior-output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ior-output.c b/src/ior-output.c index eaf5bab..4bdb37d 100644 --- a/src/ior-output.c +++ b/src/ior-output.c @@ -450,7 +450,7 @@ void ShowSetup(IOR_param_t *params) if (params->lustre_set_striping) { PrintKeyVal("Lustre stripe size", ((params->lustre_stripe_size == 0) ? "Use default" : HumanReadable(params->lustre_stripe_size, BASE_TWO))); - PrintKeyVal("stripe count", (params->lustre_stripe_count == 0 ? "Use default" : params->lustre_stripe_count) ); + PrintKeyValInt("Lustre stripe count", params->lustre_stripe_count); } #endif /* HAVE_LUSTRE_LUSTRE_USER_H */ if (params->deadlineForStonewalling > 0) { From a6f8388f9f8353efec493a69dfb2ba93143c0fb5 Mon Sep 17 00:00:00 2001 From: Gu Zheng Date: Mon, 8 Oct 2018 20:30:47 +0800 Subject: [PATCH 24/27] add mknod support Add new option '-k' to support file creation test with mknod, which is widely used in lustre. Signed-off-by: Gu Zheng --- src/aiori-POSIX.c | 19 +++++++++++++++++++ src/aiori.h | 2 ++ src/mdtest.c | 25 ++++++++++++++++++++----- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/aiori-POSIX.c b/src/aiori-POSIX.c index 5d38acc..d78cd40 100755 --- a/src/aiori-POSIX.c +++ b/src/aiori-POSIX.c @@ -107,6 +107,7 @@ ior_aiori_t posix_aiori = { .name = "POSIX", .name_legacy = NULL, .create = POSIX_Create, + .mknod = POSIX_Mknod, .open = POSIX_Open, .xfer = POSIX_Xfer, .close = POSIX_Close, @@ -427,6 +428,24 @@ void *POSIX_Create(char *testFileName, IOR_param_t * param) return ((void *)fd); } +/* + * Creat a file through mknod interface. + */ +void *POSIX_Mknod(char *testFileName) +{ + int *fd; + + fd = (int *)malloc(sizeof(int)); + if (fd == NULL) + ERR("Unable to malloc file descriptor"); + + *fd = mknod(testFileName, S_IFREG | S_IRUSR, 0); + if (*fd < 0) + ERR("mknod failed"); + + return ((void *)fd); +} + /* * Open a file through the POSIX interface. */ diff --git a/src/aiori.h b/src/aiori.h index d8cabb5..c2074c2 100755 --- a/src/aiori.h +++ b/src/aiori.h @@ -68,6 +68,7 @@ typedef struct ior_aiori { char *name; char *name_legacy; void *(*create)(char *, IOR_param_t *); + void *(*mknod)(char *); void *(*open)(char *, IOR_param_t *); IOR_offset_t (*xfer)(int, void *, IOR_size_t *, IOR_offset_t, IOR_param_t *); @@ -125,6 +126,7 @@ int aiori_posix_access (const char *path, int mode, IOR_param_t * param); int aiori_posix_stat (const char *path, struct stat *buf, IOR_param_t * param); void *POSIX_Create(char *testFileName, IOR_param_t * param); +void *POSIX_Mknod(char *testFileName); void *POSIX_Open(char *testFileName, IOR_param_t * param); IOR_offset_t POSIX_GetFileSize(IOR_param_t * test, MPI_Comm testComm, char *testFileName); void POSIX_Delete(char *testFileName, IOR_param_t * param); diff --git a/src/mdtest.c b/src/mdtest.c index d65d6f9..8613e3b 100644 --- a/src/mdtest.c +++ b/src/mdtest.c @@ -145,6 +145,7 @@ static size_t read_bytes; static int sync_file; static int path_count; static int nstride; /* neighbor stride */ +static int make_node = 0; static mdtest_results_t * summary_table; static pid_t pid; @@ -337,7 +338,10 @@ static void create_file (const char *path, uint64_t itemNum) { fflush( out_logfile ); } - aiori_fh = backend->open (curr_item, ¶m); + if (make_node) + aiori_fh = backend->mknod (curr_item); + else + aiori_fh = backend->open (curr_item, ¶m); if (NULL == aiori_fh) { FAIL("unable to open file"); } @@ -354,7 +358,10 @@ static void create_file (const char *path, uint64_t itemNum) { fflush( out_logfile ); } - aiori_fh = backend->create (curr_item, ¶m); + if (make_node) + aiori_fh = backend->mknod (curr_item); + else + aiori_fh = backend->create (curr_item, ¶m); if (NULL == aiori_fh) { FAIL("unable to create file"); } @@ -382,7 +389,8 @@ static void create_file (const char *path, uint64_t itemNum) { fflush( out_logfile ); } - backend->close (aiori_fh, ¶m); + if (!make_node) + backend->close (aiori_fh, ¶m); } /* helper for creating/removing items */ @@ -1328,7 +1336,7 @@ void print_help (void) { fprintf(out_logfile, "Usage: mdtest [-b branching_factor] [-B] [-c] [-C] [-d testdir] [-D] [-e number_of_bytes_to_read]\n" - " [-E] [-f first] [-F] [-h] [-i iterations] [-I items_per_dir] [-l last] [-L]\n" + " [-E] [-f first] [-F] [-h] [-i iterations] [-I items_per_dir] [-k] [-l last] [-L]\n" " [-n number_of_items] [-N stride_length] [-p seconds] [-r]\n" " [-R[seed]] [-s stride] [-S] [-t] [-T] [-u] [-v] [-a API]\n" " [-V verbosity_value] [-w number_of_bytes_to_write] [-W seconds] [-y] [-z depth] -Z\n" @@ -1346,6 +1354,7 @@ void print_help (void) { "\t-h: prints this help message\n" "\t-i: number of iterations the test will run\n" "\t-I: number of items per directory in tree\n" + "\t-k: use mknod\n" "\t-l: last number of tasks on which the test will run\n" "\t-L: files only at leaf level of tree\n" "\t-n: every process will creat/stat/read/remove # directories and files\n" @@ -1610,7 +1619,10 @@ void valid_tests() { FAIL("items + items_per_dir can only be set without stonewalling"); } } - + /* check for using mknod */ + if (write_bytes > 0 && make_node) { + FAIL("-k not compatible with -w"); + } } void show_file_system_size(char *file_system) { @@ -2096,6 +2108,7 @@ void mdtest_init_args(){ sync_file = 0; path_count = 0; nstride = 0; + make_node = 0; } mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * world_out) { @@ -2144,6 +2157,7 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * {'F', NULL, "perform test on files only (no directories)", OPTION_FLAG, 'd', & files_only}, {'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', & items_per_dir}, + {'k', NULL, "use mknod to create file", OPTION_FLAG, 'd', & make_node}, {'l', NULL, "last number of tasks on which the test will run", OPTION_OPTIONAL_ARGUMENT, 'd', & last}, {'L', NULL, "files only at leaf level of tree", OPTION_FLAG, 'd', & leaf_only}, {'n', NULL, "every process will creat/stat/read/remove # directories and files", OPTION_OPTIONAL_ARGUMENT, 'l', & items}, @@ -2249,6 +2263,7 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE * fprintf( out_logfile, "write_bytes : "LLU"\n", write_bytes ); fprintf( out_logfile, "sync_file : %s\n", ( sync_file ? "True" : "False" )); fprintf( out_logfile, "depth : %d\n", depth ); + fprintf( out_logfile, "make_node : %d\n", make_node ); fflush( out_logfile ); } From ed4c1d88d0064694783695c0b37b4c77264b828d Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Thu, 23 May 2019 09:31:05 +0100 Subject: [PATCH 25/27] Fix missing initialization in MMAP options. --- src/aiori-MMAP.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aiori-MMAP.c b/src/aiori-MMAP.c index dd6c649..7be860a 100644 --- a/src/aiori-MMAP.c +++ b/src/aiori-MMAP.c @@ -64,7 +64,7 @@ static option_help * MMAP_options(void ** init_backend_options, void * init_valu if (init_values != NULL){ memcpy(o, init_values, sizeof(mmap_options_t)); }else{ - o->direct_io_ignored = 0; + memset(o, 0, sizeof(mmap_options_t)); } *init_backend_options = o; From 1b3182904d9840b9542ab6ed9dbc6d9733078562 Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Thu, 23 May 2019 09:53:51 +0100 Subject: [PATCH 26/27] Moving IME ODirect option into IME. #157 --- src/aiori-IME.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/aiori-IME.c b/src/aiori-IME.c index ef7b3cf..b6cef34 100755 --- a/src/aiori-IME.c +++ b/src/aiori-IME.c @@ -54,6 +54,33 @@ static int IME_Stat(const char *, struct stat *, IOR_param_t *); static void IME_Initialize(); static void IME_Finalize(); + +/************************** O P T I O N S *****************************/ +typedef struct{ + int direct_io; +} ime_options_t; + + +option_help * IME_options(void ** init_backend_options, void * init_values){ + ime_options_t * o = malloc(sizeof(ime_options_t)); + + if (init_values != NULL){ + memcpy(o, init_values, sizeof(ime_options_t)); + }else{ + o->direct_io = 0; + } + + *init_backend_options = o; + + option_help h [] = { + {0, "ime.odirect", "Direct I/O Mode", OPTION_FLAG, 'd', & o->direct_io}, + LAST_OPTION + }; + option_help * help = malloc(sizeof(h)); + memcpy(help, h, sizeof(h)); + return help; +} + /************************** D E C L A R A T I O N S ***************************/ extern int rank; @@ -79,6 +106,7 @@ ior_aiori_t ime_aiori = { .stat = IME_Stat, .initialize = IME_Initialize, .finalize = IME_Finalize, + .get_options = IME_options, .enable_mdtest = true, }; @@ -130,8 +158,10 @@ static void *IME_Open(char *testFileName, IOR_param_t *param) if (fd == NULL) ERR("Unable to malloc file descriptor"); - if (param->useO_DIRECT) - set_o_direct_flag(&fd_oflag); + ime_options_t * o = (ime_options_t*) param->backend_options; + if (o->direct_io == TRUE){ + set_o_direct_flag(&fd_oflag); + } if (param->openFlags & IOR_RDONLY) fd_oflag |= O_RDONLY; From e4969b5af71516c0e8059ae82b05b7703d5ab23f Mon Sep 17 00:00:00 2001 From: "Julian M. Kunkel" Date: Thu, 23 May 2019 12:47:43 +0100 Subject: [PATCH 27/27] Fix for #159 (also slightly improved parsing for options, for portability between scripts also allow comment at the end of an option). --- src/parse_options.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/parse_options.c b/src/parse_options.c index 153fef8..ba72413 100755 --- a/src/parse_options.c +++ b/src/parse_options.c @@ -92,7 +92,7 @@ void DecodeDirective(char *line, IOR_param_t *params, options_all_t * module_opt char value[MAX_STR]; int rc; int initialized; - + rc = sscanf(line, " %[^=# \t\r\n] = %[^# \t\r\n] ", option, value); if (rc != 2 && rank == 0) { fprintf(out_logfile, "Syntax error in configuration options: %s\n", @@ -317,17 +317,26 @@ void ParseLine(char *line, IOR_param_t * test, options_all_t * module_options) { char *start, *end; - start = line; + char * newline = strdup(line); + start = newline; do { end = strchr(start, '#'); - if (end != NULL) + if (end != NULL){ *end = '\0'; + end = NULL; // stop parsing after comment + } end = strchr(start, ','); - if (end != NULL) - *end = '\0'; + if (end != NULL){ + *end = '\0'; + } + if(strlen(start) < 3){ + fprintf(out_logfile, "Invalid option substring string: \"%s\" in \"%s\"\n", start, line); + exit(1); + } DecodeDirective(start, test, module_options); start = end + 1; } while (end != NULL); + free(newline); }