- Merge branch 'master' into daos-devel
- fix bugs with cont destroy. - add destroy option to DFS driver - share pool and container handle with DFS driver, and allow multi rank access Signed-off-by: Mohamad Chaarawi <mohamad.chaarawi@intel.com> Conflicts: src/ior.c src/mdtest.c src/option.c src/parse_options.cmaster
commit
262d35d87e
16
NEWS
16
NEWS
|
@ -1,3 +1,19 @@
|
|||
Version 3.3.0+dev
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
New major features:
|
||||
|
||||
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
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -102,6 +102,10 @@ ior_aiori_t daos_aiori = {
|
|||
.initialize = DAOS_Init,
|
||||
.finalize = DAOS_Fini,
|
||||
.get_options = DAOS_options,
|
||||
.statfs = aiori_posix_statfs,
|
||||
.mkdir = aiori_posix_mkdir,
|
||||
.rmdir = aiori_posix_rmdir,
|
||||
.stat = aiori_posix_stat,
|
||||
};
|
||||
|
||||
#define IOR_DAOS_MUR_SEED 0xDEAD10CC
|
||||
|
@ -327,7 +331,7 @@ DAOS_Fini()
|
|||
|
||||
INFO(VERBOSE_1, "Destroying Container %s", o.cont);
|
||||
uuid_parse(o.cont, uuid);
|
||||
rc = daos_cont_destroy(poh, o.cont, 1, NULL);
|
||||
rc = daos_cont_destroy(poh, uuid, 1, NULL);
|
||||
}
|
||||
|
||||
MPI_Bcast(&rc, 1, MPI_INT, 0, MPI_COMM_WORLD);
|
||||
|
|
207
src/aiori-DFS.c
207
src/aiori-DFS.c
|
@ -48,19 +48,27 @@
|
|||
dfs_t *dfs;
|
||||
daos_handle_t poh, coh;
|
||||
|
||||
enum handleType {
|
||||
POOL_HANDLE,
|
||||
CONT_HANDLE,
|
||||
ARRAY_HANDLE
|
||||
};
|
||||
|
||||
/************************** O P T I O N S *****************************/
|
||||
struct dfs_options{
|
||||
char * pool;
|
||||
char * svcl;
|
||||
char * group;
|
||||
char * cont;
|
||||
char *pool;
|
||||
char *svcl;
|
||||
char *group;
|
||||
char *cont;
|
||||
int destroy;
|
||||
};
|
||||
|
||||
static struct dfs_options o = {
|
||||
.pool = NULL,
|
||||
.svcl = NULL,
|
||||
.group = NULL,
|
||||
.cont = NULL,
|
||||
.pool = NULL,
|
||||
.svcl = NULL,
|
||||
.group = NULL,
|
||||
.cont = NULL,
|
||||
.destroy = 0,
|
||||
};
|
||||
|
||||
static option_help options [] = {
|
||||
|
@ -68,6 +76,7 @@ static option_help options [] = {
|
|||
{0, "dfs.svcl", "DAOS pool SVCL", OPTION_REQUIRED_ARGUMENT, 's', & o.svcl},
|
||||
{0, "dfs.group", "DAOS server group", OPTION_OPTIONAL_ARGUMENT, 's', & o.group},
|
||||
{0, "dfs.cont", "DFS container uuid", OPTION_REQUIRED_ARGUMENT, 's', & o.cont},
|
||||
{0, "dfs.destroy", "Destroy DFS Container", OPTION_FLAG, 'd', &o.destroy},
|
||||
LAST_OPTION
|
||||
};
|
||||
|
||||
|
@ -141,6 +150,59 @@ do { \
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
/* Distribute process 0's pool or container handle to others. */
|
||||
static void
|
||||
HandleDistribute(daos_handle_t *handle, enum handleType type)
|
||||
{
|
||||
d_iov_t global;
|
||||
int rc;
|
||||
|
||||
global.iov_buf = NULL;
|
||||
global.iov_buf_len = 0;
|
||||
global.iov_len = 0;
|
||||
|
||||
assert(type == POOL_HANDLE || type == CONT_HANDLE);
|
||||
if (rank == 0) {
|
||||
/* Get the global handle size. */
|
||||
if (type == POOL_HANDLE)
|
||||
rc = daos_pool_local2global(*handle, &global);
|
||||
else
|
||||
rc = daos_cont_local2global(*handle, &global);
|
||||
DCHECK(rc, "Failed to get global handle size");
|
||||
}
|
||||
|
||||
MPI_CHECK(MPI_Bcast(&global.iov_buf_len, 1, MPI_UINT64_T, 0,
|
||||
MPI_COMM_WORLD),
|
||||
"Failed to bcast global handle buffer size");
|
||||
|
||||
global.iov_len = global.iov_buf_len;
|
||||
global.iov_buf = malloc(global.iov_buf_len);
|
||||
if (global.iov_buf == NULL)
|
||||
ERR("Failed to allocate global handle buffer");
|
||||
|
||||
if (rank == 0) {
|
||||
if (type == POOL_HANDLE)
|
||||
rc = daos_pool_local2global(*handle, &global);
|
||||
else
|
||||
rc = daos_cont_local2global(*handle, &global);
|
||||
DCHECK(rc, "Failed to create global handle");
|
||||
}
|
||||
|
||||
MPI_CHECK(MPI_Bcast(global.iov_buf, global.iov_buf_len, MPI_BYTE, 0,
|
||||
MPI_COMM_WORLD),
|
||||
"Failed to bcast global pool handle");
|
||||
|
||||
if (rank != 0) {
|
||||
if (type == POOL_HANDLE)
|
||||
rc = daos_pool_global2local(global, handle);
|
||||
else
|
||||
rc = daos_cont_global2local(poh, global, handle);
|
||||
DCHECK(rc, "Failed to get local handle");
|
||||
}
|
||||
|
||||
free(global.iov_buf);
|
||||
}
|
||||
|
||||
static int
|
||||
parse_filename(const char *path, char **_obj_name, char **_cont_name)
|
||||
{
|
||||
|
@ -238,52 +300,59 @@ static option_help * DFS_options(){
|
|||
|
||||
static void
|
||||
DFS_Init() {
|
||||
uuid_t pool_uuid, co_uuid;
|
||||
daos_pool_info_t pool_info;
|
||||
daos_cont_info_t co_info;
|
||||
d_rank_list_t *svcl = NULL;
|
||||
bool cont_created = false;
|
||||
int rc;
|
||||
int rc;
|
||||
|
||||
if (o.pool == NULL || o.svcl == NULL || o.cont == NULL)
|
||||
ERR("Invalid pool or container options\n");
|
||||
|
||||
rc = uuid_parse(o.pool, pool_uuid);
|
||||
DCHECK(rc, "Failed to parse 'Pool uuid': %s", o.pool);
|
||||
|
||||
rc = uuid_parse(o.cont, co_uuid);
|
||||
DCHECK(rc, "Failed to parse 'Cont uuid': %s", o.cont);
|
||||
|
||||
svcl = daos_rank_list_parse(o.svcl, ":");
|
||||
if (svcl == NULL)
|
||||
ERR("Failed to allocate svcl");
|
||||
|
||||
if (verbose >= VERBOSE_1) {
|
||||
printf("Pool uuid = %s, SVCL = %s\n", o.pool, o.svcl);
|
||||
printf("DFS Container namespace uuid = %s\n", o.cont);
|
||||
}
|
||||
|
||||
rc = daos_init();
|
||||
DCHECK(rc, "Failed to initialize daos");
|
||||
|
||||
/** Connect to DAOS pool */
|
||||
rc = daos_pool_connect(pool_uuid, o.group, svcl, DAOS_PC_RW, &poh,
|
||||
&pool_info, NULL);
|
||||
DCHECK(rc, "Failed to connect to pool");
|
||||
d_rank_list_free(svcl);
|
||||
rc = daos_cont_open(poh, co_uuid, DAOS_COO_RW, &coh, &co_info, NULL);
|
||||
/* If NOEXIST we create it */
|
||||
if (rc == -DER_NONEXIST) {
|
||||
if (verbose >= VERBOSE_1)
|
||||
printf("Creating DFS Container ...\n");
|
||||
rc = daos_cont_create(poh, co_uuid, NULL, NULL);
|
||||
if (rc == 0) {
|
||||
cont_created = true;
|
||||
rc = daos_cont_open(poh, co_uuid, DAOS_COO_RW, &coh,
|
||||
&co_info, NULL);
|
||||
}
|
||||
}
|
||||
DCHECK(rc, "Failed to create container");
|
||||
if (rank == 0) {
|
||||
uuid_t pool_uuid, co_uuid;
|
||||
d_rank_list_t *svcl = NULL;
|
||||
daos_pool_info_t pool_info;
|
||||
daos_cont_info_t co_info;
|
||||
|
||||
rc = uuid_parse(o.pool, pool_uuid);
|
||||
DCHECK(rc, "Failed to parse 'Pool uuid': %s", o.pool);
|
||||
|
||||
rc = uuid_parse(o.cont, co_uuid);
|
||||
DCHECK(rc, "Failed to parse 'Cont uuid': %s", o.cont);
|
||||
|
||||
svcl = daos_rank_list_parse(o.svcl, ":");
|
||||
if (svcl == NULL)
|
||||
ERR("Failed to allocate svcl");
|
||||
|
||||
if (verbose >= VERBOSE_1) {
|
||||
printf("Pool uuid = %s, SVCL = %s\n", o.pool, o.svcl);
|
||||
printf("DFS Container namespace uuid = %s\n", o.cont);
|
||||
}
|
||||
|
||||
/** Connect to DAOS pool */
|
||||
rc = daos_pool_connect(pool_uuid, o.group, svcl, DAOS_PC_RW,
|
||||
&poh, &pool_info, NULL);
|
||||
d_rank_list_free(svcl);
|
||||
DCHECK(rc, "Failed to connect to pool");
|
||||
|
||||
rc = daos_cont_open(poh, co_uuid, DAOS_COO_RW, &coh, &co_info,
|
||||
NULL);
|
||||
/* If NOEXIST we create it */
|
||||
if (rc == -DER_NONEXIST) {
|
||||
if (verbose >= VERBOSE_1)
|
||||
printf("Creating DFS Container ...\n");
|
||||
|
||||
rc = daos_cont_create(poh, co_uuid, NULL, NULL);
|
||||
if (rc == 0) {
|
||||
rc = daos_cont_open(poh, co_uuid, DAOS_COO_RW,
|
||||
&coh, &co_info, NULL);
|
||||
}
|
||||
}
|
||||
DCHECK(rc, "Failed to create container");
|
||||
}
|
||||
|
||||
HandleDistribute(&poh, POOL_HANDLE);
|
||||
HandleDistribute(&coh, CONT_HANDLE);
|
||||
|
||||
rc = dfs_mount(poh, coh, O_RDWR, &dfs);
|
||||
DCHECK(rc, "Failed to mount DFS namespace");
|
||||
|
@ -300,6 +369,19 @@ DFS_Finalize()
|
|||
rc = daos_cont_close(coh, NULL);
|
||||
DCHECK(rc, "Failed to close container");
|
||||
|
||||
if (rank == 0 && o.destroy) {
|
||||
uuid_t uuid;
|
||||
|
||||
if (verbose >= VERBOSE_1)
|
||||
printf("Destorying DFS Container: %s\n", o.cont);
|
||||
uuid_parse(o.cont, uuid);
|
||||
rc = daos_cont_destroy(poh, uuid, 1, NULL);
|
||||
}
|
||||
|
||||
MPI_Bcast(&rc, 1, MPI_INT, 0, MPI_COMM_WORLD);
|
||||
if (rc)
|
||||
DCHECK(rc, "Failed to destroy container %s (%d)", o.cont, rc);
|
||||
|
||||
daos_pool_disconnect(poh, NULL);
|
||||
DCHECK(rc, "Failed to disconnect from pool");
|
||||
|
||||
|
@ -321,21 +403,32 @@ DFS_Create(char *testFileName, IOR_param_t *param)
|
|||
|
||||
assert(param);
|
||||
|
||||
fd_oflag |= O_CREAT | O_RDWR;
|
||||
mode = S_IFREG | param->mode;
|
||||
|
||||
rc = parse_filename(testFileName, &name, &dir_name);
|
||||
rc = parse_filename(testFileName, &name, &dir_name);
|
||||
DERR(rc, "Failed to parse path %s", testFileName);
|
||||
|
||||
assert(dir_name);
|
||||
assert(name);
|
||||
assert(dir_name);
|
||||
assert(name);
|
||||
|
||||
rc = dfs_lookup(dfs, dir_name, O_RDWR, &parent, &pmode);
|
||||
rc = dfs_lookup(dfs, dir_name, O_RDWR, &parent, &pmode);
|
||||
DERR(rc, "dfs_lookup() of %s Failed", dir_name);
|
||||
mode = S_IFREG | param->mode;
|
||||
|
||||
rc = dfs_open(dfs, parent, name, mode, fd_oflag, DAOS_OC_LARGE_RW,
|
||||
0, NULL, &obj);
|
||||
DERR(rc, "dfs_open() of %s Failed", name);
|
||||
if (param->filePerProc || rank == 0) {
|
||||
fd_oflag |= O_CREAT | O_RDWR | O_EXCL;
|
||||
|
||||
rc = dfs_open(dfs, parent, name, mode, fd_oflag,
|
||||
DAOS_OC_LARGE_RW, 0, NULL, &obj);
|
||||
DERR(rc, "dfs_open() of %s Failed", name);
|
||||
|
||||
MPI_CHECK(MPI_Barrier(testComm), "barrier error");
|
||||
} else {
|
||||
MPI_CHECK(MPI_Barrier(testComm), "barrier error");
|
||||
|
||||
fd_oflag |= O_RDWR;
|
||||
rc = dfs_open(dfs, parent, name, mode, fd_oflag,
|
||||
DAOS_OC_LARGE_RW, 0, NULL, &obj);
|
||||
DERR(rc, "dfs_open() of %s Failed", name);
|
||||
}
|
||||
|
||||
out:
|
||||
if (name)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -138,22 +144,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,
|
||||
};
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,8 @@ ior_aiori_t ime_aiori = {
|
|||
.stat = IME_Stat,
|
||||
.initialize = IME_Initialize,
|
||||
.finalize = IME_Finalize,
|
||||
.get_options = IME_options,
|
||||
.enable_mdtest = true,
|
||||
};
|
||||
|
||||
/***************************** F U N C T I O N S ******************************/
|
||||
|
@ -129,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;
|
||||
|
@ -269,20 +300,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;
|
||||
|
|
|
@ -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{
|
||||
memset(o, 0, sizeof(mmap_options_t));
|
||||
}
|
||||
|
||||
*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);
|
||||
}
|
||||
|
|
|
@ -72,12 +72,42 @@ 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{
|
||||
/* in case of a change, please update depending MMAP module too */
|
||||
int direct_io;
|
||||
} posix_options_t;
|
||||
|
||||
|
||||
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,
|
||||
.create = POSIX_Create,
|
||||
.mknod = POSIX_Mknod,
|
||||
.open = POSIX_Open,
|
||||
.xfer = POSIX_Xfer,
|
||||
.close = POSIX_Close,
|
||||
|
@ -90,6 +120,8 @@ ior_aiori_t posix_aiori = {
|
|||
.rmdir = aiori_posix_rmdir,
|
||||
.access = aiori_posix_access,
|
||||
.stat = aiori_posix_stat,
|
||||
.get_options = POSIX_options,
|
||||
.enable_mdtest = true,
|
||||
};
|
||||
|
||||
/***************************** F U N C T I O N S ******************************/
|
||||
|
@ -200,6 +232,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
|
||||
*/
|
||||
|
@ -246,8 +296,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;
|
||||
|
@ -273,9 +324,10 @@ 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)
|
||||
set_o_direct_flag(&fd_oflag);
|
||||
posix_options_t * o = (posix_options_t*) param->backend_options;
|
||||
if (o->direct_io == TRUE){
|
||||
set_o_direct_flag(&fd_oflag);
|
||||
}
|
||||
|
||||
if(param->dryRun)
|
||||
return 0;
|
||||
|
@ -376,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.
|
||||
*/
|
||||
|
@ -388,7 +458,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;
|
||||
|
|
84
src/aiori.c
84
src/aiori.c
|
@ -76,37 +76,65 @@ 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;
|
||||
}
|
||||
}
|
||||
option_parse(argc, argv, &opt);
|
||||
free(opt.modules);
|
||||
}
|
||||
|
||||
void aiori_supported_apis(char * APIs, char * APIs_legacy){
|
||||
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;
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
20
src/aiori.h
20
src/aiori.h
|
@ -22,6 +22,7 @@
|
|||
#endif /* not MPI_FILE_NULL */
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "ior.h"
|
||||
#include "iordef.h" /* IOR Definitions */
|
||||
|
@ -67,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 *);
|
||||
|
@ -82,9 +84,15 @@ 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;
|
||||
|
||||
enum bench_type {
|
||||
IOR,
|
||||
MDTEST
|
||||
};
|
||||
|
||||
extern ior_aiori_t dummy_aiori;
|
||||
extern ior_aiori_t hdf5_aiori;
|
||||
extern ior_aiori_t hdfs_aiori;
|
||||
|
@ -104,8 +112,11 @@ 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 airoi_parse_options(int argc, char ** argv, option_help * global_options);
|
||||
void aiori_supported_apis(char * APIs, char * APIs_legacy, enum bench_type type);
|
||||
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 */
|
||||
|
@ -117,10 +128,13 @@ 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);
|
||||
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);
|
||||
|
|
|
@ -368,7 +368,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);
|
||||
|
@ -452,7 +451,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)));
|
||||
PrintKeyValInt("Lustre stripe count", params->lustre_stripe_count);
|
||||
}
|
||||
#endif /* HAVE_LUSTRE_LUSTRE_USER_H */
|
||||
if (params->deadlineForStonewalling > 0) {
|
||||
|
|
22
src/ior.c
22
src/ior.c
|
@ -219,8 +219,6 @@ void init_IOR_Param_t(IOR_param_t * p)
|
|||
|
||||
p->beegfs_numTargets = -1;
|
||||
p->beegfs_chunkSize = -1;
|
||||
|
||||
p->mmap_ptr = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -495,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);
|
||||
|
@ -1237,12 +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);
|
||||
|
|
14
src/ior.h
14
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,16 +150,18 @@ 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 */
|
||||
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 */
|
||||
|
@ -179,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 */
|
||||
|
|
98
src/mdtest.c
98
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
|
||||
|
||||
|
@ -145,13 +145,13 @@ 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;
|
||||
static uid_t uid;
|
||||
|
||||
/* just use the POSIX backend for now */
|
||||
static const char *backend_name = "POSIX";
|
||||
/* Use the POSIX backend by default */
|
||||
static const ior_aiori_t *backend;
|
||||
|
||||
static IOR_param_t param;
|
||||
|
@ -210,8 +210,10 @@ 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");
|
||||
}
|
||||
|
||||
|
@ -271,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);
|
||||
}
|
||||
|
@ -300,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);
|
||||
}
|
||||
|
@ -331,12 +333,15 @@ 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 );
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
@ -349,19 +354,22 @@ static void create_file (const char *path, uint64_t itemNum) {
|
|||
param.filePerProc = !shared_file;
|
||||
param.mode = FILEMODE;
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
@ -377,12 +385,13 @@ 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 );
|
||||
}
|
||||
|
||||
backend->close (aiori_fh, ¶m);
|
||||
if (!make_node)
|
||||
backend->close (aiori_fh, ¶m);
|
||||
}
|
||||
|
||||
/* helper for creating/removing items */
|
||||
|
@ -429,7 +438,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 +485,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 +514,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);
|
||||
}
|
||||
|
@ -551,7 +560,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;
|
||||
}
|
||||
|
||||
|
@ -583,13 +592,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 +627,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 +709,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 +738,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 +814,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 );
|
||||
}
|
||||
|
@ -1323,13 +1332,13 @@ 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);
|
||||
|
||||
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"
|
||||
|
@ -1347,6 +1356,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"
|
||||
|
@ -1573,11 +1583,6 @@ void valid_tests() {
|
|||
FAIL("-c not compatible with -B");
|
||||
}
|
||||
|
||||
if (strcasecmp(backend_name, "POSIX") != 0 && strcasecmp(backend_name, "DUMMY") != 0 &&
|
||||
strcasecmp(backend_name, "DFS") != 0) {
|
||||
FAIL("-a only supported interface is POSIX, DFS (and DUMMY) right now!");
|
||||
}
|
||||
|
||||
/* check for shared file incompatibilities */
|
||||
if (unique_dir_per_task && shared_file && rank == 0) {
|
||||
FAIL("-u not compatible with -S");
|
||||
|
@ -1616,7 +1621,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) {
|
||||
|
@ -1716,7 +1724,7 @@ void display_freespace(char *testdirpath)
|
|||
strcpy(dirpath, ".");
|
||||
}
|
||||
|
||||
if (strcasecmp(backend_name, "DFS") == 0)
|
||||
if (strcasecmp(param.api, "DFS") == 0)
|
||||
return;
|
||||
|
||||
if (verbose >= 3 && rank == 0) {
|
||||
|
@ -2105,9 +2113,9 @@ 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) {
|
||||
testComm = world_com;
|
||||
out_logfile = world_out;
|
||||
|
@ -2135,12 +2143,12 @@ 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);
|
||||
|
||||
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},
|
||||
|
@ -2154,6 +2162,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},
|
||||
|
@ -2176,12 +2185,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);
|
||||
|
@ -2233,7 +2240,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" ));
|
||||
|
@ -2264,6 +2271,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 );
|
||||
}
|
||||
|
||||
|
@ -2281,7 +2289,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;
|
||||
}
|
||||
|
|
256
src/option.c
256
src/option.c
|
@ -228,7 +228,141 @@ 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){
|
||||
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)){
|
||||
// now process the option.
|
||||
switch(o->arg){
|
||||
case (OPTION_FLAG):{
|
||||
assert(o->type == 'd');
|
||||
if(arg != NULL){
|
||||
int val = atoi(arg);
|
||||
(*(int*) o->variable) = (val < 0) ? 0 : val;
|
||||
}else{
|
||||
(*(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);
|
||||
}
|
||||
}
|
||||
case('l'):{
|
||||
*(long long*) o->variable = string_to_bytes(arg);
|
||||
break;
|
||||
}
|
||||
case('u'):{
|
||||
*(uint64_t*) 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)++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(strcmp(txt, "-h") == 0 || strcmp(txt, "--help") == 0){
|
||||
*print_help = 1;
|
||||
}else{
|
||||
*error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int option_parse_key_value(char * key, char *val, options_all_t * opt_all){
|
||||
int flag_parsed_next;
|
||||
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;
|
||||
}
|
||||
|
||||
int option_parse(int argc, char ** argv, options_all_t * opt_all){
|
||||
int error = 0;
|
||||
int requiredArgsSeen = 0;
|
||||
int requiredArgsNeeded = 0;
|
||||
|
@ -246,121 +380,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;
|
||||
}
|
||||
case('u'):{
|
||||
*(uint64_t*) 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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,12 @@ 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);
|
||||
}
|
||||
} else if (strcasecmp(option, "summaryFile") == 0) {
|
||||
if (rank == 0){
|
||||
out_resultfile = fopen(value, "w");
|
||||
|
@ -240,8 +219,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,34 +291,57 @@ 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);
|
||||
// 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)
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse a single line, which may contain multiple comma-seperated directives
|
||||
*/
|
||||
void ParseLine(const char *line, IOR_param_t * test)
|
||||
void ParseLine(char *line, IOR_param_t * test, options_all_t * module_options)
|
||||
{
|
||||
char *start, *end;
|
||||
|
||||
start = strdup(line);
|
||||
if (start == NULL)
|
||||
ERR("failed to duplicate line");
|
||||
char * newline = strdup(line);
|
||||
start = newline;
|
||||
do {
|
||||
end = strchr(start, '#');
|
||||
if (end != NULL){
|
||||
*end = '\0';
|
||||
end = NULL; // stop parsing after comment
|
||||
}
|
||||
end = strchr(start, ',');
|
||||
if (end != NULL)
|
||||
*end = '\0';
|
||||
DecodeDirective(start, test);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static void decodeDirectiveWrapper(char *line){
|
||||
ParseLine(line, parameters, global_options);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -385,9 +385,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");
|
||||
|
@ -424,7 +427,10 @@ 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);
|
||||
}
|
||||
runflag = 1;
|
||||
} else if (runflag) {
|
||||
|
@ -432,156 +438,126 @@ 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);
|
||||
((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);
|
||||
ParseLine(ptr, &tail->params, global_options);
|
||||
} else {
|
||||
ParseLine(ptr, &tail->params);
|
||||
ParseLine(ptr, &tail->params, global_options);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
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){
|
||||
ParseLine(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);
|
||||
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(optarg);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
@ -215,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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -14,4 +14,8 @@ transferSize=100k
|
|||
blockSize=100k
|
||||
# space-prefixed comment
|
||||
run
|
||||
--dummy.delay-create=1000
|
||||
useo_direct=0
|
||||
#--posix.odirect=0
|
||||
api=dummy
|
||||
ior stop
|
||||
|
|
Loading…
Reference in New Issue