- 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.c
master
Mohamad Chaarawi 2019-06-24 21:26:15 +00:00
commit 262d35d87e
22 changed files with 967 additions and 529 deletions

2
META
View File

@ -1,3 +1,3 @@
Package: ior
Version: 3.2.0
Version: 3.3.0+dev
Release: 0

16
NEWS
View File

@ -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
--------------------------------------------------------------------------------

View File

@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -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);

View File

@ -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)

View File

@ -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,
};

View File

@ -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),

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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++;
}
}
/**

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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 */

View File

@ -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, &param);
if (make_node)
aiori_fh = backend->mknod (curr_item);
else
aiori_fh = backend->open (curr_item, &param);
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, &param);
if (make_node)
aiori_fh = backend->mknod (curr_item);
else
aiori_fh = backend->create (curr_item, &param);
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, &param);
if (!make_node)
backend->close (aiori_fh, &param);
}
/* 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;
}

View File

@ -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]);
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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