Merge branch 'master' into master

master
Julian Kunkel 2020-06-24 09:50:03 +01:00 committed by GitHub
commit d5de9bcc77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1883 additions and 1365 deletions

2
META
View File

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

View File

@ -212,6 +212,20 @@ AM_COND_IF([USE_RADOS_AIORI],[
AC_DEFINE([USE_RADOS_AIORI], [], [Build RADOS backend AIORI]) AC_DEFINE([USE_RADOS_AIORI], [], [Build RADOS backend AIORI])
]) ])
# CEPHFS support
AC_ARG_WITH([cephfs],
[AS_HELP_STRING([--with-cephfs],
[support IO with libcephfs backend @<:@default=no@:>@])],
[],
[with_cephfs=no])
AS_IF([test "x$with_cephfs" != xno], [
CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64 -std=gnu11"
])
AM_CONDITIONAL([USE_CEPHFS_AIORI], [test x$with_cephfs = xyes])
AM_COND_IF([USE_CEPHFS_AIORI],[
AC_DEFINE([USE_CEPHFS_AIORI], [], [Build CEPHFS backend AIORI])
])
# DAOS Backends (DAOS and DFS) IO support require DAOS and CART/GURT # DAOS Backends (DAOS and DFS) IO support require DAOS and CART/GURT
AC_ARG_WITH([cart], AC_ARG_WITH([cart],
[AS_HELP_STRING([--with-cart], [AS_HELP_STRING([--with-cart],
@ -220,7 +234,8 @@ AC_ARG_WITH([cart],
AS_IF([test "x$with_cart" != xno], [ AS_IF([test "x$with_cart" != xno], [
CART="yes" CART="yes"
LDFLAGS="$LDFLAGS -L$with_cart/lib" LDFLAGS="$LDFLAGS -L$with_cart/lib64 -Wl,--enable-new-dtags -Wl,-rpath=$with_cart/lib64"
LDFLAGS="$LDFLAGS -L$with_cart/lib -Wl,--enable-new-dtags -Wl,-rpath=$with_cart/lib"
CPPFLAGS="$CPPFLAGS -I$with_cart/include/" CPPFLAGS="$CPPFLAGS -I$with_cart/include/"
AC_CHECK_HEADERS(gurt/common.h,, [unset CART]) AC_CHECK_HEADERS(gurt/common.h,, [unset CART])
AC_CHECK_LIB([gurt], [d_hash_murmur64],, [unset CART]) AC_CHECK_LIB([gurt], [d_hash_murmur64],, [unset CART])
@ -233,7 +248,7 @@ AC_ARG_WITH([daos],
AS_IF([test "x$with_daos" != xno], [ AS_IF([test "x$with_daos" != xno], [
DAOS="yes" DAOS="yes"
LDFLAGS="$LDFLAGS -L$with_daos/lib" LDFLAGS="$LDFLAGS -L$with_daos/lib64 -Wl,--enable-new-dtags -Wl,-rpath=$with_daos/lib64"
CPPFLAGS="$CPPFLAGS -I$with_daos/include" CPPFLAGS="$CPPFLAGS -I$with_daos/include"
AC_CHECK_HEADERS(daos_types.h,, [unset DAOS]) AC_CHECK_HEADERS(daos_types.h,, [unset DAOS])
AC_CHECK_LIB([uuid], [uuid_generate],, [unset DAOS]) AC_CHECK_LIB([uuid], [uuid_generate],, [unset DAOS])
@ -348,6 +363,7 @@ AM_CONDITIONAL([USE_CAPS], [test x$enable_caps = xyes])
AC_CONFIG_FILES([Makefile AC_CONFIG_FILES([Makefile
src/Makefile src/Makefile
src/test/Makefile
contrib/Makefile contrib/Makefile
doc/Makefile]) doc/Makefile])
AC_OUTPUT AC_OUTPUT

View File

@ -65,7 +65,6 @@ These options are to be used on the command line. E.g., 'IOR -a POSIX -b 4K'.
-a S api -- API for I/O, e.g., POSIX -a S api -- API for I/O, e.g., POSIX
-A N refNum -- user reference number to include in long summary -A N refNum -- user reference number to include in long summary
-b N blockSize -- contiguous bytes to write per task (e.g.: 8, 4k, 2m, 1g) -b N blockSize -- contiguous bytes to write per task (e.g.: 8, 4k, 2m, 1g)
-B useO_DIRECT -- uses O_DIRECT for POSIX, bypassing I/O buffers
-c collective -- collective I/O -c collective -- collective I/O
-C reorderTasksConstant -- changes task ordering to n+1 ordering for readback -C reorderTasksConstant -- changes task ordering to n+1 ordering for readback
-d N interTestDelay -- delay between reps in seconds -d N interTestDelay -- delay between reps in seconds
@ -118,6 +117,8 @@ NOTES: * S is a string, N is an integer number.
* For transfer and block sizes, the case-insensitive K, M, and G * For transfer and block sizes, the case-insensitive K, M, and G
suffices are recognized. I.e., '4k' or '4K' is accepted as 4096. suffices are recognized. I.e., '4k' or '4K' is accepted as 4096.
Various options are only valid for specific modules, you can see details when running $ ./ior -h
These options are typically prefixed with the module name, an example is: --posix.odirect
********************* *********************
* 4. OPTION DETAILS * * 4. OPTION DETAILS *

View File

@ -22,7 +22,6 @@ These options are to be used on the command line (e.g., ``./ior -a POSIX -b 4K``
-a S api -- API for I/O [POSIX|MPIIO|HDF5|HDFS|S3|S3_EMC|NCMPI|RADOS] -a S api -- API for I/O [POSIX|MPIIO|HDF5|HDFS|S3|S3_EMC|NCMPI|RADOS]
-A N refNum -- user reference number to include in long summary -A N refNum -- user reference number to include in long summary
-b N blockSize -- contiguous bytes to write per task (e.g.: 8, 4k, 2m, 1g) -b N blockSize -- contiguous bytes to write per task (e.g.: 8, 4k, 2m, 1g)
-B useO_DIRECT -- uses O_DIRECT for POSIX, bypassing I/O buffers
-c collective -- collective I/O -c collective -- collective I/O
-C reorderTasksConstant -- changes task ordering to n+1 ordering for readback -C reorderTasksConstant -- changes task ordering to n+1 ordering for readback
-d N interTestDelay -- delay between reps in seconds -d N interTestDelay -- delay between reps in seconds
@ -76,6 +75,9 @@ These options are to be used on the command line (e.g., ``./ior -a POSIX -b 4K``
* For transfer and block sizes, the case-insensitive K, M, and G * For transfer and block sizes, the case-insensitive K, M, and G
suffices are recognized. I.e., '4k' or '4K' is accepted as 4096. suffices are recognized. I.e., '4k' or '4K' is accepted as 4096.
Various options are only valid for specific modules, you can see details when running $ ./ior -h
These options are typically prefixed with the module name, an example is: --posix.odirect
Directive Options Directive Options
------------------ ------------------

View File

@ -1,4 +1,4 @@
SUBDIRS = . SUBDIRS = . test
bin_PROGRAMS = ior mdtest bin_PROGRAMS = ior mdtest
if USE_CAPS if USE_CAPS
@ -75,6 +75,12 @@ extraSOURCES += aiori-RADOS.c
extraLDADD += -lrados extraLDADD += -lrados
endif endif
if USE_CEPHFS_AIORI
extraSOURCES += aiori-CEPHFS.c
extraLDADD += -lcephfs
endif
if USE_DAOS_AIORI if USE_DAOS_AIORI
extraSOURCES += aiori-DAOS.c aiori-DFS.c extraSOURCES += aiori-DAOS.c aiori-DFS.c
endif endif
@ -122,11 +128,3 @@ MDTEST_CPPFLAGS = $(mdtest_CPPFLAGS)
libaiori_a_SOURCES += $(extraSOURCES) libaiori_a_SOURCES += $(extraSOURCES)
libaiori_a_CPPFLAGS = $(extraCPPFLAGS) libaiori_a_CPPFLAGS = $(extraCPPFLAGS)
TESTS = testlib
bin_PROGRAMS += testlib
testlib_SOURCES = ./test/lib.c
testlib_LDFLAGS = $(extraLDFLAGS)
testlib_LDADD = libaiori.a $(extraLDADD)

385
src/aiori-CEPHFS.c Executable file
View File

@ -0,0 +1,385 @@
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*/
/******************************************************************************\
* *
* (C) 2015 The University of Chicago *
* (C) 2020 Red Hat, Inc. *
* *
* See COPYRIGHT in top-level directory. *
* *
********************************************************************************
*
* Implement abstract I/O interface for CEPHFS.
*
\******************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <cephfs/libcephfs.h>
#include "ior.h"
#include "iordef.h"
#include "aiori.h"
#include "utilities.h"
#define CEPH_O_RDONLY 00000000
#define CEPH_O_WRONLY 00000001
#define CEPH_O_RDWR 00000002
#define CEPH_O_CREAT 00000100
#define CEPH_O_EXCL 00000200
#define CEPH_O_TRUNC 00001000
#define CEPH_O_LAZY 00020000
#define CEPH_O_DIRECTORY 00200000
#define CEPH_O_NOFOLLOW 00400000
/************************** O P T I O N S *****************************/
struct cephfs_options{
char * user;
char * conf;
char * prefix;
};
static struct cephfs_options o = {
.user = NULL,
.conf = NULL,
.prefix = NULL,
};
static option_help options [] = {
{0, "cephfs.user", "Username for the ceph cluster", OPTION_REQUIRED_ARGUMENT, 's', & o.user},
{0, "cephfs.conf", "Config file for the ceph cluster", OPTION_REQUIRED_ARGUMENT, 's', & o.conf},
{0, "cephfs.prefix", "mount prefix", OPTION_OPTIONAL_ARGUMENT, 's', & o.prefix},
LAST_OPTION
};
static struct ceph_mount_info *cmount;
/**************************** P R O T O T Y P E S *****************************/
static void CEPHFS_Init();
static void CEPHFS_Final();
static void *CEPHFS_Create(char *, IOR_param_t *);
static void *CEPHFS_Open(char *, IOR_param_t *);
static IOR_offset_t CEPHFS_Xfer(int, void *, IOR_size_t *,
IOR_offset_t, IOR_param_t *);
static void CEPHFS_Close(void *, IOR_param_t *);
static void CEPHFS_Delete(char *, IOR_param_t *);
static void CEPHFS_Fsync(void *, IOR_param_t *);
static IOR_offset_t CEPHFS_GetFileSize(IOR_param_t *, MPI_Comm, char *);
static int CEPHFS_StatFS(const char *, ior_aiori_statfs_t *, IOR_param_t *);
static int CEPHFS_MkDir(const char *, mode_t, IOR_param_t *);
static int CEPHFS_RmDir(const char *, IOR_param_t *);
static int CEPHFS_Access(const char *, int, IOR_param_t *);
static int CEPHFS_Stat(const char *, struct stat *, IOR_param_t *);
static void CEPHFS_Sync(IOR_param_t *);
static option_help * CEPHFS_options();
/************************** D E C L A R A T I O N S ***************************/
ior_aiori_t cephfs_aiori = {
.name = "CEPHFS",
.name_legacy = NULL,
.initialize = CEPHFS_Init,
.finalize = CEPHFS_Final,
.create = CEPHFS_Create,
.open = CEPHFS_Open,
.xfer = CEPHFS_Xfer,
.close = CEPHFS_Close,
.delete = CEPHFS_Delete,
.get_version = aiori_get_version,
.fsync = CEPHFS_Fsync,
.get_file_size = CEPHFS_GetFileSize,
.statfs = CEPHFS_StatFS,
.mkdir = CEPHFS_MkDir,
.rmdir = CEPHFS_RmDir,
.access = CEPHFS_Access,
.stat = CEPHFS_Stat,
.sync = CEPHFS_Sync,
.get_options = CEPHFS_options,
};
#define CEPHFS_ERR(__err_str, __ret) do { \
errno = -__ret; \
ERR(__err_str); \
} while(0)
/***************************** F U N C T I O N S ******************************/
static const char* pfix(const char* path) {
const char* npath = path;
const char* prefix = o.prefix;
while (*prefix) {
if(*prefix++ != *npath++) {
return path;
}
}
return npath;
}
static option_help * CEPHFS_options(){
return options;
}
static void CEPHFS_Init()
{
/* Short circuit if the options haven't been filled yet. */
if (!o.user || !o.conf || !o.prefix) {
WARN("CEPHFS_Init() called before options have been populated!");
return;
}
/* Short circuit if the mount handle already exists */
if (cmount) {
return;
}
int ret;
/* create CEPHFS mount handle */
ret = ceph_create(&cmount, o.user);
if (ret) {
CEPHFS_ERR("unable to create CEPHFS mount handle", ret);
}
/* set the handle using the Ceph config */
ret = ceph_conf_read_file(cmount, o.conf);
if (ret) {
CEPHFS_ERR("unable to read ceph config file", ret);
}
/* mount the handle */
ret = ceph_mount(cmount, "/");
if (ret) {
CEPHFS_ERR("unable to mount cephfs", ret);
ceph_shutdown(cmount);
}
Inode *root;
/* try retrieving the root cephfs inode */
ret = ceph_ll_lookup_root(cmount, &root);
if (ret) {
CEPHFS_ERR("uanble to retrieve root cephfs inode", ret);
ceph_shutdown(cmount);
}
return;
}
static void CEPHFS_Final()
{
/* shutdown */
int ret = ceph_unmount(cmount);
if (ret < 0) {
CEPHFS_ERR("ceph_umount failed", ret);
}
ret = ceph_release(cmount);
if (ret < 0) {
CEPHFS_ERR("ceph_release failed", ret);
}
cmount = NULL;
}
static void *CEPHFS_Create(char *testFileName, IOR_param_t * param)
{
return CEPHFS_Open(testFileName, param);
}
static void *CEPHFS_Open(char *testFileName, IOR_param_t * param)
{
const char *file = pfix(testFileName);
int* fd;
fd = (int *)malloc(sizeof(int));
mode_t mode = 0664;
int flags = (int) 0;
/* set IOR file flags to CephFS flags */
/* -- file open flags -- */
if (param->openFlags & IOR_RDONLY) {
flags |= CEPH_O_RDONLY;
}
if (param->openFlags & IOR_WRONLY) {
flags |= CEPH_O_WRONLY;
}
if (param->openFlags & IOR_RDWR) {
flags |= CEPH_O_RDWR;
}
if (param->openFlags & IOR_APPEND) {
fprintf(stdout, "File append not implemented in CephFS\n");
}
if (param->openFlags & IOR_CREAT) {
flags |= CEPH_O_CREAT;
}
if (param->openFlags & IOR_EXCL) {
flags |= CEPH_O_EXCL;
}
if (param->openFlags & IOR_TRUNC) {
flags |= CEPH_O_TRUNC;
}
if (param->openFlags & IOR_DIRECT) {
fprintf(stdout, "O_DIRECT not implemented in CephFS\n");
}
*fd = ceph_open(cmount, file, flags, mode);
if (*fd < 0) {
CEPHFS_ERR("ceph_open failed", *fd);
}
return (void *) fd;
}
static IOR_offset_t CEPHFS_Xfer(int access, void *file, IOR_size_t * buffer,
IOR_offset_t length, IOR_param_t * param)
{
uint64_t size = (uint64_t) length;
char *buf = (char *) buffer;
int fd = *(int *) file;
int ret;
if (access == WRITE)
{
ret = ceph_write(cmount, fd, buf, size, param->offset);
if (ret < 0) {
CEPHFS_ERR("unable to write file to CephFS", ret);
} else if (ret < size) {
CEPHFS_ERR("short write to CephFS", ret);
}
if (param->fsyncPerWrite == TRUE) {
CEPHFS_Fsync(&fd, param);
}
}
else /* READ */
{
ret = ceph_read(cmount, fd, buf, size, param->offset);
if (ret < 0) {
CEPHFS_ERR("unable to read file from CephFS", ret);
} else if (ret < size) {
CEPHFS_ERR("short read from CephFS", ret);
}
}
return length;
}
static void CEPHFS_Fsync(void *file, IOR_param_t * param)
{
int fd = *(int *) file;
int ret = ceph_fsync(cmount, fd, 0);
if (ret < 0) {
CEPHFS_ERR("ceph_fsync failed", ret);
}
}
static void CEPHFS_Close(void *file, IOR_param_t * param)
{
int fd = *(int *) file;
int ret = ceph_close(cmount, fd);
if (ret < 0) {
CEPHFS_ERR("ceph_close failed", ret);
}
free(file);
return;
}
static void CEPHFS_Delete(char *testFileName, IOR_param_t * param)
{
int ret = ceph_unlink(cmount, pfix(testFileName));
if (ret < 0) {
CEPHFS_ERR("ceph_unlink failed", ret);
}
return;
}
static IOR_offset_t CEPHFS_GetFileSize(IOR_param_t * param, MPI_Comm testComm,
char *testFileName)
{
struct stat stat_buf;
IOR_offset_t aggFileSizeFromStat, tmpMin, tmpMax, tmpSum;
int ret = ceph_stat(cmount, pfix(testFileName), &stat_buf);
if (ret < 0) {
CEPHFS_ERR("ceph_stat failed", ret);
}
aggFileSizeFromStat = stat_buf.st_size;
if (param->filePerProc == TRUE) {
MPI_CHECK(MPI_Allreduce(&aggFileSizeFromStat, &tmpSum, 1,
MPI_LONG_LONG_INT, MPI_SUM, testComm),
"cannot total data moved");
aggFileSizeFromStat = tmpSum;
} else {
MPI_CHECK(MPI_Allreduce(&aggFileSizeFromStat, &tmpMin, 1,
MPI_LONG_LONG_INT, MPI_MIN, testComm),
"cannot total data moved");
MPI_CHECK(MPI_Allreduce(&aggFileSizeFromStat, &tmpMax, 1,
MPI_LONG_LONG_INT, MPI_MAX, testComm),
"cannot total data moved");
if (tmpMin != tmpMax) {
if (rank == 0) {
WARN("inconsistent file size by different tasks");
}
/* incorrect, but now consistent across tasks */
aggFileSizeFromStat = tmpMin;
}
}
return (aggFileSizeFromStat);
}
static int CEPHFS_StatFS(const char *path, ior_aiori_statfs_t *stat_buf,
IOR_param_t *param)
{
#if defined(HAVE_STATVFS)
struct statvfs statfs_buf;
int ret = ceph_statfs(cmount, pfix(path), &statfs_buf);
if (ret < 0) {
CEPHFS_ERR("ceph_statfs failed", ret);
return -1;
}
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
WARN("ceph_statfs requires statvfs!");
return -1;
#endif
}
static int CEPHFS_MkDir(const char *path, mode_t mode, IOR_param_t *param)
{
return ceph_mkdir(cmount, pfix(path), mode);
}
static int CEPHFS_RmDir(const char *path, IOR_param_t *param)
{
return ceph_rmdir(cmount, pfix(path));
}
static int CEPHFS_Access(const char *testFileName, int mode, IOR_param_t *param)
{
struct stat buf;
return ceph_stat(cmount, pfix(testFileName), &buf);
}
static int CEPHFS_Stat(const char *testFileName, struct stat *buf, IOR_param_t *param)
{
return ceph_stat(cmount, pfix(testFileName), buf);
}
static void CEPHFS_Sync(IOR_param_t *param)
{
int ret = ceph_sync_fs(cmount);
if (ret < 0) {
CEPHFS_ERR("ceph_sync_fs failed", ret);
}
}

View File

@ -1,16 +1,9 @@
/* /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8: * vim:expandtab:shiftwidth=8:tabstop=8:
*/ */
/* /*
* Copyright (C) 2018-2019 Intel Corporation * Copyright (C) 2018-2020 Intel Corporation
* * See the file COPYRIGHT for a complete copyright notice and license.
* GOVERNMENT LICENSE RIGHTS-OPEN SOURCE SOFTWARE
* The Government's rights to use, modify, reproduce, release, perform, display,
* or disclose this software are subject to the terms of the Apache License as
* provided in Contract No. 8F-30005.
* Any reproduction of computer software, computer software documentation, or
* portions thereof marked with this legend must also reproduce the markings.
*/ */
/* /*
@ -31,15 +24,16 @@
#include <libgen.h> #include <libgen.h>
#include <stdbool.h> #include <stdbool.h>
#include <mpi.h>
#include <gurt/common.h> #include <gurt/common.h>
#include <daos.h> #include <daos.h>
#include "ior.h"
#include "aiori.h" #include "aiori.h"
#include "utilities.h"
#include "iordef.h" #include "iordef.h"
/************************** O P T I O N S *****************************/ /************************** O P T I O N S *****************************/
struct daos_options{ typedef struct {
char *pool; char *pool;
char *svcl; char *svcl;
char *group; char *group;
@ -47,49 +41,62 @@ struct daos_options{
int chunk_size; int chunk_size;
int destroy; int destroy;
char *oclass; char *oclass;
}; } DAOS_options_t;
static struct daos_options o = { static option_help * DAOS_options(aiori_mod_opt_t ** init_backend_options,
.pool = NULL, aiori_mod_opt_t * init_values){
.svcl = NULL, DAOS_options_t * o = malloc(sizeof(DAOS_options_t));
.group = NULL,
.cont = NULL,
.chunk_size = 1048576,
.destroy = 0,
.oclass = NULL,
};
static option_help options [] = { if (init_values != NULL) {
{0, "daos.pool", "pool uuid", OPTION_OPTIONAL_ARGUMENT, 's', &o.pool}, memcpy(o, init_values, sizeof(DAOS_options_t));
{0, "daos.svcl", "pool SVCL", OPTION_OPTIONAL_ARGUMENT, 's', &o.svcl}, } else {
{0, "daos.group", "server group", OPTION_OPTIONAL_ARGUMENT, 's', &o.group}, memset(o, 0, sizeof(DAOS_options_t));
{0, "daos.cont", "container uuid", OPTION_OPTIONAL_ARGUMENT, 's', &o.cont}, /* initialize the options properly */
{0, "daos.chunk_size", "chunk size", OPTION_OPTIONAL_ARGUMENT, 'd', &o.chunk_size}, o->chunk_size = 1048576;
{0, "daos.destroy", "Destroy Container", OPTION_FLAG, 'd', &o.destroy}, }
{0, "daos.oclass", "object class", OPTION_OPTIONAL_ARGUMENT, 's', &o.oclass},
LAST_OPTION *init_backend_options = (aiori_mod_opt_t *) o;
};
option_help h [] = {
{0, "daos.pool", "pool uuid", OPTION_OPTIONAL_ARGUMENT, 's', &o->pool},
{0, "daos.svcl", "pool SVCL", OPTION_OPTIONAL_ARGUMENT, 's', &o->svcl},
{0, "daos.group", "server group", OPTION_OPTIONAL_ARGUMENT, 's', &o->group},
{0, "daos.cont", "container uuid", OPTION_OPTIONAL_ARGUMENT, 's', &o->cont},
{0, "daos.chunk_size", "chunk size", OPTION_OPTIONAL_ARGUMENT, 'd', &o->chunk_size},
{0, "daos.destroy", "Destroy Container", OPTION_FLAG, 'd', &o->destroy},
{0, "daos.oclass", "object class", OPTION_OPTIONAL_ARGUMENT, 's', &o->oclass},
LAST_OPTION
};
option_help * help = malloc(sizeof(h));
memcpy(help, h, sizeof(h));
return help;
}
/**************************** P R O T O T Y P E S *****************************/ /**************************** P R O T O T Y P E S *****************************/
static void DAOS_Init(); static void DAOS_Init(aiori_mod_opt_t *);
static void DAOS_Fini(); static void DAOS_Fini(aiori_mod_opt_t *);
static void *DAOS_Create(char *, IOR_param_t *); static aiori_fd_t *DAOS_Create(char *, int, aiori_mod_opt_t *);
static void *DAOS_Open(char *, IOR_param_t *); static aiori_fd_t *DAOS_Open(char *, int, aiori_mod_opt_t *);
static int DAOS_Access(const char *, int, IOR_param_t *); static int DAOS_Access(const char *, int, aiori_mod_opt_t *);
static IOR_offset_t DAOS_Xfer(int, void *, IOR_size_t *, static IOR_offset_t DAOS_Xfer(int, aiori_fd_t *, IOR_size_t *, IOR_offset_t,
IOR_offset_t, IOR_param_t *); IOR_offset_t, aiori_mod_opt_t *);
static void DAOS_Close(void *, IOR_param_t *); static void DAOS_Close(aiori_fd_t *, aiori_mod_opt_t *);
static void DAOS_Delete(char *, IOR_param_t *); static void DAOS_Delete(char *, aiori_mod_opt_t *);
static char* DAOS_GetVersion(); static char* DAOS_GetVersion();
static void DAOS_Fsync(void *, IOR_param_t *); static void DAOS_Fsync(aiori_fd_t *, aiori_mod_opt_t *);
static IOR_offset_t DAOS_GetFileSize(IOR_param_t *, MPI_Comm, char *); static IOR_offset_t DAOS_GetFileSize(aiori_mod_opt_t *, MPI_Comm, char *);
static option_help * DAOS_options(); static option_help * DAOS_options();
static void DAOS_init_xfer_options(aiori_xfer_hint_t *);
static int DAOS_check_params(aiori_mod_opt_t *);
/************************** D E C L A R A T I O N S ***************************/ /************************** D E C L A R A T I O N S ***************************/
ior_aiori_t daos_aiori = { ior_aiori_t daos_aiori = {
.name = "DAOS", .name = "DAOS",
.initialize = DAOS_Init,
.finalize = DAOS_Fini,
.create = DAOS_Create, .create = DAOS_Create,
.open = DAOS_Open, .open = DAOS_Open,
.access = DAOS_Access, .access = DAOS_Access,
@ -97,15 +104,17 @@ ior_aiori_t daos_aiori = {
.close = DAOS_Close, .close = DAOS_Close,
.delete = DAOS_Delete, .delete = DAOS_Delete,
.get_version = DAOS_GetVersion, .get_version = DAOS_GetVersion,
.xfer_hints = DAOS_init_xfer_options,
.fsync = DAOS_Fsync, .fsync = DAOS_Fsync,
.get_file_size = DAOS_GetFileSize, .get_file_size = DAOS_GetFileSize,
.initialize = DAOS_Init,
.finalize = DAOS_Fini,
.get_options = DAOS_options,
.statfs = aiori_posix_statfs, .statfs = aiori_posix_statfs,
.mkdir = aiori_posix_mkdir, .mkdir = aiori_posix_mkdir,
.rmdir = aiori_posix_rmdir, .rmdir = aiori_posix_rmdir,
.stat = aiori_posix_stat, .stat = aiori_posix_stat,
.get_options = DAOS_options,
.xfer_hints = DAOS_init_xfer_options,
.check_params = DAOS_check_params,
.enable_mdtest = false,
}; };
#define IOR_DAOS_MUR_SEED 0xDEAD10CC #define IOR_DAOS_MUR_SEED 0xDEAD10CC
@ -151,6 +160,22 @@ do { \
MPI_CHECK(MPI_Abort(MPI_COMM_WORLD, -1), "MPI_Abort() error"); \ MPI_CHECK(MPI_Abort(MPI_COMM_WORLD, -1), "MPI_Abort() error"); \
} while (0) } while (0)
static aiori_xfer_hint_t * hints = NULL;
void DAOS_init_xfer_options(aiori_xfer_hint_t * params)
{
hints = params;
}
static int DAOS_check_params(aiori_mod_opt_t * options){
DAOS_options_t *o = (DAOS_options_t *) options;
if (o->pool == NULL || o->svcl == NULL || o->cont == NULL)
ERR("Invalid pool or container options\n");
return 0;
}
/* Distribute process 0's pool or container handle to others. */ /* Distribute process 0's pool or container handle to others. */
static void static void
HandleDistribute(daos_handle_t *handle, enum handleType type) HandleDistribute(daos_handle_t *handle, enum handleType type)
@ -209,29 +234,22 @@ HandleDistribute(daos_handle_t *handle, enum handleType type)
free(global.iov_buf); free(global.iov_buf);
} }
static option_help *
DAOS_options()
{
return options;
}
static void static void
DAOS_Init() DAOS_Init(aiori_mod_opt_t * options)
{ {
DAOS_options_t *o = (DAOS_options_t *)options;
int rc; int rc;
if (daos_initialized) if (daos_initialized)
return; return;
if (o.pool == NULL || o.svcl == NULL || o.cont == NULL) { if (o->pool == NULL || o->svcl == NULL || o->cont == NULL)
GERR("Invalid DAOS pool/cont\n");
return; return;
}
if (o.oclass) { if (o->oclass) {
objectClass = daos_oclass_name2id(o.oclass); objectClass = daos_oclass_name2id(o->oclass);
if (objectClass == OC_UNKNOWN) if (objectClass == OC_UNKNOWN)
GERR("Invalid DAOS Object class %s\n", o.oclass); GERR("Invalid DAOS Object class %s\n", o->oclass);
} }
rc = daos_init(); rc = daos_init();
@ -244,25 +262,25 @@ DAOS_Init()
static daos_pool_info_t po_info; static daos_pool_info_t po_info;
static daos_cont_info_t co_info; static daos_cont_info_t co_info;
INFO(VERBOSE_1, "Connecting to pool %s", o.pool); INFO(VERBOSE_1, "Connecting to pool %s", o->pool);
rc = uuid_parse(o.pool, uuid); rc = uuid_parse(o->pool, uuid);
DCHECK(rc, "Failed to parse 'pool': %s", o.pool); DCHECK(rc, "Failed to parse 'pool': %s", o->pool);
svcl = daos_rank_list_parse(o.svcl, ":"); svcl = daos_rank_list_parse(o->svcl, ":");
if (svcl == NULL) if (svcl == NULL)
ERR("Failed to allocate svcl"); ERR("Failed to allocate svcl");
rc = daos_pool_connect(uuid, o.group, svcl, DAOS_PC_RW, rc = daos_pool_connect(uuid, o->group, svcl, DAOS_PC_RW,
&poh, &po_info, NULL); &poh, &po_info, NULL);
d_rank_list_free(svcl); d_rank_list_free(svcl);
DCHECK(rc, "Failed to connect to pool %s", o.pool); DCHECK(rc, "Failed to connect to pool %s", o->pool);
INFO(VERBOSE_1, "Create/Open Container %s", o.cont); INFO(VERBOSE_1, "Create/Open Container %s", o->cont);
uuid_clear(uuid); uuid_clear(uuid);
rc = uuid_parse(o.cont, uuid); rc = uuid_parse(o->cont, uuid);
DCHECK(rc, "Failed to parse 'cont': %s", o.cont); DCHECK(rc, "Failed to parse 'cont': %s", o->cont);
rc = daos_cont_open(poh, uuid, DAOS_COO_RW, &coh, &co_info, rc = daos_cont_open(poh, uuid, DAOS_COO_RW, &coh, &co_info,
NULL); NULL);
@ -285,8 +303,9 @@ DAOS_Init()
} }
static void static void
DAOS_Fini() DAOS_Fini(aiori_mod_opt_t *options)
{ {
DAOS_options_t *o = (DAOS_options_t *)options;
int rc; int rc;
if (!daos_initialized) if (!daos_initialized)
@ -295,18 +314,18 @@ DAOS_Fini()
MPI_Barrier(MPI_COMM_WORLD); MPI_Barrier(MPI_COMM_WORLD);
rc = daos_cont_close(coh, NULL); rc = daos_cont_close(coh, NULL);
if (rc) { if (rc) {
DCHECK(rc, "Failed to close container %s (%d)", o.cont, rc); DCHECK(rc, "Failed to close container %s (%d)", o->cont, rc);
MPI_Abort(MPI_COMM_WORLD, -1); MPI_Abort(MPI_COMM_WORLD, -1);
} }
MPI_Barrier(MPI_COMM_WORLD); MPI_Barrier(MPI_COMM_WORLD);
if (o.destroy) { if (o->destroy) {
if (rank == 0) { if (rank == 0) {
uuid_t uuid; uuid_t uuid;
double t1, t2; double t1, t2;
INFO(VERBOSE_1, "Destroying DAOS Container %s", o.cont); INFO(VERBOSE_1, "Destroying DAOS Container %s", o->cont);
uuid_parse(o.cont, uuid); uuid_parse(o->cont, uuid);
t1 = MPI_Wtime(); t1 = MPI_Wtime();
rc = daos_cont_destroy(poh, uuid, 1, NULL); rc = daos_cont_destroy(poh, uuid, 1, NULL);
t2 = MPI_Wtime(); t2 = MPI_Wtime();
@ -317,7 +336,7 @@ DAOS_Fini()
MPI_Bcast(&rc, 1, MPI_INT, 0, MPI_COMM_WORLD); MPI_Bcast(&rc, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (rc) { if (rc) {
if (rank == 0) if (rank == 0)
DCHECK(rc, "Failed to destroy container %s (%d)", o.cont, rc); DCHECK(rc, "Failed to destroy container %s (%d)", o->cont, rc);
MPI_Abort(MPI_COMM_WORLD, -1); MPI_Abort(MPI_COMM_WORLD, -1);
} }
} }
@ -326,7 +345,7 @@ DAOS_Fini()
INFO(VERBOSE_1, "Disconnecting from DAOS POOL.."); INFO(VERBOSE_1, "Disconnecting from DAOS POOL..");
rc = daos_pool_disconnect(poh, NULL); rc = daos_pool_disconnect(poh, NULL);
DCHECK(rc, "Failed to disconnect from pool %s", o.pool); DCHECK(rc, "Failed to disconnect from pool %s", o->pool);
MPI_CHECK(MPI_Barrier(MPI_COMM_WORLD), "barrier error"); MPI_CHECK(MPI_Barrier(MPI_COMM_WORLD), "barrier error");
if (rank == 0) if (rank == 0)
@ -341,38 +360,38 @@ DAOS_Fini()
static void static void
gen_oid(const char *name, daos_obj_id_t *oid) gen_oid(const char *name, daos_obj_id_t *oid)
{ {
oid->lo = d_hash_murmur64(name, strlen(name), IOR_DAOS_MUR_SEED); oid->lo = d_hash_murmur64(name, strlen(name), IOR_DAOS_MUR_SEED);
oid->hi = 0; oid->hi = 0;
daos_array_generate_id(oid, objectClass, true, 0); daos_array_generate_id(oid, objectClass, true, 0);
} }
static void * static aiori_fd_t *
DAOS_Create(char *testFileName, IOR_param_t *param) DAOS_Create(char *testFileName, int flags, aiori_mod_opt_t *param)
{ {
DAOS_options_t *o = (DAOS_options_t*) param;
daos_obj_id_t oid; daos_obj_id_t oid;
int rc; int rc;
/** Convert file name into object ID */ /** Convert file name into object ID */
gen_oid(testFileName, &oid); gen_oid(testFileName, &oid);
/** Create the array */ /** Create the array */
if (param->filePerProc || rank == 0) { if (hints->filePerProc || rank == 0) {
rc = daos_array_create(coh, oid, DAOS_TX_NONE, 1, o.chunk_size, rc = daos_array_create(coh, oid, DAOS_TX_NONE, 1, o->chunk_size,
&aoh, NULL); &aoh, NULL);
DCHECK(rc, "Failed to create array object\n"); DCHECK(rc, "Failed to create array object\n");
} }
/** Distribute the array handle if not FPP */ /** Distribute the array handle if not FPP */
if (!param->filePerProc) if (!hints->filePerProc)
HandleDistribute(&aoh, ARRAY_HANDLE); HandleDistribute(&aoh, ARRAY_HANDLE);
return &aoh; return (aiori_fd_t*)(&aoh);
} }
static int static int
DAOS_Access(const char *testFileName, int mode, IOR_param_t * param) DAOS_Access(const char *testFileName, int mode, aiori_mod_opt_t * param)
{ {
daos_obj_id_t oid; daos_obj_id_t oid;
daos_size_t cell_size, chunk_size; daos_size_t cell_size, chunk_size;
@ -394,8 +413,8 @@ DAOS_Access(const char *testFileName, int mode, IOR_param_t * param)
return rc; return rc;
} }
static void * static aiori_fd_t *
DAOS_Open(char *testFileName, IOR_param_t *param) DAOS_Open(char *testFileName, int flags, aiori_mod_opt_t *param)
{ {
daos_obj_id_t oid; daos_obj_id_t oid;
@ -403,7 +422,7 @@ DAOS_Open(char *testFileName, IOR_param_t *param)
gen_oid(testFileName, &oid); gen_oid(testFileName, &oid);
/** Open the array */ /** Open the array */
if (param->filePerProc || rank == 0) { if (hints->filePerProc || rank == 0) {
daos_size_t cell_size, chunk_size; daos_size_t cell_size, chunk_size;
int rc; int rc;
@ -416,15 +435,15 @@ DAOS_Open(char *testFileName, IOR_param_t *param)
} }
/** Distribute the array handle if not FPP */ /** Distribute the array handle if not FPP */
if (!param->filePerProc) if (!hints->filePerProc)
HandleDistribute(&aoh, ARRAY_HANDLE); HandleDistribute(&aoh, ARRAY_HANDLE);
return &aoh; return (aiori_fd_t*)(&aoh);
} }
static IOR_offset_t static IOR_offset_t
DAOS_Xfer(int access, void *file, IOR_size_t *buffer, DAOS_Xfer(int access, aiori_fd_t *file, IOR_size_t *buffer, IOR_offset_t length,
IOR_offset_t length, IOR_param_t *param) IOR_offset_t off, aiori_mod_opt_t *param)
{ {
daos_array_iod_t iod; daos_array_iod_t iod;
daos_range_t rg; daos_range_t rg;
@ -435,7 +454,7 @@ DAOS_Xfer(int access, void *file, IOR_size_t *buffer,
/** set array location */ /** set array location */
iod.arr_nr = 1; iod.arr_nr = 1;
rg.rg_len = length; rg.rg_len = length;
rg.rg_idx = param->offset; rg.rg_idx = off;
iod.arr_rgs = &rg; iod.arr_rgs = &rg;
/** set memory location */ /** set memory location */
@ -444,10 +463,10 @@ DAOS_Xfer(int access, void *file, IOR_size_t *buffer,
sgl.sg_iovs = &iov; sgl.sg_iovs = &iov;
if (access == WRITE) { if (access == WRITE) {
rc = daos_array_write(aoh, DAOS_TX_NONE, &iod, &sgl, NULL, NULL); rc = daos_array_write(aoh, DAOS_TX_NONE, &iod, &sgl, NULL);
DCHECK(rc, "daos_array_write() failed (%d).", rc); DCHECK(rc, "daos_array_write() failed (%d).", rc);
} else { } else {
rc = daos_array_read(aoh, DAOS_TX_NONE, &iod, &sgl, NULL, NULL); rc = daos_array_read(aoh, DAOS_TX_NONE, &iod, &sgl, NULL);
DCHECK(rc, "daos_array_read() failed (%d).", rc); DCHECK(rc, "daos_array_read() failed (%d).", rc);
} }
@ -455,7 +474,7 @@ DAOS_Xfer(int access, void *file, IOR_size_t *buffer,
} }
static void static void
DAOS_Close(void *file, IOR_param_t *param) DAOS_Close(aiori_fd_t *file, aiori_mod_opt_t *param)
{ {
int rc; int rc;
@ -469,7 +488,7 @@ DAOS_Close(void *file, IOR_param_t *param)
} }
static void static void
DAOS_Delete(char *testFileName, IOR_param_t *param) DAOS_Delete(char *testFileName, aiori_mod_opt_t *param)
{ {
daos_obj_id_t oid; daos_obj_id_t oid;
daos_size_t cell_size, chunk_size; daos_size_t cell_size, chunk_size;
@ -507,13 +526,13 @@ DAOS_GetVersion()
} }
static void static void
DAOS_Fsync(void *file, IOR_param_t *param) DAOS_Fsync(aiori_fd_t *file, aiori_mod_opt_t *param)
{ {
return; return;
} }
static IOR_offset_t static IOR_offset_t
DAOS_GetFileSize(IOR_param_t *param, MPI_Comm testComm, char *testFileName) DAOS_GetFileSize(aiori_mod_opt_t *param, MPI_Comm comm, char *testFileName)
{ {
daos_obj_id_t oid; daos_obj_id_t oid;
daos_size_t size; daos_size_t size;
@ -526,7 +545,7 @@ DAOS_GetFileSize(IOR_param_t *param, MPI_Comm testComm, char *testFileName)
gen_oid(testFileName, &oid); gen_oid(testFileName, &oid);
/** open the array to verify it exists */ /** open the array to verify it exists */
if (param->filePerProc || rank == 0) { if (hints->filePerProc || rank == 0) {
daos_size_t cell_size, chunk_size; daos_size_t cell_size, chunk_size;
rc = daos_array_open(coh, oid, DAOS_TX_NONE, DAOS_OO_RO, rc = daos_array_open(coh, oid, DAOS_TX_NONE, DAOS_OO_RO,
@ -544,7 +563,7 @@ DAOS_GetFileSize(IOR_param_t *param, MPI_Comm testComm, char *testFileName)
aoh.cookie = 0; aoh.cookie = 0;
} }
if (!param->filePerProc) if (!hints->filePerProc)
MPI_Bcast(&size, 1, MPI_LONG, 0, MPI_COMM_WORLD); MPI_Bcast(&size, 1, MPI_LONG, 0, MPI_COMM_WORLD);
return size; return size;

View File

@ -2,14 +2,8 @@
* vim:expandtab:shiftwidth=8:tabstop=8: * vim:expandtab:shiftwidth=8:tabstop=8:
*/ */
/* /*
* Copyright (C) 2018-2019 Intel Corporation * Copyright (C) 2018-2020 Intel Corporation
* * See the file COPYRIGHT for a complete copyright notice and license.
* GOVERNMENT LICENSE RIGHTS-OPEN SOURCE SOFTWARE
* The Government's rights to use, modify, reproduce, release, perform, display,
* or disclose this software are subject to the terms of the Apache License as
* provided in Contract No. 8F-30005.
* Any reproduction of computer software, computer software documentation, or
* portions thereof marked with this legend must also reproduce the markings.
*/ */
/* /*
@ -33,20 +27,22 @@
#include <fcntl.h> #include <fcntl.h>
#include <libgen.h> #include <libgen.h>
#include <mpi.h>
#include <gurt/common.h> #include <gurt/common.h>
#include <gurt/hash.h> #include <gurt/hash.h>
#include <daos.h> #include <daos.h>
#include <daos_fs.h> #include <daos_fs.h>
#include "ior.h"
#include "iordef.h"
#include "aiori.h" #include "aiori.h"
#include "utilities.h" #include "utilities.h"
#include "iordef.h"
dfs_t *dfs; dfs_t *dfs;
static daos_handle_t poh, coh; static daos_handle_t poh, coh;
static daos_oclass_id_t objectClass = OC_SX; static daos_oclass_id_t objectClass = OC_SX;
static daos_oclass_id_t dir_oclass = OC_SX;
static struct d_hash_table *dir_hash; static struct d_hash_table *dir_hash;
static bool dfs_init;
struct aiori_dir_hdl { struct aiori_dir_hdl {
d_list_t entry; d_list_t entry;
@ -57,64 +53,83 @@ struct aiori_dir_hdl {
enum handleType { enum handleType {
POOL_HANDLE, POOL_HANDLE,
CONT_HANDLE, CONT_HANDLE,
ARRAY_HANDLE DFS_HANDLE
}; };
/************************** O P T I O N S *****************************/ /************************** O P T I O N S *****************************/
struct dfs_options{ typedef struct {
char *pool; char *pool;
char *svcl; char *svcl;
char *group; char *group;
char *cont; char *cont;
int chunk_size; int chunk_size;
char *oclass; char *oclass;
char *dir_oclass;
char *prefix;
int destroy; int destroy;
}; } DFS_options_t;
static struct dfs_options o = { static option_help * DFS_options(aiori_mod_opt_t ** init_backend_options,
.pool = NULL, aiori_mod_opt_t * init_values){
.svcl = NULL, DFS_options_t * o = malloc(sizeof(DFS_options_t));
.group = NULL,
.cont = NULL,
.chunk_size = 1048576,
.oclass = NULL,
.destroy = 0,
};
static option_help options [] = { if (init_values != NULL) {
{0, "dfs.pool", "pool uuid", OPTION_OPTIONAL_ARGUMENT, 's', & o.pool}, memcpy(o, init_values, sizeof(DFS_options_t));
{0, "dfs.svcl", "pool SVCL", OPTION_OPTIONAL_ARGUMENT, 's', & o.svcl}, } else {
{0, "dfs.group", "server group", OPTION_OPTIONAL_ARGUMENT, 's', & o.group}, memset(o, 0, sizeof(DFS_options_t));
{0, "dfs.cont", "DFS container uuid", OPTION_OPTIONAL_ARGUMENT, 's', & o.cont}, /* initialize the options properly */
{0, "dfs.chunk_size", "chunk size", OPTION_OPTIONAL_ARGUMENT, 'd', &o.chunk_size}, o->chunk_size = 1048576;
{0, "dfs.oclass", "object class", OPTION_OPTIONAL_ARGUMENT, 's', &o.oclass}, }
{0, "dfs.destroy", "Destroy DFS Container", OPTION_FLAG, 'd', &o.destroy},
LAST_OPTION *init_backend_options = (aiori_mod_opt_t *) o;
};
option_help h [] = {
{0, "dfs.pool", "pool uuid", OPTION_OPTIONAL_ARGUMENT, 's', &o->pool},
{0, "dfs.svcl", "pool SVCL", OPTION_OPTIONAL_ARGUMENT, 's', &o->svcl},
{0, "dfs.group", "server group", OPTION_OPTIONAL_ARGUMENT, 's', &o->group},
{0, "dfs.cont", "DFS container uuid", OPTION_OPTIONAL_ARGUMENT, 's', &o->cont},
{0, "dfs.chunk_size", "chunk size", OPTION_OPTIONAL_ARGUMENT, 'd', &o->chunk_size},
{0, "dfs.oclass", "object class", OPTION_OPTIONAL_ARGUMENT, 's', &o->oclass},
{0, "dfs.dir_oclass", "directory object class", OPTION_OPTIONAL_ARGUMENT, 's',
&o->dir_oclass},
{0, "dfs.prefix", "mount prefix", OPTION_OPTIONAL_ARGUMENT, 's', &o->prefix},
{0, "dfs.destroy", "Destroy DFS Container", OPTION_FLAG, 'd', &o->destroy},
LAST_OPTION
};
option_help * help = malloc(sizeof(h));
memcpy(help, h, sizeof(h));
return help;
}
/**************************** P R O T O T Y P E S *****************************/ /**************************** P R O T O T Y P E S *****************************/
static void *DFS_Create(char *, IOR_param_t *); static void DFS_Init(aiori_mod_opt_t *);
static void *DFS_Open(char *, IOR_param_t *); static void DFS_Finalize(aiori_mod_opt_t *);
static IOR_offset_t DFS_Xfer(int, void *, IOR_size_t *, static aiori_fd_t *DFS_Create(char *, int, aiori_mod_opt_t *);
IOR_offset_t, IOR_param_t *); static aiori_fd_t *DFS_Open(char *, int, aiori_mod_opt_t *);
static void DFS_Close(void *, IOR_param_t *); static IOR_offset_t DFS_Xfer(int, aiori_fd_t *, IOR_size_t *, IOR_offset_t,
static void DFS_Delete(char *, IOR_param_t *); IOR_offset_t, aiori_mod_opt_t *);
static void DFS_Close(aiori_fd_t *, aiori_mod_opt_t *);
static void DFS_Delete(char *, aiori_mod_opt_t *);
static char* DFS_GetVersion(); static char* DFS_GetVersion();
static void DFS_Fsync(void *, IOR_param_t *); static void DFS_Fsync(aiori_fd_t *, aiori_mod_opt_t *);
static IOR_offset_t DFS_GetFileSize(IOR_param_t *, MPI_Comm, char *); static void DFS_Sync(aiori_mod_opt_t *);
static int DFS_Statfs (const char *, ior_aiori_statfs_t *, IOR_param_t *); static IOR_offset_t DFS_GetFileSize(aiori_mod_opt_t *, MPI_Comm, char *);
static int DFS_Stat (const char *, struct stat *, IOR_param_t *); static int DFS_Statfs (const char *, ior_aiori_statfs_t *, aiori_mod_opt_t *);
static int DFS_Mkdir (const char *, mode_t, IOR_param_t *); static int DFS_Stat (const char *, struct stat *, aiori_mod_opt_t *);
static int DFS_Rmdir (const char *, IOR_param_t *); static int DFS_Mkdir (const char *, mode_t, aiori_mod_opt_t *);
static int DFS_Access (const char *, int, IOR_param_t *); static int DFS_Rmdir (const char *, aiori_mod_opt_t *);
static void DFS_Init(); static int DFS_Access (const char *, int, aiori_mod_opt_t *);
static void DFS_Finalize();
static option_help * DFS_options(); static option_help * DFS_options();
static void DFS_init_xfer_options(aiori_xfer_hint_t *);
static int DFS_check_params(aiori_mod_opt_t *);
/************************** D E C L A R A T I O N S ***************************/ /************************** D E C L A R A T I O N S ***************************/
ior_aiori_t dfs_aiori = { ior_aiori_t dfs_aiori = {
.name = "DFS", .name = "DFS",
.initialize = DFS_Init,
.finalize = DFS_Finalize,
.create = DFS_Create, .create = DFS_Create,
.open = DFS_Open, .open = DFS_Open,
.xfer = DFS_Xfer, .xfer = DFS_Xfer,
@ -122,15 +137,17 @@ ior_aiori_t dfs_aiori = {
.delete = DFS_Delete, .delete = DFS_Delete,
.get_version = DFS_GetVersion, .get_version = DFS_GetVersion,
.fsync = DFS_Fsync, .fsync = DFS_Fsync,
.sync = DFS_Sync,
.get_file_size = DFS_GetFileSize, .get_file_size = DFS_GetFileSize,
.xfer_hints = DFS_init_xfer_options,
.statfs = DFS_Statfs, .statfs = DFS_Statfs,
.mkdir = DFS_Mkdir, .mkdir = DFS_Mkdir,
.rmdir = DFS_Rmdir, .rmdir = DFS_Rmdir,
.access = DFS_Access, .access = DFS_Access,
.stat = DFS_Stat, .stat = DFS_Stat,
.initialize = DFS_Init,
.finalize = DFS_Finalize,
.get_options = DFS_options, .get_options = DFS_options,
.check_params = DFS_check_params,
.enable_mdtest = true,
}; };
/***************************** F U N C T I O N S ******************************/ /***************************** F U N C T I O N S ******************************/
@ -161,6 +178,22 @@ do { \
MPI_CHECK(MPI_Abort(MPI_COMM_WORLD, -1), "MPI_Abort() error"); \ MPI_CHECK(MPI_Abort(MPI_COMM_WORLD, -1), "MPI_Abort() error"); \
} while (0) } while (0)
static aiori_xfer_hint_t * hints = NULL;
void DFS_init_xfer_options(aiori_xfer_hint_t * params)
{
hints = params;
}
static int DFS_check_params(aiori_mod_opt_t * options){
DFS_options_t *o = (DFS_options_t *) options;
if (o->pool == NULL || o->svcl == NULL || o->cont == NULL)
ERR("Invalid pool or container options\n");
return 0;
}
static inline struct aiori_dir_hdl * static inline struct aiori_dir_hdl *
hdl_obj(d_list_t *rlink) hdl_obj(d_list_t *rlink)
{ {
@ -193,7 +226,7 @@ static d_hash_table_ops_t hdl_hash_ops = {
/* Distribute process 0's pool or container handle to others. */ /* Distribute process 0's pool or container handle to others. */
static void static void
HandleDistribute(daos_handle_t *handle, enum handleType type) HandleDistribute(enum handleType type)
{ {
d_iov_t global; d_iov_t global;
int rc; int rc;
@ -202,13 +235,15 @@ HandleDistribute(daos_handle_t *handle, enum handleType type)
global.iov_buf_len = 0; global.iov_buf_len = 0;
global.iov_len = 0; global.iov_len = 0;
assert(type == POOL_HANDLE || type == CONT_HANDLE); assert(type == POOL_HANDLE || type == CONT_HANDLE || type == DFS_HANDLE);
if (rank == 0) { if (rank == 0) {
/* Get the global handle size. */ /* Get the global handle size. */
if (type == POOL_HANDLE) if (type == POOL_HANDLE)
rc = daos_pool_local2global(*handle, &global); rc = daos_pool_local2global(poh, &global);
else if (type == CONT_HANDLE)
rc = daos_cont_local2global(coh, &global);
else else
rc = daos_cont_local2global(*handle, &global); rc = dfs_local2global(dfs, &global);
DCHECK(rc, "Failed to get global handle size"); DCHECK(rc, "Failed to get global handle size");
} }
@ -223,9 +258,11 @@ HandleDistribute(daos_handle_t *handle, enum handleType type)
if (rank == 0) { if (rank == 0) {
if (type == POOL_HANDLE) if (type == POOL_HANDLE)
rc = daos_pool_local2global(*handle, &global); rc = daos_pool_local2global(poh, &global);
else if (type == CONT_HANDLE)
rc = daos_cont_local2global(coh, &global);
else else
rc = daos_cont_local2global(*handle, &global); rc = dfs_local2global(dfs, &global);
DCHECK(rc, "Failed to create global handle"); DCHECK(rc, "Failed to create global handle");
} }
@ -235,9 +272,11 @@ HandleDistribute(daos_handle_t *handle, enum handleType type)
if (rank != 0) { if (rank != 0) {
if (type == POOL_HANDLE) if (type == POOL_HANDLE)
rc = daos_pool_global2local(global, handle); rc = daos_pool_global2local(global, &poh);
else if (type == CONT_HANDLE)
rc = daos_cont_global2local(poh, global, &coh);
else else
rc = daos_cont_global2local(poh, global, handle); rc = dfs_global2local(poh, coh, 0, global, &dfs);
DCHECK(rc, "Failed to get local handle"); DCHECK(rc, "Failed to get local handle");
} }
@ -336,7 +375,7 @@ out:
} }
static dfs_obj_t * static dfs_obj_t *
lookup_insert_dir(const char *name) lookup_insert_dir(const char *name, mode_t *mode)
{ {
struct aiori_dir_hdl *hdl; struct aiori_dir_hdl *hdl;
d_list_t *rlink; d_list_t *rlink;
@ -355,8 +394,11 @@ lookup_insert_dir(const char *name)
strncpy(hdl->name, name, PATH_MAX-1); strncpy(hdl->name, name, PATH_MAX-1);
hdl->name[PATH_MAX-1] = '\0'; hdl->name[PATH_MAX-1] = '\0';
rc = dfs_lookup(dfs, name, O_RDWR, &hdl->oh, NULL, NULL); rc = dfs_lookup(dfs, name, O_RDWR, &hdl->oh, mode, NULL);
DCHECK(rc, "dfs_lookup() of %s Failed", name); if (rc)
return NULL;
if (mode && S_ISREG(*mode))
return hdl->oh;
rc = d_hash_rec_insert(dir_hash, hdl->name, strlen(hdl->name), rc = d_hash_rec_insert(dir_hash, hdl->name, strlen(hdl->name),
&hdl->entry, true); &hdl->entry, true);
@ -365,26 +407,35 @@ lookup_insert_dir(const char *name)
return hdl->oh; return hdl->oh;
} }
static option_help * DFS_options(){
return options;
}
static void static void
DFS_Init() { DFS_Init(aiori_mod_opt_t * options)
{
DFS_options_t *o = (DFS_options_t *)options;
int rc; int rc;
if (o.pool == NULL || o.svcl == NULL || o.cont == NULL) /** in case we are already initialized, return */
ERR("Invalid pool or container options\n"); if (dfs_init)
return;
if (o.oclass) { /** shouldn't be fatal since it can be called with POSIX backend selection */
objectClass = daos_oclass_name2id(o.oclass); if (o->pool == NULL || o->svcl == NULL || o->cont == NULL)
if (objectClass == OC_UNKNOWN) return;
GERR("Invalid DAOS Object class %s\n", o.oclass);
}
rc = daos_init(); rc = daos_init();
DCHECK(rc, "Failed to initialize daos"); DCHECK(rc, "Failed to initialize daos");
if (o->oclass) {
objectClass = daos_oclass_name2id(o->oclass);
if (objectClass == OC_UNKNOWN)
GERR("Invalid DAOS object class %s\n", o->oclass);
}
if (o->dir_oclass) {
dir_oclass = daos_oclass_name2id(o->dir_oclass);
if (dir_oclass == OC_UNKNOWN)
GERR("Invalid DAOS directory object class %s\n", o->dir_oclass);
}
rc = d_hash_table_create(0, 16, NULL, &hdl_hash_ops, &dir_hash); rc = d_hash_table_create(0, 16, NULL, &hdl_hash_ops, &dir_hash);
DCHECK(rc, "Failed to initialize dir hashtable"); DCHECK(rc, "Failed to initialize dir hashtable");
@ -394,21 +445,21 @@ DFS_Init() {
daos_pool_info_t pool_info; daos_pool_info_t pool_info;
daos_cont_info_t co_info; daos_cont_info_t co_info;
rc = uuid_parse(o.pool, pool_uuid); rc = uuid_parse(o->pool, pool_uuid);
DCHECK(rc, "Failed to parse 'Pool uuid': %s", o.pool); DCHECK(rc, "Failed to parse 'Pool uuid': %s", o->pool);
rc = uuid_parse(o.cont, co_uuid); rc = uuid_parse(o->cont, co_uuid);
DCHECK(rc, "Failed to parse 'Cont uuid': %s", o.cont); DCHECK(rc, "Failed to parse 'Cont uuid': %s", o->cont);
svcl = daos_rank_list_parse(o.svcl, ":"); svcl = daos_rank_list_parse(o->svcl, ":");
if (svcl == NULL) if (svcl == NULL)
ERR("Failed to allocate svcl"); ERR("Failed to allocate svcl");
INFO(VERBOSE_1, "Pool uuid = %s, SVCL = %s\n", o.pool, o.svcl); INFO(VERBOSE_1, "Pool uuid = %s, SVCL = %s\n", o->pool, o->svcl);
INFO(VERBOSE_1, "DFS Container namespace uuid = %s\n", o.cont); INFO(VERBOSE_1, "DFS Container namespace uuid = %s\n", o->cont);
/** Connect to DAOS pool */ /** Connect to DAOS pool */
rc = daos_pool_connect(pool_uuid, o.group, svcl, DAOS_PC_RW, rc = daos_pool_connect(pool_uuid, o->group, svcl, DAOS_PC_RW,
&poh, &pool_info, NULL); &poh, &pool_info, NULL);
d_rank_list_free(svcl); d_rank_list_free(svcl);
DCHECK(rc, "Failed to connect to pool"); DCHECK(rc, "Failed to connect to pool");
@ -425,18 +476,26 @@ DFS_Init() {
} else if (rc) { } else if (rc) {
DCHECK(rc, "Failed to create container"); DCHECK(rc, "Failed to create container");
} }
rc = dfs_mount(poh, coh, O_RDWR, &dfs);
DCHECK(rc, "Failed to mount DFS namespace");
} }
HandleDistribute(&poh, POOL_HANDLE); HandleDistribute(POOL_HANDLE);
HandleDistribute(&coh, CONT_HANDLE); HandleDistribute(CONT_HANDLE);
HandleDistribute(DFS_HANDLE);
rc = dfs_mount(poh, coh, O_RDWR, &dfs); if (o->prefix) {
DCHECK(rc, "Failed to mount DFS namespace"); rc = dfs_set_prefix(dfs, o->prefix);
DCHECK(rc, "Failed to set DFS Prefix");
}
dfs_init = true;
} }
static void static void
DFS_Finalize() DFS_Finalize(aiori_mod_opt_t *options)
{ {
DFS_options_t *o = (DFS_options_t *)options;
int rc; int rc;
MPI_Barrier(MPI_COMM_WORLD); MPI_Barrier(MPI_COMM_WORLD);
@ -447,16 +506,16 @@ DFS_Finalize()
MPI_Barrier(MPI_COMM_WORLD); MPI_Barrier(MPI_COMM_WORLD);
rc = daos_cont_close(coh, NULL); rc = daos_cont_close(coh, NULL);
DCHECK(rc, "Failed to close container %s (%d)", o.cont, rc); DCHECK(rc, "Failed to close container %s (%d)", o->cont, rc);
MPI_Barrier(MPI_COMM_WORLD); MPI_Barrier(MPI_COMM_WORLD);
if (o.destroy) { if (o->destroy) {
if (rank == 0) { if (rank == 0) {
uuid_t uuid; uuid_t uuid;
double t1, t2; double t1, t2;
INFO(VERBOSE_1, "Destorying DFS Container: %s\n", o.cont); INFO(VERBOSE_1, "Destorying DFS Container: %s\n", o->cont);
uuid_parse(o.cont, uuid); uuid_parse(o->cont, uuid);
t1 = MPI_Wtime(); t1 = MPI_Wtime();
rc = daos_cont_destroy(poh, uuid, 1, NULL); rc = daos_cont_destroy(poh, uuid, 1, NULL);
t2 = MPI_Wtime(); t2 = MPI_Wtime();
@ -467,7 +526,7 @@ DFS_Finalize()
MPI_Bcast(&rc, 1, MPI_INT, 0, MPI_COMM_WORLD); MPI_Bcast(&rc, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (rc) { if (rc) {
if (rank == 0) if (rank == 0)
DCHECK(rc, "Failed to destroy container %s (%d)", o.cont, rc); DCHECK(rc, "Failed to destroy container %s (%d)", o->cont, rc);
MPI_Abort(MPI_COMM_WORLD, -1); MPI_Abort(MPI_COMM_WORLD, -1);
} }
} }
@ -485,45 +544,58 @@ DFS_Finalize()
rc = daos_fini(); rc = daos_fini();
DCHECK(rc, "Failed to finalize DAOS"); DCHECK(rc, "Failed to finalize DAOS");
/** reset tunables */
o->pool = NULL;
o->svcl = NULL;
o->group = NULL;
o->cont = NULL;
o->chunk_size = 1048576;
o->oclass = NULL;
o->dir_oclass = NULL;
o->prefix = NULL;
o->destroy = 0;
objectClass = OC_SX;
dir_oclass = OC_SX;
dfs_init = false;
} }
/* /*
* Creat and open a file through the DFS interface. * Creat and open a file through the DFS interface.
*/ */
static void * static aiori_fd_t *
DFS_Create(char *testFileName, IOR_param_t *param) DFS_Create(char *testFileName, int flags, aiori_mod_opt_t *param)
{ {
DFS_options_t *o = (DFS_options_t*) param;
char *name = NULL, *dir_name = NULL; char *name = NULL, *dir_name = NULL;
dfs_obj_t *obj = NULL, *parent = NULL; dfs_obj_t *obj = NULL, *parent = NULL;
mode_t mode; mode_t mode = 0664;
int fd_oflag = 0; int fd_oflag = 0;
int rc; int rc;
assert(param);
rc = parse_filename(testFileName, &name, &dir_name); rc = parse_filename(testFileName, &name, &dir_name);
DCHECK(rc, "Failed to parse path %s", testFileName); DCHECK(rc, "Failed to parse path %s", testFileName);
assert(dir_name); assert(dir_name);
assert(name); assert(name);
parent = lookup_insert_dir(dir_name); parent = lookup_insert_dir(dir_name, NULL);
if (parent == NULL) if (parent == NULL)
GERR("Failed to lookup parent dir"); GERR("Failed to lookup parent dir");
mode = S_IFREG | param->mode; mode = S_IFREG | mode;
if (param->filePerProc || rank == 0) { if (hints->filePerProc || rank == 0) {
fd_oflag |= O_CREAT | O_RDWR | O_EXCL; fd_oflag |= O_CREAT | O_RDWR | O_EXCL;
rc = dfs_open(dfs, parent, name, mode, fd_oflag, rc = dfs_open(dfs, parent, name, mode, fd_oflag,
objectClass, o.chunk_size, NULL, &obj); objectClass, o->chunk_size, NULL, &obj);
DCHECK(rc, "dfs_open() of %s Failed", name); DCHECK(rc, "dfs_open() of %s Failed", name);
} }
if (!param->filePerProc) { if (!hints->filePerProc) {
MPI_Barrier(MPI_COMM_WORLD); MPI_Barrier(MPI_COMM_WORLD);
if (rank != 0) { if (rank != 0) {
fd_oflag |= O_RDWR; fd_oflag |= O_RDWR;
rc = dfs_open(dfs, parent, name, mode, fd_oflag, rc = dfs_open(dfs, parent, name, mode, fd_oflag,
objectClass, o.chunk_size, NULL, &obj); objectClass, o->chunk_size, NULL, &obj);
DCHECK(rc, "dfs_open() of %s Failed", name); DCHECK(rc, "dfs_open() of %s Failed", name);
} }
} }
@ -533,36 +605,36 @@ DFS_Create(char *testFileName, IOR_param_t *param)
if (dir_name) if (dir_name)
free(dir_name); free(dir_name);
return ((void *)obj); return (aiori_fd_t *)(obj);
} }
/* /*
* Open a file through the DFS interface. * Open a file through the DFS interface.
*/ */
static void * static aiori_fd_t *
DFS_Open(char *testFileName, IOR_param_t *param) DFS_Open(char *testFileName, int flags, aiori_mod_opt_t *param)
{ {
DFS_options_t *o = (DFS_options_t*) param;
char *name = NULL, *dir_name = NULL; char *name = NULL, *dir_name = NULL;
dfs_obj_t *obj = NULL, *parent = NULL; dfs_obj_t *obj = NULL, *parent = NULL;
mode_t mode; mode_t mode = 0664;
int rc;
int fd_oflag = 0; int fd_oflag = 0;
int rc;
fd_oflag |= O_RDWR; fd_oflag |= O_RDWR;
mode = S_IFREG | param->mode; mode = S_IFREG | flags;
rc = parse_filename(testFileName, &name, &dir_name); rc = parse_filename(testFileName, &name, &dir_name);
DCHECK(rc, "Failed to parse path %s", testFileName); DCHECK(rc, "Failed to parse path %s", testFileName);
assert(dir_name); assert(dir_name);
assert(name); assert(name);
parent = lookup_insert_dir(dir_name); parent = lookup_insert_dir(dir_name, NULL);
if (parent == NULL) if (parent == NULL)
GERR("Failed to lookup parent dir"); GERR("Failed to lookup parent dir");
rc = dfs_open(dfs, parent, name, mode, fd_oflag, objectClass, rc = dfs_open(dfs, parent, name, mode, fd_oflag, objectClass,
o.chunk_size, NULL, &obj); o->chunk_size, NULL, &obj);
DCHECK(rc, "dfs_open() of %s Failed", name); DCHECK(rc, "dfs_open() of %s Failed", name);
if (name) if (name)
@ -570,15 +642,15 @@ DFS_Open(char *testFileName, IOR_param_t *param)
if (dir_name) if (dir_name)
free(dir_name); free(dir_name);
return ((void *)obj); return (aiori_fd_t *)(obj);
} }
/* /*
* Write or read access to file using the DFS interface. * Write or read access to file using the DFS interface.
*/ */
static IOR_offset_t static IOR_offset_t
DFS_Xfer(int access, void *file, IOR_size_t *buffer, IOR_offset_t length, DFS_Xfer(int access, aiori_fd_t *file, IOR_size_t *buffer, IOR_offset_t length,
IOR_param_t *param) IOR_offset_t off, aiori_mod_opt_t *param)
{ {
int xferRetries = 0; int xferRetries = 0;
long long remaining = (long long)length; long long remaining = (long long)length;
@ -601,20 +673,20 @@ DFS_Xfer(int access, void *file, IOR_size_t *buffer, IOR_offset_t length,
/* write/read file */ /* write/read file */
if (access == WRITE) { if (access == WRITE) {
rc = dfs_write(dfs, obj, &sgl, param->offset, NULL); rc = dfs_write(dfs, obj, &sgl, off, NULL);
if (rc) { if (rc) {
fprintf(stderr, "dfs_write() failed (%d)", rc); fprintf(stderr, "dfs_write() failed (%d)", rc);
return -1; return -1;
} }
ret = remaining; ret = remaining;
} else { } else {
rc = dfs_read(dfs, obj, &sgl, param->offset, &ret, NULL); rc = dfs_read(dfs, obj, &sgl, off, &ret, NULL);
if (rc || ret == 0) if (rc || ret == 0)
fprintf(stderr, "dfs_read() failed(%d)", rc); fprintf(stderr, "dfs_read() failed(%d)", rc);
} }
if (ret < remaining) { if (ret < remaining) {
if (param->singleXferAttempt == TRUE) if (hints->singleXferAttempt == TRUE)
exit(-1); exit(-1);
if (xferRetries > MAX_RETRY) if (xferRetries > MAX_RETRY)
ERR("too many retries -- aborting"); ERR("too many retries -- aborting");
@ -634,8 +706,20 @@ DFS_Xfer(int access, void *file, IOR_size_t *buffer, IOR_offset_t length,
* Perform fsync(). * Perform fsync().
*/ */
static void static void
DFS_Fsync(void *fd, IOR_param_t * param) DFS_Fsync(aiori_fd_t *fd, aiori_mod_opt_t * param)
{ {
/* no cache in DFS, so this is a no-op currently */
dfs_sync(dfs);
return;
}
/*
* Perform sync() on the dfs mount.
*/
static void
DFS_Sync(aiori_mod_opt_t * param)
{
/* no cache in DFS, so this is a no-op currently */
dfs_sync(dfs); dfs_sync(dfs);
return; return;
} }
@ -644,7 +728,7 @@ DFS_Fsync(void *fd, IOR_param_t * param)
* Close a file through the DFS interface. * Close a file through the DFS interface.
*/ */
static void static void
DFS_Close(void *fd, IOR_param_t * param) DFS_Close(aiori_fd_t *fd, aiori_mod_opt_t * param)
{ {
dfs_release((dfs_obj_t *)fd); dfs_release((dfs_obj_t *)fd);
} }
@ -653,7 +737,7 @@ DFS_Close(void *fd, IOR_param_t * param)
* Delete a file through the DFS interface. * Delete a file through the DFS interface.
*/ */
static void static void
DFS_Delete(char *testFileName, IOR_param_t * param) DFS_Delete(char *testFileName, aiori_mod_opt_t * param)
{ {
char *name = NULL, *dir_name = NULL; char *name = NULL, *dir_name = NULL;
dfs_obj_t *parent = NULL; dfs_obj_t *parent = NULL;
@ -665,7 +749,7 @@ DFS_Delete(char *testFileName, IOR_param_t * param)
assert(dir_name); assert(dir_name);
assert(name); assert(name);
parent = lookup_insert_dir(dir_name); parent = lookup_insert_dir(dir_name, NULL);
if (parent == NULL) if (parent == NULL)
GERR("Failed to lookup parent dir"); GERR("Failed to lookup parent dir");
@ -690,7 +774,7 @@ static char* DFS_GetVersion()
* Use DFS stat() to return aggregate file size. * Use DFS stat() to return aggregate file size.
*/ */
static IOR_offset_t static IOR_offset_t
DFS_GetFileSize(IOR_param_t * test, MPI_Comm comm, char *testFileName) DFS_GetFileSize(aiori_mod_opt_t * test, MPI_Comm comm, char *testFileName)
{ {
dfs_obj_t *obj; dfs_obj_t *obj;
daos_size_t fsize, tmpMin, tmpMax, tmpSum; daos_size_t fsize, tmpMin, tmpMax, tmpSum;
@ -708,7 +792,7 @@ DFS_GetFileSize(IOR_param_t * test, MPI_Comm comm, char *testFileName)
dfs_release(obj); dfs_release(obj);
if (test->filePerProc == TRUE) { if (hints->filePerProc == TRUE) {
MPI_CHECK(MPI_Allreduce(&fsize, &tmpSum, 1, MPI_CHECK(MPI_Allreduce(&fsize, &tmpSum, 1,
MPI_LONG_LONG_INT, MPI_SUM, comm), MPI_LONG_LONG_INT, MPI_SUM, comm),
"cannot total data moved"); "cannot total data moved");
@ -733,13 +817,13 @@ DFS_GetFileSize(IOR_param_t * test, MPI_Comm comm, char *testFileName)
} }
static int static int
DFS_Statfs(const char *path, ior_aiori_statfs_t *sfs, IOR_param_t * param) DFS_Statfs(const char *path, ior_aiori_statfs_t *sfs, aiori_mod_opt_t * param)
{ {
return 0; return 0;
} }
static int static int
DFS_Mkdir(const char *path, mode_t mode, IOR_param_t * param) DFS_Mkdir(const char *path, mode_t mode, aiori_mod_opt_t * param)
{ {
dfs_obj_t *parent = NULL; dfs_obj_t *parent = NULL;
char *name = NULL, *dir_name = NULL; char *name = NULL, *dir_name = NULL;
@ -752,24 +836,22 @@ DFS_Mkdir(const char *path, mode_t mode, IOR_param_t * param)
if (!name) if (!name)
return 0; return 0;
parent = lookup_insert_dir(dir_name); parent = lookup_insert_dir(dir_name, NULL);
if (parent == NULL) if (parent == NULL)
GERR("Failed to lookup parent dir"); GERR("Failed to lookup parent dir");
rc = dfs_mkdir(dfs, parent, name, mode); rc = dfs_mkdir(dfs, parent, name, mode, dir_oclass);
DCHECK(rc, "dfs_mkdir() of %s Failed", name); DCHECK(rc, "dfs_mkdir() of %s Failed", name);
if (name) if (name)
free(name); free(name);
if (dir_name) if (dir_name)
free(dir_name); free(dir_name);
if (rc)
return -1;
return rc; return rc;
} }
static int static int
DFS_Rmdir(const char *path, IOR_param_t * param) DFS_Rmdir(const char *path, aiori_mod_opt_t * param)
{ {
dfs_obj_t *parent = NULL; dfs_obj_t *parent = NULL;
char *name = NULL, *dir_name = NULL; char *name = NULL, *dir_name = NULL;
@ -781,7 +863,7 @@ DFS_Rmdir(const char *path, IOR_param_t * param)
assert(dir_name); assert(dir_name);
assert(name); assert(name);
parent = lookup_insert_dir(dir_name); parent = lookup_insert_dir(dir_name, NULL);
if (parent == NULL) if (parent == NULL)
GERR("Failed to lookup parent dir"); GERR("Failed to lookup parent dir");
@ -798,39 +880,24 @@ DFS_Rmdir(const char *path, IOR_param_t * param)
} }
static int static int
DFS_Access(const char *path, int mode, IOR_param_t * param) DFS_Access(const char *path, int mode, aiori_mod_opt_t * param)
{ {
dfs_obj_t *parent = NULL; dfs_obj_t *obj = NULL;
char *name = NULL, *dir_name = NULL; mode_t fmode;
struct stat stbuf;
int rc;
rc = parse_filename(path, &name, &dir_name); obj = lookup_insert_dir(path, &fmode);
DCHECK(rc, "Failed to parse path %s", path); if (obj == NULL)
assert(dir_name);
parent = lookup_insert_dir(dir_name);
if (parent == NULL)
GERR("Failed to lookup parent dir");
if (name && strcmp(name, ".") == 0) {
free(name);
name = NULL;
}
rc = dfs_stat(dfs, parent, name, &stbuf);
if (name)
free(name);
if (dir_name)
free(dir_name);
if (rc)
return -1; return -1;
return rc;
/** just close if it's a file */
if (S_ISREG(fmode))
dfs_release(obj);
return 0;
} }
static int static int
DFS_Stat(const char *path, struct stat *buf, IOR_param_t * param) DFS_Stat(const char *path, struct stat *buf, aiori_mod_opt_t * param)
{ {
dfs_obj_t *parent = NULL; dfs_obj_t *parent = NULL;
char *name = NULL, *dir_name = NULL; char *name = NULL, *dir_name = NULL;
@ -842,7 +909,7 @@ DFS_Stat(const char *path, struct stat *buf, IOR_param_t * param)
assert(dir_name); assert(dir_name);
assert(name); assert(name);
parent = lookup_insert_dir(dir_name); parent = lookup_insert_dir(dir_name, NULL);
if (parent == NULL) if (parent == NULL)
GERR("Failed to lookup parent dir"); GERR("Failed to lookup parent dir");

View File

@ -25,7 +25,7 @@ typedef struct {
static char * current = (char*) 1; static char * current = (char*) 1;
static option_help * DUMMY_options(void ** init_backend_options, void * init_values){ static option_help * DUMMY_options(aiori_mod_opt_t ** init_backend_options, aiori_mod_opt_t * init_values){
dummy_options_t * o = malloc(sizeof(dummy_options_t)); dummy_options_t * o = malloc(sizeof(dummy_options_t));
if (init_values != NULL){ if (init_values != NULL){
memcpy(o, init_values, sizeof(dummy_options_t)); memcpy(o, init_values, sizeof(dummy_options_t));
@ -33,7 +33,7 @@ static option_help * DUMMY_options(void ** init_backend_options, void * init_val
memset(o, 0, sizeof(dummy_options_t)); memset(o, 0, sizeof(dummy_options_t));
} }
*init_backend_options = o; *init_backend_options = (aiori_mod_opt_t*) o;
option_help h [] = { option_help h [] = {
{0, "dummy.delay-create", "Delay per create in usec", OPTION_OPTIONAL_ARGUMENT, 'l', & o->delay_creates}, {0, "dummy.delay-create", "Delay per create in usec", OPTION_OPTIONAL_ARGUMENT, 'l', & o->delay_creates},
@ -46,44 +46,57 @@ static option_help * DUMMY_options(void ** init_backend_options, void * init_val
return help; return help;
} }
static void *DUMMY_Create(char *testFileName, IOR_param_t * param) static int count_init = 0;
static aiori_fd_t *DUMMY_Create(char *testFileName, int iorflags, aiori_mod_opt_t * options)
{ {
if(count_init <= 0){
ERR("DUMMY missing initialization in create\n");
}
if(verbose > 4){ if(verbose > 4){
fprintf(out_logfile, "DUMMY create: %s = %p\n", testFileName, current); fprintf(out_logfile, "DUMMY create: %s = %p\n", testFileName, current);
} }
dummy_options_t * o = (dummy_options_t*) param->backend_options; dummy_options_t * o = (dummy_options_t*) options;
if (o->delay_creates){ if (o->delay_creates){
if (! o->delay_rank_0_only || (o->delay_rank_0_only && rank == 0)){ 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)}; struct timespec wait = { o->delay_creates / 1000 / 1000, 1000l * (o->delay_creates % 1000000)};
nanosleep( & wait, NULL); nanosleep( & wait, NULL);
} }
} }
return current++; return (aiori_fd_t*) current++;
} }
static void *DUMMY_Open(char *testFileName, IOR_param_t * param) static aiori_fd_t *DUMMY_Open(char *testFileName, int flags, aiori_mod_opt_t * options)
{ {
if(count_init <= 0){
ERR("DUMMY missing initialization in open\n");
}
if(verbose > 4){ if(verbose > 4){
fprintf(out_logfile, "DUMMY open: %s = %p\n", testFileName, current); fprintf(out_logfile, "DUMMY open: %s = %p\n", testFileName, current);
} }
return current++; return (aiori_fd_t*) current++;
} }
static void DUMMY_Fsync(void *fd, IOR_param_t * param) static void DUMMY_Fsync(aiori_fd_t *fd, aiori_mod_opt_t * options)
{ {
if(verbose > 4){ if(verbose > 4){
fprintf(out_logfile, "DUMMY fsync %p\n", fd); fprintf(out_logfile, "DUMMY fsync %p\n", fd);
} }
} }
static void DUMMY_Close(void *fd, IOR_param_t * param)
static void DUMMY_Sync(aiori_mod_opt_t * options)
{
}
static void DUMMY_Close(aiori_fd_t *fd, aiori_mod_opt_t * options)
{ {
if(verbose > 4){ if(verbose > 4){
fprintf(out_logfile, "DUMMY close %p\n", fd); fprintf(out_logfile, "DUMMY close %p\n", fd);
} }
} }
static void DUMMY_Delete(char *testFileName, IOR_param_t * param) static void DUMMY_Delete(char *testFileName, aiori_mod_opt_t * options)
{ {
if(verbose > 4){ if(verbose > 4){
fprintf(out_logfile, "DUMMY delete: %s\n", testFileName); fprintf(out_logfile, "DUMMY delete: %s\n", testFileName);
@ -95,7 +108,7 @@ static char * DUMMY_getVersion()
return "0.5"; return "0.5";
} }
static IOR_offset_t DUMMY_GetFileSize(IOR_param_t * test, MPI_Comm testComm, char *testFileName) static IOR_offset_t DUMMY_GetFileSize(aiori_mod_opt_t * options, MPI_Comm testComm, char *testFileName)
{ {
if(verbose > 4){ if(verbose > 4){
fprintf(out_logfile, "DUMMY getFileSize: %s\n", testFileName); fprintf(out_logfile, "DUMMY getFileSize: %s\n", testFileName);
@ -103,11 +116,11 @@ static IOR_offset_t DUMMY_GetFileSize(IOR_param_t * test, MPI_Comm testComm, cha
return 0; return 0;
} }
static IOR_offset_t DUMMY_Xfer(int access, void *file, IOR_size_t * buffer, IOR_offset_t length, IOR_param_t * param){ static IOR_offset_t DUMMY_Xfer(int access, aiori_fd_t *file, IOR_size_t * buffer, IOR_offset_t length, IOR_offset_t offset, aiori_mod_opt_t * options){
if(verbose > 4){ if(verbose > 4){
fprintf(out_logfile, "DUMMY xfer: %p\n", file); fprintf(out_logfile, "DUMMY xfer: %p\n", file);
} }
dummy_options_t * o = (dummy_options_t*) param->backend_options; dummy_options_t * o = (dummy_options_t*) options;
if (o->delay_xfer){ if (o->delay_xfer){
if (! o->delay_rank_0_only || (o->delay_rank_0_only && rank == 0)){ 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)}; struct timespec wait = {o->delay_xfer / 1000 / 1000, 1000l * (o->delay_xfer % 1000000)};
@ -117,7 +130,7 @@ static IOR_offset_t DUMMY_Xfer(int access, void *file, IOR_size_t * buffer, IOR_
return length; return length;
} }
static int DUMMY_statfs (const char * path, ior_aiori_statfs_t * stat, IOR_param_t * param){ static int DUMMY_statfs (const char * path, ior_aiori_statfs_t * stat, aiori_mod_opt_t * options){
stat->f_bsize = 1; stat->f_bsize = 1;
stat->f_blocks = 1; stat->f_blocks = 1;
stat->f_bfree = 1; stat->f_bfree = 1;
@ -127,26 +140,40 @@ static int DUMMY_statfs (const char * path, ior_aiori_statfs_t * stat, IOR_param
return 0; return 0;
} }
static int DUMMY_mkdir (const char *path, mode_t mode, IOR_param_t * param){ static int DUMMY_mkdir (const char *path, mode_t mode, aiori_mod_opt_t * options){
return 0; return 0;
} }
static int DUMMY_rmdir (const char *path, IOR_param_t * param){ static int DUMMY_rmdir (const char *path, aiori_mod_opt_t * options){
return 0; return 0;
} }
static int DUMMY_access (const char *path, int mode, IOR_param_t * param){ static int DUMMY_access (const char *path, int mode, aiori_mod_opt_t * options){
return 0; return 0;
} }
static int DUMMY_stat (const char *path, struct stat *buf, IOR_param_t * param){ static int DUMMY_stat (const char *path, struct stat *buf, aiori_mod_opt_t * options){
return 0; return 0;
} }
static int DUMMY_check_params(IOR_param_t * test){ static int DUMMY_check_params(aiori_mod_opt_t * options){
return 1; return 0;
} }
static void DUMMY_init(aiori_mod_opt_t * options){
WARN("DUMMY initialized");
count_init++;
}
static void DUMMY_final(aiori_mod_opt_t * options){
WARN("DUMMY finalized");
if(count_init <= 0){
ERR("DUMMY invalid finalization\n");
}
count_init--;
}
ior_aiori_t dummy_aiori = { ior_aiori_t dummy_aiori = {
.name = "DUMMY", .name = "DUMMY",
.name_legacy = NULL, .name_legacy = NULL,
@ -163,9 +190,10 @@ ior_aiori_t dummy_aiori = {
.rmdir = DUMMY_rmdir, .rmdir = DUMMY_rmdir,
.access = DUMMY_access, .access = DUMMY_access,
.stat = DUMMY_stat, .stat = DUMMY_stat,
.initialize = NULL, .initialize = DUMMY_init,
.finalize = NULL, .finalize = DUMMY_final,
.get_options = DUMMY_options, .get_options = DUMMY_options,
.enable_mdtest = true, .check_params = DUMMY_check_params,
.check_params = DUMMY_check_params .sync = DUMMY_Sync,
.enable_mdtest = true
}; };

View File

@ -81,39 +81,53 @@
#endif /* H5_VERS_MAJOR > 1 && H5_VERS_MINOR > 6 */ #endif /* H5_VERS_MAJOR > 1 && H5_VERS_MINOR > 6 */
/**************************** P R O T O T Y P E S *****************************/ /**************************** P R O T O T Y P E S *****************************/
static IOR_offset_t SeekOffset(void *, IOR_offset_t, IOR_param_t *); static IOR_offset_t SeekOffset(void *, IOR_offset_t, aiori_mod_opt_t *);
static void SetupDataSet(void *, IOR_param_t *); static void SetupDataSet(void *, int flags, aiori_mod_opt_t *);
static void *HDF5_Create(char *, IOR_param_t *); static aiori_fd_t *HDF5_Create(char *, int flags, aiori_mod_opt_t *);
static void *HDF5_Open(char *, IOR_param_t *); static aiori_fd_t *HDF5_Open(char *, int flags, aiori_mod_opt_t *);
static IOR_offset_t HDF5_Xfer(int, void *, IOR_size_t *, static IOR_offset_t HDF5_Xfer(int, aiori_fd_t *, IOR_size_t *,
IOR_offset_t, IOR_param_t *); IOR_offset_t, IOR_offset_t, aiori_mod_opt_t *);
static void HDF5_Close(void *, IOR_param_t *); static void HDF5_Close(aiori_fd_t *, aiori_mod_opt_t *);
static void HDF5_Delete(char *, IOR_param_t *); static void HDF5_Delete(char *, aiori_mod_opt_t *);
static char* HDF5_GetVersion(); static char* HDF5_GetVersion();
static void HDF5_Fsync(void *, IOR_param_t *); static void HDF5_Fsync(aiori_fd_t *, aiori_mod_opt_t *);
static IOR_offset_t HDF5_GetFileSize(IOR_param_t *, MPI_Comm, char *); static IOR_offset_t HDF5_GetFileSize(aiori_mod_opt_t *, MPI_Comm, char *);
static int HDF5_Access(const char *, int, IOR_param_t *); static int HDF5_Access(const char *, int, aiori_mod_opt_t *);
static void HDF5_init_xfer_options(aiori_xfer_hint_t * params);
static int HDF5_check_params(aiori_mod_opt_t * options);
/************************** O P T I O N S *****************************/ /************************** O P T I O N S *****************************/
typedef struct{ typedef struct{
int collective_md; int collective_md;
char * hintsFileName; /* full name for hints file */
int showHints; /* show hints */
int individualDataSets; /* datasets not shared by all procs */
int noFill; /* no fill in file creation */
IOR_offset_t setAlignment; /* alignment in bytes */
} HDF5_options_t; } HDF5_options_t;
/***************************** F U N C T I O N S ******************************/ /***************************** F U N C T I O N S ******************************/
static option_help * HDF5_options(void ** init_backend_options, void * init_values){ static option_help * HDF5_options(aiori_mod_opt_t ** init_backend_options, aiori_mod_opt_t * init_values){
HDF5_options_t * o = malloc(sizeof(HDF5_options_t)); HDF5_options_t * o = malloc(sizeof(HDF5_options_t));
if (init_values != NULL){ if (init_values != NULL){
memcpy(o, init_values, sizeof(HDF5_options_t)); memcpy(o, init_values, sizeof(HDF5_options_t));
}else{ }else{
memset(o, 0, sizeof(HDF5_options_t));
/* initialize the options properly */ /* initialize the options properly */
o->collective_md = 0; o->collective_md = 0;
o->setAlignment = 1;
} }
*init_backend_options = o; *init_backend_options = (aiori_mod_opt_t*) o;
option_help h [] = { option_help h [] = {
{0, "hdf5.collectiveMetadata", "Use collectiveMetadata (available since HDF5-1.10.0)", OPTION_FLAG, 'd', & o->collective_md}, {0, "hdf5.collectiveMetadata", "Use collectiveMetadata (available since HDF5-1.10.0)", OPTION_FLAG, 'd', & o->collective_md},
{0, "hdf5.hintsFileName","Full name for hints file", OPTION_OPTIONAL_ARGUMENT, 's', & o->hintsFileName},
{0, "hdf5.showHints", "Show MPI hints", OPTION_FLAG, 'd', & o->showHints},
{0, "hdf5.individualDataSets", "Datasets not shared by all procs [not working]", OPTION_FLAG, 'd', & o->individualDataSets},
{0, "hdf5.setAlignment", "HDF5 alignment in bytes (e.g.: 8, 4k, 2m, 1g)", OPTION_OPTIONAL_ARGUMENT, 'd', & o->setAlignment},
{0, "hdf5.noFill", "No fill in HDF5 file creation", OPTION_FLAG, 'd', & o->noFill},
LAST_OPTION LAST_OPTION
}; };
option_help * help = malloc(sizeof(h)); option_help * help = malloc(sizeof(h));
@ -133,6 +147,7 @@ ior_aiori_t hdf5_aiori = {
.close = HDF5_Close, .close = HDF5_Close,
.delete = HDF5_Delete, .delete = HDF5_Delete,
.get_version = HDF5_GetVersion, .get_version = HDF5_GetVersion,
.xfer_hints = HDF5_init_xfer_options,
.fsync = HDF5_Fsync, .fsync = HDF5_Fsync,
.get_file_size = HDF5_GetFileSize, .get_file_size = HDF5_GetFileSize,
.statfs = aiori_posix_statfs, .statfs = aiori_posix_statfs,
@ -140,7 +155,8 @@ ior_aiori_t hdf5_aiori = {
.rmdir = aiori_posix_rmdir, .rmdir = aiori_posix_rmdir,
.access = HDF5_Access, .access = HDF5_Access,
.stat = aiori_posix_stat, .stat = aiori_posix_stat,
.get_options = HDF5_options .get_options = HDF5_options,
.check_params = HDF5_check_params
}; };
static hid_t xferPropList; /* xfer property list */ static hid_t xferPropList; /* xfer property list */
@ -151,20 +167,47 @@ hid_t memDataSpace; /* memory data space id */
int newlyOpenedFile; /* newly opened file */ int newlyOpenedFile; /* newly opened file */
/***************************** F U N C T I O N S ******************************/ /***************************** F U N C T I O N S ******************************/
static aiori_xfer_hint_t * hints = NULL;
static void HDF5_init_xfer_options(aiori_xfer_hint_t * params){
hints = params;
}
static int HDF5_check_params(aiori_mod_opt_t * options){
HDF5_options_t *o = (HDF5_options_t*) options;
if (o->setAlignment < 0)
ERR("alignment must be non-negative integer");
if (o->individualDataSets)
ERR("individual data sets not implemented");
if (o->noFill) {
/* check if hdf5 available */
#if defined (H5_VERS_MAJOR) && defined (H5_VERS_MINOR)
/* no-fill option not available until hdf5-1.6.x */
#if (H5_VERS_MAJOR > 0 && H5_VERS_MINOR > 5)
#else
ERRF("'no fill' option not available in HDF5");
#endif
#else
WARN("unable to determine HDF5 version for 'no fill' usage");
#endif
}
return 0;
}
/* /*
* Create and open a file through the HDF5 interface. * Create and open a file through the HDF5 interface.
*/ */
static void *HDF5_Create(char *testFileName, IOR_param_t * param) static aiori_fd_t *HDF5_Create(char *testFileName, int flags, aiori_mod_opt_t * param)
{ {
return HDF5_Open(testFileName, param); return HDF5_Open(testFileName, flags, param);
} }
/* /*
* Open a file through the HDF5 interface. * Open a file through the HDF5 interface.
*/ */
static void *HDF5_Open(char *testFileName, IOR_param_t * param) static aiori_fd_t *HDF5_Open(char *testFileName, int flags, aiori_mod_opt_t * param)
{ {
HDF5_options_t *o = (HDF5_options_t*) param;
hid_t accessPropList, createPropList; hid_t accessPropList, createPropList;
hsize_t memStart[NUM_DIMS], hsize_t memStart[NUM_DIMS],
dataSetDims[NUM_DIMS], dataSetDims[NUM_DIMS],
@ -182,36 +225,27 @@ static void *HDF5_Open(char *testFileName, IOR_param_t * param)
/* /*
* HDF5 uses different flags than those for POSIX/MPIIO * HDF5 uses different flags than those for POSIX/MPIIO
*/ */
if (param->open == WRITE) { /* WRITE flags */
param->openFlags = IOR_TRUNC;
} else { /* READ or check WRITE/READ flags */
param->openFlags = IOR_RDONLY;
}
/* set IOR file flags to HDF5 flags */ /* set IOR file flags to HDF5 flags */
/* -- file open flags -- */ /* -- file open flags -- */
if (param->openFlags & IOR_RDONLY) { if (flags & IOR_RDONLY) {
fd_mode |= H5F_ACC_RDONLY; fd_mode |= H5F_ACC_RDONLY;
} }
if (param->openFlags & IOR_WRONLY) { if (flags & IOR_WRONLY || flags & IOR_RDWR) {
fprintf(stdout, "File write only not implemented in HDF5\n");
}
if (param->openFlags & IOR_RDWR) {
fd_mode |= H5F_ACC_RDWR; fd_mode |= H5F_ACC_RDWR;
} }
if (param->openFlags & IOR_APPEND) { if (flags & IOR_APPEND) {
fprintf(stdout, "File append not implemented in HDF5\n"); fprintf(stdout, "File append not implemented in HDF5\n");
} }
if (param->openFlags & IOR_CREAT) { if (flags & IOR_CREAT) {
fd_mode |= H5F_ACC_CREAT; fd_mode |= H5F_ACC_CREAT;
} }
if (param->openFlags & IOR_EXCL) { if (flags & IOR_EXCL) {
fd_mode |= H5F_ACC_EXCL; fd_mode |= H5F_ACC_EXCL;
} }
if (param->openFlags & IOR_TRUNC) { if (flags & IOR_TRUNC) {
fd_mode |= H5F_ACC_TRUNC; fd_mode |= H5F_ACC_TRUNC;
} }
if (param->openFlags & IOR_DIRECT) { if (flags & IOR_DIRECT) {
fprintf(stdout, "O_DIRECT not implemented in HDF5\n"); fprintf(stdout, "O_DIRECT not implemented in HDF5\n");
} }
@ -231,13 +265,13 @@ static void *HDF5_Open(char *testFileName, IOR_param_t * param)
* someday HDF5 implementation will allow subsets of MPI_COMM_WORLD * someday HDF5 implementation will allow subsets of MPI_COMM_WORLD
*/ */
/* store MPI communicator info for the file access property list */ /* store MPI communicator info for the file access property list */
if (param->filePerProc) { if (hints->filePerProc) {
comm = MPI_COMM_SELF; comm = MPI_COMM_SELF;
} else { } else {
comm = testComm; comm = testComm;
} }
SetHints(&mpiHints, param->hintsFileName); SetHints(&mpiHints, o->hintsFileName);
/* /*
* note that with MP_HINTS_FILTERED=no, all key/value pairs will * note that with MP_HINTS_FILTERED=no, all key/value pairs will
* be in the info object. The info object that is attached to * be in the info object. The info object that is attached to
@ -245,7 +279,7 @@ static void *HDF5_Open(char *testFileName, IOR_param_t * param)
* deemed valid by the implementation. * deemed valid by the implementation.
*/ */
/* show hints passed to file */ /* show hints passed to file */
if (rank == 0 && param->showHints) { if (rank == 0 && o->showHints) {
fprintf(stdout, "\nhints passed to access property list {\n"); fprintf(stdout, "\nhints passed to access property list {\n");
ShowHints(&mpiHints); ShowHints(&mpiHints);
fprintf(stdout, "}\n"); fprintf(stdout, "}\n");
@ -254,12 +288,11 @@ static void *HDF5_Open(char *testFileName, IOR_param_t * param)
"cannot set file access property list"); "cannot set file access property list");
/* set alignment */ /* set alignment */
HDF5_CHECK(H5Pset_alignment(accessPropList, param->setAlignment, HDF5_CHECK(H5Pset_alignment(accessPropList, o->setAlignment, o->setAlignment),
param->setAlignment),
"cannot set alignment"); "cannot set alignment");
#ifdef HAVE_H5PSET_ALL_COLL_METADATA_OPS #ifdef HAVE_H5PSET_ALL_COLL_METADATA_OPS
HDF5_options_t *o = (HDF5_options_t*) param->backend_options;
if (o->collective_md) { if (o->collective_md) {
/* more scalable metadata */ /* more scalable metadata */
@ -271,10 +304,9 @@ static void *HDF5_Open(char *testFileName, IOR_param_t * param)
#endif #endif
/* open file */ /* open file */
if(! param->dryRun){ if(! hints->dryRun){
if (param->open == WRITE) { /* WRITE */ if (flags & IOR_CREAT) { /* WRITE */
*fd = H5Fcreate(testFileName, fd_mode, *fd = H5Fcreate(testFileName, H5F_ACC_TRUNC, createPropList, accessPropList);
createPropList, accessPropList);
HDF5_CHECK(*fd, "cannot create file"); HDF5_CHECK(*fd, "cannot create file");
} else { /* READ or CHECK */ } else { /* READ or CHECK */
*fd = H5Fopen(testFileName, fd_mode, accessPropList); *fd = H5Fopen(testFileName, fd_mode, accessPropList);
@ -283,9 +315,8 @@ static void *HDF5_Open(char *testFileName, IOR_param_t * param)
} }
/* show hints actually attached to file handle */ /* show hints actually attached to file handle */
if (param->showHints || (1) /* WEL - this needs fixing */ ) { if (o->showHints || (1) /* WEL - this needs fixing */ ) {
if (rank == 0 if (rank == 0 && (o->showHints) /* WEL - this needs fixing */ ) {
&& (param->showHints) /* WEL - this needs fixing */ ) {
WARN("showHints not working for HDF5"); WARN("showHints not working for HDF5");
} }
} else { } else {
@ -334,7 +365,7 @@ static void *HDF5_Open(char *testFileName, IOR_param_t * param)
HDF5_CHECK(xferPropList, "cannot create transfer property list"); HDF5_CHECK(xferPropList, "cannot create transfer property list");
/* set data transfer mode */ /* set data transfer mode */
if (param->collective) { if (hints->collective) {
HDF5_CHECK(H5Pset_dxpl_mpio(xferPropList, H5FD_MPIO_COLLECTIVE), HDF5_CHECK(H5Pset_dxpl_mpio(xferPropList, H5FD_MPIO_COLLECTIVE),
"cannot set collective data transfer mode"); "cannot set collective data transfer mode");
} else { } else {
@ -346,9 +377,9 @@ static void *HDF5_Open(char *testFileName, IOR_param_t * param)
/* set up memory data space for transfer */ /* set up memory data space for transfer */
memStart[0] = (hsize_t) 0; memStart[0] = (hsize_t) 0;
memCount[0] = (hsize_t) 1; memCount[0] = (hsize_t) 1;
memStride[0] = (hsize_t) (param->transferSize / sizeof(IOR_size_t)); memStride[0] = (hsize_t) (hints->transferSize / sizeof(IOR_size_t));
memBlock[0] = (hsize_t) (param->transferSize / sizeof(IOR_size_t)); memBlock[0] = (hsize_t) (hints->transferSize / sizeof(IOR_size_t));
memDataSpaceDims[0] = (hsize_t) param->transferSize; memDataSpaceDims[0] = (hsize_t) hints->transferSize;
memDataSpace = H5Screate_simple(NUM_DIMS, memDataSpaceDims, NULL); memDataSpace = H5Screate_simple(NUM_DIMS, memDataSpaceDims, NULL);
HDF5_CHECK(memDataSpace, "cannot create simple memory data space"); HDF5_CHECK(memDataSpace, "cannot create simple memory data space");
@ -358,18 +389,18 @@ static void *HDF5_Open(char *testFileName, IOR_param_t * param)
memBlock), "cannot create hyperslab"); memBlock), "cannot create hyperslab");
/* set up parameters for fpp or different dataset count */ /* set up parameters for fpp or different dataset count */
if (param->filePerProc) { if (hints->filePerProc) {
tasksPerDataSet = 1; tasksPerDataSet = 1;
} else { } else {
if (param->individualDataSets) { if (o->individualDataSets) {
/* each task in segment has single data set */ /* each task in segment has single data set */
tasksPerDataSet = 1; tasksPerDataSet = 1;
} else { } else {
/* share single data set across all tasks in segment */ /* share single data set across all tasks in segment */
tasksPerDataSet = param->numTasks; tasksPerDataSet = hints->numTasks;
} }
} }
dataSetDims[0] = (hsize_t) ((param->blockSize / sizeof(IOR_size_t)) dataSetDims[0] = (hsize_t) ((hints->blockSize / sizeof(IOR_size_t))
* tasksPerDataSet); * tasksPerDataSet);
/* create a simple data space containing information on size /* create a simple data space containing information on size
@ -379,14 +410,14 @@ static void *HDF5_Open(char *testFileName, IOR_param_t * param)
if (mpiHints != MPI_INFO_NULL) if (mpiHints != MPI_INFO_NULL)
MPI_Info_free(&mpiHints); MPI_Info_free(&mpiHints);
return (fd); return (aiori_fd_t*)(fd);
} }
/* /*
* Write or read access to file using the HDF5 interface. * Write or read access to file using the HDF5 interface.
*/ */
static IOR_offset_t HDF5_Xfer(int access, void *fd, IOR_size_t * buffer, static IOR_offset_t HDF5_Xfer(int access, aiori_fd_t *fd, IOR_size_t * buffer,
IOR_offset_t length, IOR_param_t * param) IOR_offset_t length, IOR_offset_t offset, aiori_mod_opt_t * param)
{ {
static int firstReadCheck = FALSE, startNewDataSet; static int firstReadCheck = FALSE, startNewDataSet;
IOR_offset_t segmentPosition, segmentSize; IOR_offset_t segmentPosition, segmentSize;
@ -405,17 +436,16 @@ static IOR_offset_t HDF5_Xfer(int access, void *fd, IOR_size_t * buffer,
} }
/* determine by offset if need to start new data set */ /* determine by offset if need to start new data set */
if (param->filePerProc == TRUE) { if (hints->filePerProc == TRUE) {
segmentPosition = (IOR_offset_t) 0; segmentPosition = (IOR_offset_t) 0;
segmentSize = param->blockSize; segmentSize = hints->blockSize;
} else { } else {
segmentPosition = segmentPosition =
(IOR_offset_t) ((rank + rankOffset) % param->numTasks) (IOR_offset_t) ((rank + rankOffset) % hints->numTasks)
* param->blockSize; * hints->blockSize;
segmentSize = segmentSize = (IOR_offset_t) (hints->numTasks) * hints->blockSize;
(IOR_offset_t) (param->numTasks) * param->blockSize;
} }
if ((IOR_offset_t) ((param->offset - segmentPosition) % segmentSize) == if ((IOR_offset_t) ((offset - segmentPosition) % segmentSize) ==
0) { 0) {
/* /*
* ordinarily start a new data set, unless this is the * ordinarily start a new data set, unless this is the
@ -427,7 +457,7 @@ static IOR_offset_t HDF5_Xfer(int access, void *fd, IOR_size_t * buffer,
} }
} }
if(param->dryRun) if(hints->dryRun)
return length; return length;
/* create new data set */ /* create new data set */
@ -438,10 +468,10 @@ static IOR_offset_t HDF5_Xfer(int access, void *fd, IOR_size_t * buffer,
HDF5_CHECK(H5Sclose(fileDataSpace), HDF5_CHECK(H5Sclose(fileDataSpace),
"cannot close file data space"); "cannot close file data space");
} }
SetupDataSet(fd, param); SetupDataSet(fd, access == WRITE ? IOR_CREAT : IOR_RDWR, param);
} }
SeekOffset(fd, param->offset, param); SeekOffset(fd, offset, param);
/* this is necessary to reset variables for reaccessing file */ /* this is necessary to reset variables for reaccessing file */
startNewDataSet = FALSE; startNewDataSet = FALSE;
@ -465,19 +495,18 @@ static IOR_offset_t HDF5_Xfer(int access, void *fd, IOR_size_t * buffer,
/* /*
* Perform fsync(). * Perform fsync().
*/ */
static void HDF5_Fsync(void *fd, IOR_param_t * param) static void HDF5_Fsync(aiori_fd_t *fd, aiori_mod_opt_t * param)
{ {
;
} }
/* /*
* Close a file through the HDF5 interface. * Close a file through the HDF5 interface.
*/ */
static void HDF5_Close(void *fd, IOR_param_t * param) static void HDF5_Close(aiori_fd_t *fd, aiori_mod_opt_t * param)
{ {
if(param->dryRun) if(hints->dryRun)
return; return;
if (param->fd_fppReadCheck == NULL) { //if (hints->fd_fppReadCheck == NULL) {
HDF5_CHECK(H5Dclose(dataSet), "cannot close data set"); HDF5_CHECK(H5Dclose(dataSet), "cannot close data set");
HDF5_CHECK(H5Sclose(dataSpace), "cannot close data space"); HDF5_CHECK(H5Sclose(dataSpace), "cannot close data space");
HDF5_CHECK(H5Sclose(fileDataSpace), HDF5_CHECK(H5Sclose(fileDataSpace),
@ -486,7 +515,7 @@ static void HDF5_Close(void *fd, IOR_param_t * param)
"cannot close memory data space"); "cannot close memory data space");
HDF5_CHECK(H5Pclose(xferPropList), HDF5_CHECK(H5Pclose(xferPropList),
" cannot close transfer property list"); " cannot close transfer property list");
} //}
HDF5_CHECK(H5Fclose(*(hid_t *) fd), "cannot close file"); HDF5_CHECK(H5Fclose(*(hid_t *) fd), "cannot close file");
free(fd); free(fd);
} }
@ -494,9 +523,9 @@ static void HDF5_Close(void *fd, IOR_param_t * param)
/* /*
* Delete a file through the HDF5 interface. * Delete a file through the HDF5 interface.
*/ */
static void HDF5_Delete(char *testFileName, IOR_param_t * param) static void HDF5_Delete(char *testFileName, aiori_mod_opt_t * param)
{ {
if(param->dryRun) if(hints->dryRun)
return return
MPIIO_Delete(testFileName, param); MPIIO_Delete(testFileName, param);
return; return;
@ -528,23 +557,24 @@ static char * HDF5_GetVersion()
* Seek to offset in file using the HDF5 interface and set up hyperslab. * Seek to offset in file using the HDF5 interface and set up hyperslab.
*/ */
static IOR_offset_t SeekOffset(void *fd, IOR_offset_t offset, static IOR_offset_t SeekOffset(void *fd, IOR_offset_t offset,
IOR_param_t * param) aiori_mod_opt_t * param)
{ {
HDF5_options_t *o = (HDF5_options_t*) param;
IOR_offset_t segmentSize; IOR_offset_t segmentSize;
hsize_t hsStride[NUM_DIMS], hsCount[NUM_DIMS], hsBlock[NUM_DIMS]; hsize_t hsStride[NUM_DIMS], hsCount[NUM_DIMS], hsBlock[NUM_DIMS];
hsize_t hsStart[NUM_DIMS]; hsize_t hsStart[NUM_DIMS];
if (param->filePerProc == TRUE) { if (hints->filePerProc == TRUE) {
segmentSize = (IOR_offset_t) param->blockSize; segmentSize = (IOR_offset_t) hints->blockSize;
} else { } else {
segmentSize = segmentSize =
(IOR_offset_t) (param->numTasks) * param->blockSize; (IOR_offset_t) (hints->numTasks) * hints->blockSize;
} }
/* create a hyperslab representing the file data space */ /* create a hyperslab representing the file data space */
if (param->individualDataSets) { if (o->individualDataSets) {
/* start at zero offset if not */ /* start at zero offset if not */
hsStart[0] = (hsize_t) ((offset % param->blockSize) hsStart[0] = (hsize_t) ((offset % hints->blockSize)
/ sizeof(IOR_size_t)); / sizeof(IOR_size_t));
} else { } else {
/* start at a unique offset if shared */ /* start at a unique offset if shared */
@ -552,8 +582,8 @@ static IOR_offset_t SeekOffset(void *fd, IOR_offset_t offset,
(hsize_t) ((offset % segmentSize) / sizeof(IOR_size_t)); (hsize_t) ((offset % segmentSize) / sizeof(IOR_size_t));
} }
hsCount[0] = (hsize_t) 1; hsCount[0] = (hsize_t) 1;
hsStride[0] = (hsize_t) (param->transferSize / sizeof(IOR_size_t)); hsStride[0] = (hsize_t) (hints->transferSize / sizeof(IOR_size_t));
hsBlock[0] = (hsize_t) (param->transferSize / sizeof(IOR_size_t)); hsBlock[0] = (hsize_t) (hints->transferSize / sizeof(IOR_size_t));
/* retrieve data space from data set for hyperslab */ /* retrieve data space from data set for hyperslab */
fileDataSpace = H5Dget_space(dataSet); fileDataSpace = H5Dget_space(dataSet);
@ -567,8 +597,9 @@ static IOR_offset_t SeekOffset(void *fd, IOR_offset_t offset,
/* /*
* Create HDF5 data set. * Create HDF5 data set.
*/ */
static void SetupDataSet(void *fd, IOR_param_t * param) static void SetupDataSet(void *fd, int flags, aiori_mod_opt_t * param)
{ {
HDF5_options_t *o = (HDF5_options_t*) param;
char dataSetName[MAX_STR]; char dataSetName[MAX_STR];
hid_t dataSetPropList; hid_t dataSetPropList;
int dataSetID; int dataSetID;
@ -582,8 +613,8 @@ static void SetupDataSet(void *fd, IOR_param_t * param)
dataSetSuffix = 0; dataSetSuffix = 0;
/* may want to use individual access to each data set someday */ /* may want to use individual access to each data set someday */
if (param->individualDataSets) { if (o->individualDataSets) {
dataSetID = (rank + rankOffset) % param->numTasks; dataSetID = (rank + rankOffset) % hints->numTasks;
} else { } else {
dataSetID = 0; dataSetID = 0;
} }
@ -591,14 +622,14 @@ static void SetupDataSet(void *fd, IOR_param_t * param)
sprintf(dataSetName, "%s-%04d.%04d", "Dataset", dataSetID, sprintf(dataSetName, "%s-%04d.%04d", "Dataset", dataSetID,
dataSetSuffix++); dataSetSuffix++);
if (param->open == WRITE) { /* WRITE */ if (flags & IOR_CREAT) { /* WRITE */
/* create data set */ /* create data set */
dataSetPropList = H5Pcreate(H5P_DATASET_CREATE); dataSetPropList = H5Pcreate(H5P_DATASET_CREATE);
/* check if hdf5 available */ /* check if hdf5 available */
#if defined (H5_VERS_MAJOR) && defined (H5_VERS_MINOR) #if defined (H5_VERS_MAJOR) && defined (H5_VERS_MINOR)
/* no-fill option not available until hdf5-1.6.x */ /* no-fill option not available until hdf5-1.6.x */
#if (H5_VERS_MAJOR > 0 && H5_VERS_MINOR > 5) #if (H5_VERS_MAJOR > 0 && H5_VERS_MINOR > 5)
if (param->noFill == TRUE) { if (o->noFill == TRUE) {
if (rank == 0 && verbose >= VERBOSE_1) { if (rank == 0 && verbose >= VERBOSE_1) {
fprintf(stdout, "\nusing 'no fill' option\n"); fprintf(stdout, "\nusing 'no fill' option\n");
} }
@ -629,9 +660,9 @@ static void SetupDataSet(void *fd, IOR_param_t * param)
* Use MPIIO call to get file size. * Use MPIIO call to get file size.
*/ */
static IOR_offset_t static IOR_offset_t
HDF5_GetFileSize(IOR_param_t * test, MPI_Comm testComm, char *testFileName) HDF5_GetFileSize(aiori_mod_opt_t * test, MPI_Comm testComm, char *testFileName)
{ {
if(test->dryRun) if(hints->dryRun)
return 0; return 0;
return(MPIIO_GetFileSize(test, testComm, testFileName)); return(MPIIO_GetFileSize(test, testComm, testFileName));
} }
@ -639,9 +670,9 @@ HDF5_GetFileSize(IOR_param_t * test, MPI_Comm testComm, char *testFileName)
/* /*
* Use MPIIO call to check for access. * Use MPIIO call to check for access.
*/ */
static int HDF5_Access(const char *path, int mode, IOR_param_t *param) static int HDF5_Access(const char *path, int mode, aiori_mod_opt_t *param)
{ {
if(param->dryRun) if(hints->dryRun)
return 0; return 0;
return(MPIIO_Access(path, mode, param)); return(MPIIO_Access(path, mode, param));
} }

View File

@ -51,6 +51,12 @@ static int IME_StatFS(const char *, ior_aiori_statfs_t *,
static int IME_RmDir(const char *, IOR_param_t *); static int IME_RmDir(const char *, IOR_param_t *);
static int IME_MkDir(const char *, mode_t, IOR_param_t *); static int IME_MkDir(const char *, mode_t, IOR_param_t *);
static int IME_Stat(const char *, struct stat *, IOR_param_t *); static int IME_Stat(const char *, struct stat *, IOR_param_t *);
#if (IME_NATIVE_API_VERSION >= 132)
static int IME_Mknod(char *);
static void IME_Sync(IOR_param_t *);
#endif
static void IME_Initialize(); static void IME_Initialize();
static void IME_Finalize(); static void IME_Finalize();
@ -107,6 +113,10 @@ ior_aiori_t ime_aiori = {
.initialize = IME_Initialize, .initialize = IME_Initialize,
.finalize = IME_Finalize, .finalize = IME_Finalize,
.get_options = IME_options, .get_options = IME_options,
#if (IME_NATIVE_API_VERSION >= 132)
.sync = IME_Sync,
.mknod = IME_Mknod,
#endif
.enable_mdtest = true, .enable_mdtest = true,
}; };
@ -406,3 +416,27 @@ static IOR_offset_t IME_GetFileSize(IOR_param_t *test, MPI_Comm testComm,
return(aggFileSizeFromStat); return(aggFileSizeFromStat);
} }
#if (IME_NATIVE_API_VERSION >= 132)
/*
* Create a file through mknod interface.
*/
static int IME_Mknod(char *testFileName)
{
int ret = ime_native_mknod(testFileName, S_IFREG | S_IRUSR, 0);
if (ret < 0)
ERR("mknod failed");
return ret;
}
/*
* Use IME sync to flush page cache of all opened files.
*/
static void IME_Sync(IOR_param_t * param)
{
int ret = ime_native_sync(0);
if (ret != 0)
FAIL("Error executing the sync command.");
}
#endif

View File

@ -26,14 +26,15 @@
#include "utilities.h" #include "utilities.h"
/**************************** P R O T O T Y P E S *****************************/ /**************************** P R O T O T Y P E S *****************************/
static void *MMAP_Create(char *, IOR_param_t *); static aiori_fd_t *MMAP_Create(char *, int flags, aiori_mod_opt_t *);
static void *MMAP_Open(char *, IOR_param_t *); static aiori_fd_t *MMAP_Open(char *, int flags, aiori_mod_opt_t *);
static IOR_offset_t MMAP_Xfer(int, void *, IOR_size_t *, static IOR_offset_t MMAP_Xfer(int, aiori_fd_t *, IOR_size_t *,
IOR_offset_t, IOR_param_t *); IOR_offset_t, IOR_offset_t, aiori_mod_opt_t *);
static void MMAP_Close(void *, IOR_param_t *); static void MMAP_Close(aiori_fd_t *, aiori_mod_opt_t *);
static void MMAP_Fsync(void *, IOR_param_t *); static void MMAP_Fsync(aiori_fd_t *, aiori_mod_opt_t *);
static option_help * MMAP_options(void ** init_backend_options, void * init_values); static option_help * MMAP_options(aiori_mod_opt_t ** init_backend_options, aiori_mod_opt_t * init_values);
static void MMAP_xfer_hints(aiori_xfer_hint_t * params);
static int MMAP_check_params(aiori_mod_opt_t * options);
/************************** D E C L A R A T I O N S ***************************/ /************************** D E C L A R A T I O N S ***************************/
ior_aiori_t mmap_aiori = { ior_aiori_t mmap_aiori = {
@ -43,10 +44,12 @@ ior_aiori_t mmap_aiori = {
.xfer = MMAP_Xfer, .xfer = MMAP_Xfer,
.close = MMAP_Close, .close = MMAP_Close,
.delete = POSIX_Delete, .delete = POSIX_Delete,
.xfer_hints = MMAP_xfer_hints,
.get_version = aiori_get_version, .get_version = aiori_get_version,
.fsync = MMAP_Fsync, .fsync = MMAP_Fsync,
.get_file_size = POSIX_GetFileSize, .get_file_size = POSIX_GetFileSize,
.get_options = MMAP_options, .get_options = MMAP_options,
.check_params = MMAP_check_params
}; };
/***************************** F U N C T I O N S ******************************/ /***************************** F U N C T I O N S ******************************/
@ -58,7 +61,7 @@ typedef struct{
int madv_pattern; int madv_pattern;
} mmap_options_t; } mmap_options_t;
static option_help * MMAP_options(void ** init_backend_options, void * init_values){ static option_help * MMAP_options(aiori_mod_opt_t ** init_backend_options, aiori_mod_opt_t * init_values){
mmap_options_t * o = malloc(sizeof(mmap_options_t)); mmap_options_t * o = malloc(sizeof(mmap_options_t));
if (init_values != NULL){ if (init_values != NULL){
@ -67,7 +70,7 @@ static option_help * MMAP_options(void ** init_backend_options, void * init_valu
memset(o, 0, sizeof(mmap_options_t)); memset(o, 0, sizeof(mmap_options_t));
} }
*init_backend_options = o; *init_backend_options = (aiori_mod_opt_t*) o;
option_help h [] = { option_help h [] = {
{0, "mmap.madv_dont_need", "Use advise don't need", OPTION_FLAG, 'd', & o->madv_dont_need}, {0, "mmap.madv_dont_need", "Use advise don't need", OPTION_FLAG, 'd', & o->madv_dont_need},
@ -79,25 +82,38 @@ static option_help * MMAP_options(void ** init_backend_options, void * init_valu
return help; return help;
} }
static void ior_mmap_file(int *file, IOR_param_t *param) static aiori_xfer_hint_t * hints = NULL;
static void MMAP_xfer_hints(aiori_xfer_hint_t * params){
hints = params;
aiori_posix_xfer_hints(params);
}
static int MMAP_check_params(aiori_mod_opt_t * options){
if (hints->fsyncPerWrite && (hints->transferSize & (sysconf(_SC_PAGESIZE) - 1)))
ERR("transfer size must be aligned with PAGESIZE for MMAP with fsyncPerWrite");
return 0;
}
static void ior_mmap_file(int *file, int mflags, void *param)
{ {
int flags = PROT_READ; int flags = PROT_READ;
IOR_offset_t size = param->expectedAggFileSize; IOR_offset_t size = hints->expectedAggFileSize;
if (param->open == WRITE) if (mflags & IOR_WRONLY || mflags & IOR_RDWR)
flags |= PROT_WRITE; flags |= PROT_WRITE;
mmap_options_t *o = (mmap_options_t*) param->backend_options; mmap_options_t *o = (mmap_options_t*) param;
o->mmap_ptr = mmap(NULL, size, flags, MAP_SHARED, o->mmap_ptr = mmap(NULL, size, flags, MAP_SHARED,
*file, 0); *file, 0);
if (o->mmap_ptr == MAP_FAILED) if (o->mmap_ptr == MAP_FAILED)
ERR("mmap() failed"); ERR("mmap() failed");
if (param->randomOffset) if (hints->randomOffset)
flags = POSIX_MADV_RANDOM; flags = POSIX_MADV_RANDOM;
else else
flags = POSIX_MADV_SEQUENTIAL; flags = POSIX_MADV_SEQUENTIAL;
if(o->madv_pattern){ if(o->madv_pattern){
if (posix_madvise(o->mmap_ptr, size, flags) != 0) if (posix_madvise(o->mmap_ptr, size, flags) != 0)
ERR("madvise() failed"); ERR("madvise() failed");
@ -114,46 +130,45 @@ static void ior_mmap_file(int *file, IOR_param_t *param)
/* /*
* Creat and open a file through the POSIX interface, then setup mmap. * Creat and open a file through the POSIX interface, then setup mmap.
*/ */
static void *MMAP_Create(char *testFileName, IOR_param_t * param) static aiori_fd_t *MMAP_Create(char *testFileName, int flags, aiori_mod_opt_t * param)
{ {
int *fd; int *fd;
fd = POSIX_Create(testFileName, param); fd = (int*) POSIX_Create(testFileName, flags, param);
if (ftruncate(*fd, param->expectedAggFileSize) != 0) if (ftruncate(*fd, hints->expectedAggFileSize) != 0)
ERR("ftruncate() failed"); ERR("ftruncate() failed");
ior_mmap_file(fd, param); ior_mmap_file(fd, flags, param);
return ((void *)fd); return ((aiori_fd_t *)fd);
} }
/* /*
* Open a file through the POSIX interface and setup mmap. * Open a file through the POSIX interface and setup mmap.
*/ */
static void *MMAP_Open(char *testFileName, IOR_param_t * param) static aiori_fd_t *MMAP_Open(char *testFileName, int flags, aiori_mod_opt_t * param)
{ {
int *fd; int *fd;
fd = (int*) POSIX_Open(testFileName, flags, param);
fd = POSIX_Open(testFileName, param); ior_mmap_file(fd, flags, param);
ior_mmap_file(fd, param); return ((aiori_fd_t *)fd);
return ((void *)fd);
} }
/* /*
* Write or read access to file using mmap * Write or read access to file using mmap
*/ */
static IOR_offset_t MMAP_Xfer(int access, void *file, IOR_size_t * buffer, static IOR_offset_t MMAP_Xfer(int access, aiori_fd_t *file, IOR_size_t * buffer,
IOR_offset_t length, IOR_param_t * param) IOR_offset_t length, IOR_offset_t offset, aiori_mod_opt_t * param)
{ {
mmap_options_t *o = (mmap_options_t*) param->backend_options; mmap_options_t *o = (mmap_options_t*) param;
if (access == WRITE) { if (access == WRITE) {
memcpy(o->mmap_ptr + param->offset, buffer, length); memcpy(o->mmap_ptr + offset, buffer, length);
} else { } else {
memcpy(buffer, o->mmap_ptr + param->offset, length); memcpy(buffer, o->mmap_ptr + offset, length);
} }
if (param->fsyncPerWrite == TRUE) { if (hints->fsyncPerWrite == TRUE) {
if (msync(o->mmap_ptr + param->offset, length, MS_SYNC) != 0) if (msync(o->mmap_ptr + offset, length, MS_SYNC) != 0)
ERR("msync() failed"); ERR("msync() failed");
if (posix_madvise(o->mmap_ptr + param->offset, length, if (posix_madvise(o->mmap_ptr + offset, length,
POSIX_MADV_DONTNEED) != 0) POSIX_MADV_DONTNEED) != 0)
ERR("madvise() failed"); ERR("madvise() failed");
} }
@ -163,20 +178,20 @@ static IOR_offset_t MMAP_Xfer(int access, void *file, IOR_size_t * buffer,
/* /*
* Perform msync(). * Perform msync().
*/ */
static void MMAP_Fsync(void *fd, IOR_param_t * param) static void MMAP_Fsync(aiori_fd_t *fd, aiori_mod_opt_t * param)
{ {
mmap_options_t *o = (mmap_options_t*) param->backend_options; mmap_options_t *o = (mmap_options_t*) param;
if (msync(o->mmap_ptr, param->expectedAggFileSize, MS_SYNC) != 0) if (msync(o->mmap_ptr, hints->expectedAggFileSize, MS_SYNC) != 0)
EWARN("msync() failed"); EWARN("msync() failed");
} }
/* /*
* Close a file through the POSIX interface, after tear down the mmap. * Close a file through the POSIX interface, after tear down the mmap.
*/ */
static void MMAP_Close(void *fd, IOR_param_t * param) static void MMAP_Close(aiori_fd_t *fd, aiori_mod_opt_t * param)
{ {
mmap_options_t *o = (mmap_options_t*) param->backend_options; mmap_options_t *o = (mmap_options_t*) param;
if (munmap(o->mmap_ptr, param->expectedAggFileSize) != 0) if (munmap(o->mmap_ptr, hints->expectedAggFileSize) != 0)
ERR("munmap failed"); ERR("munmap failed");
o->mmap_ptr = NULL; o->mmap_ptr = NULL;
POSIX_Close(fd, param); POSIX_Close(fd, param);

View File

@ -31,23 +31,65 @@
/**************************** P R O T O T Y P E S *****************************/ /**************************** P R O T O T Y P E S *****************************/
static IOR_offset_t SeekOffset(MPI_File, IOR_offset_t, IOR_param_t *); static IOR_offset_t SeekOffset(MPI_File, IOR_offset_t, aiori_mod_opt_t *);
static void *MPIIO_Create(char *, IOR_param_t *); static aiori_fd_t *MPIIO_Create(char *, int iorflags, aiori_mod_opt_t *);
static void *MPIIO_Open(char *, IOR_param_t *); static aiori_fd_t *MPIIO_Open(char *, int flags, aiori_mod_opt_t *);
static IOR_offset_t MPIIO_Xfer(int, void *, IOR_size_t *, static IOR_offset_t MPIIO_Xfer(int, aiori_fd_t *, IOR_size_t *,
IOR_offset_t, IOR_param_t *); IOR_offset_t, IOR_offset_t, aiori_mod_opt_t *);
static void MPIIO_Close(void *, IOR_param_t *); static void MPIIO_Close(aiori_fd_t *, aiori_mod_opt_t *);
static char* MPIIO_GetVersion(); static char* MPIIO_GetVersion();
static void MPIIO_Fsync(void *, IOR_param_t *); static void MPIIO_Fsync(aiori_fd_t *, aiori_mod_opt_t *);
static void MPIIO_xfer_hints(aiori_xfer_hint_t * params);
static int MPIIO_check_params(aiori_mod_opt_t * options);
/************************** D E C L A R A T I O N S ***************************/ /************************** D E C L A R A T I O N S ***************************/
typedef struct{
MPI_File fd;
MPI_Datatype transferType; /* datatype for transfer */
MPI_Datatype fileType; /* filetype for file view */
} mpiio_fd_t;
typedef struct {
int showHints; /* show hints */
int useFileView; /* use MPI_File_set_view */
int preallocate; /* preallocate file size */
int useSharedFilePointer; /* use shared file pointer */
int useStridedDatatype; /* put strided access into datatype */
char * hintsFileName; /* full name for hints file */
} mpiio_options_t;
static option_help * MPIIO_options(aiori_mod_opt_t ** init_backend_options, aiori_mod_opt_t * init_values){
mpiio_options_t * o = malloc(sizeof(mpiio_options_t));
if (init_values != NULL){
memcpy(o, init_values, sizeof(mpiio_options_t));
}else{
memset(o, 0, sizeof(mpiio_options_t));
}
*init_backend_options = (aiori_mod_opt_t*) o;
option_help h [] = {
{0, "mpiio.hintsFileName","Full name for hints file", OPTION_OPTIONAL_ARGUMENT, 's', & o->hintsFileName},
{0, "mpiio.showHints", "Show MPI hints", OPTION_FLAG, 'd', & o->showHints},
{0, "mpiio.preallocate", "Preallocate file size", OPTION_FLAG, 'd', & o->preallocate},
{0, "mpiio.useStridedDatatype", "put strided access into datatype [not working]", OPTION_FLAG, 'd', & o->useStridedDatatype},
//{'P', NULL, "useSharedFilePointer -- use shared file pointer [not working]", OPTION_FLAG, 'd', & params->useSharedFilePointer},
{0, "mpiio.useFileView", "Use MPI_File_set_view", OPTION_FLAG, 'd', & o->useFileView},
LAST_OPTION
};
option_help * help = malloc(sizeof(h));
memcpy(help, h, sizeof(h));
return help;
}
ior_aiori_t mpiio_aiori = { ior_aiori_t mpiio_aiori = {
.name = "MPIIO", .name = "MPIIO",
.name_legacy = NULL, .name_legacy = NULL,
.create = MPIIO_Create, .create = MPIIO_Create,
.get_options = MPIIO_options,
.xfer_hints = MPIIO_xfer_hints,
.open = MPIIO_Open, .open = MPIIO_Open,
.xfer = MPIIO_Xfer, .xfer = MPIIO_Xfer,
.close = MPIIO_Close, .close = MPIIO_Close,
@ -60,16 +102,46 @@ ior_aiori_t mpiio_aiori = {
.rmdir = aiori_posix_rmdir, .rmdir = aiori_posix_rmdir,
.access = MPIIO_Access, .access = MPIIO_Access,
.stat = aiori_posix_stat, .stat = aiori_posix_stat,
.check_params = MPIIO_check_params
}; };
/***************************** F U N C T I O N S ******************************/ /***************************** F U N C T I O N S ******************************/
static aiori_xfer_hint_t * hints = NULL;
static void MPIIO_xfer_hints(aiori_xfer_hint_t * params){
hints = params;
}
static int MPIIO_check_params(aiori_mod_opt_t * module_options){
mpiio_options_t * param = (mpiio_options_t*) module_options;
if ((param->useFileView == TRUE)
&& (sizeof(MPI_Aint) < 8) /* used for 64-bit datatypes */
&&((hints->numTasks * hints->blockSize) >
(2 * (IOR_offset_t) GIBIBYTE)))
ERR("segment size must be < 2GiB");
if (param->useSharedFilePointer)
ERR("shared file pointer not implemented");
if (param->useStridedDatatype)
ERR("strided datatype not implemented");
if (param->useStridedDatatype && (hints->blockSize < sizeof(IOR_size_t)
|| hints->transferSize <
sizeof(IOR_size_t)))
ERR("need larger file size for strided datatype in MPIIO");
if (hints->randomOffset && hints->collective)
ERR("random offset not available with collective MPIIO");
if (hints->randomOffset && param->useFileView)
ERR("random offset not available with MPIIO fileviews");
return 0;
}
/* /*
* Try to access a file through the MPIIO interface. * Try to access a file through the MPIIO interface.
*/ */
int MPIIO_Access(const char *path, int mode, IOR_param_t *param) int MPIIO_Access(const char *path, int mode, aiori_mod_opt_t *module_options)
{ {
if(param->dryRun){ mpiio_options_t * param = (mpiio_options_t*) module_options;
if(hints->dryRun){
return MPI_SUCCESS; return MPI_SUCCESS;
} }
MPI_File fd; MPI_File fd;
@ -98,60 +170,51 @@ int MPIIO_Access(const char *path, int mode, IOR_param_t *param)
/* /*
* Create and open a file through the MPIIO interface. * Create and open a file through the MPIIO interface.
*/ */
static void *MPIIO_Create(char *testFileName, IOR_param_t * param) static aiori_fd_t *MPIIO_Create(char *testFileName, int iorflags, aiori_mod_opt_t * module_options)
{ {
if(param->dryRun){ return MPIIO_Open(testFileName, iorflags, module_options);
return 0;
}
return MPIIO_Open(testFileName, param);
} }
/* /*
* Open a file through the MPIIO interface. Setup file view. * Open a file through the MPIIO interface. Setup file view.
*/ */
static void *MPIIO_Open(char *testFileName, IOR_param_t * param) static aiori_fd_t *MPIIO_Open(char *testFileName, int flags, aiori_mod_opt_t * module_options)
{ {
mpiio_options_t * param = (mpiio_options_t*) module_options;
int fd_mode = (int)0, int fd_mode = (int)0,
offsetFactor, offsetFactor,
tasksPerFile, tasksPerFile,
transfersPerBlock = param->blockSize / param->transferSize; transfersPerBlock = hints->blockSize / hints->transferSize;
struct fileTypeStruct { struct fileTypeStruct {
int globalSizes[2], localSizes[2], startIndices[2]; int globalSizes[2], localSizes[2], startIndices[2];
} fileTypeStruct; } fileTypeStruct;
MPI_File *fd;
mpiio_fd_t * mfd = malloc(sizeof(mpiio_fd_t));
memset(mfd, 0, sizeof(mpiio_fd_t));
MPI_Comm comm; MPI_Comm comm;
MPI_Info mpiHints = MPI_INFO_NULL; MPI_Info mpiHints = MPI_INFO_NULL;
fd = (MPI_File *) malloc(sizeof(MPI_File));
if (fd == NULL)
ERR("malloc failed()");
*fd = 0;
/* set IOR file flags to MPIIO flags */ /* set IOR file flags to MPIIO flags */
/* -- file open flags -- */ /* -- file open flags -- */
if (param->openFlags & IOR_RDONLY) { if (flags & IOR_RDONLY) {
fd_mode |= MPI_MODE_RDONLY; fd_mode |= MPI_MODE_RDONLY;
} }
if (param->openFlags & IOR_WRONLY) { if (flags & IOR_WRONLY) {
fd_mode |= MPI_MODE_WRONLY; fd_mode |= MPI_MODE_WRONLY;
} }
if (param->openFlags & IOR_RDWR) { if (flags & IOR_RDWR) {
fd_mode |= MPI_MODE_RDWR; fd_mode |= MPI_MODE_RDWR;
} }
if (param->openFlags & IOR_APPEND) { if (flags & IOR_APPEND) {
fd_mode |= MPI_MODE_APPEND; fd_mode |= MPI_MODE_APPEND;
} }
if (param->openFlags & IOR_CREAT) { if (flags & IOR_CREAT) {
fd_mode |= MPI_MODE_CREATE; fd_mode |= MPI_MODE_CREATE;
} }
if (param->openFlags & IOR_EXCL) { if (flags & IOR_EXCL) {
fd_mode |= MPI_MODE_EXCL; fd_mode |= MPI_MODE_EXCL;
} }
if (param->openFlags & IOR_TRUNC) { if (flags & IOR_DIRECT) {
fprintf(stdout, "File truncation not implemented in MPIIO\n");
}
if (param->openFlags & IOR_DIRECT) {
fprintf(stdout, "O_DIRECT not implemented in MPIIO\n"); fprintf(stdout, "O_DIRECT not implemented in MPIIO\n");
} }
@ -162,7 +225,7 @@ static void *MPIIO_Open(char *testFileName, IOR_param_t * param)
*/ */
fd_mode |= MPI_MODE_UNIQUE_OPEN; fd_mode |= MPI_MODE_UNIQUE_OPEN;
if (param->filePerProc) { if (hints->filePerProc) {
comm = MPI_COMM_SELF; comm = MPI_COMM_SELF;
} else { } else {
comm = testComm; comm = testComm;
@ -181,16 +244,19 @@ static void *MPIIO_Open(char *testFileName, IOR_param_t * param)
ShowHints(&mpiHints); ShowHints(&mpiHints);
fprintf(stdout, "}\n"); fprintf(stdout, "}\n");
} }
if(! param->dryRun){ if(! hints->dryRun){
MPI_CHECKF(MPI_File_open(comm, testFileName, fd_mode, mpiHints, fd), MPI_CHECKF(MPI_File_open(comm, testFileName, fd_mode, mpiHints, & mfd->fd),
"cannot open file: %s", testFileName); "cannot open file: %s", testFileName);
if (flags & IOR_TRUNC) {
MPI_CHECKF(MPI_File_set_size(mfd->fd, 0), "cannot truncate file: %s", testFileName);
}
} }
/* show hints actually attached to file handle */ /* show hints actually attached to file handle */
if (rank == 0 && param->showHints && ! param->dryRun) { if (rank == 0 && param->showHints && ! hints->dryRun) {
if (mpiHints != MPI_INFO_NULL) if (mpiHints != MPI_INFO_NULL)
MPI_CHECK(MPI_Info_free(&mpiHints), "MPI_Info_free failed"); MPI_CHECK(MPI_Info_free(&mpiHints), "MPI_Info_free failed");
MPI_CHECK(MPI_File_get_info(*fd, &mpiHints), MPI_CHECK(MPI_File_get_info(mfd->fd, &mpiHints),
"cannot get file info"); "cannot get file info");
fprintf(stdout, "\nhints returned from opened file {\n"); fprintf(stdout, "\nhints returned from opened file {\n");
ShowHints(&mpiHints); ShowHints(&mpiHints);
@ -198,29 +264,29 @@ static void *MPIIO_Open(char *testFileName, IOR_param_t * param)
} }
/* preallocate space for file */ /* preallocate space for file */
if (param->preallocate && param->open == WRITE && ! param->dryRun) { if (param->preallocate && flags & IOR_CREAT && ! hints->dryRun) {
MPI_CHECK(MPI_File_preallocate(*fd, MPI_CHECK(MPI_File_preallocate(mfd->fd,
(MPI_Offset) (param->segmentCount (MPI_Offset) (hints->segmentCount
* *
param->blockSize * hints->blockSize *
param->numTasks)), hints->numTasks)),
"cannot preallocate file"); "cannot preallocate file");
} }
/* create file view */ /* create file view */
if (param->useFileView) { if (param->useFileView) {
/* create contiguous transfer datatype */ /* create contiguous transfer datatype */
MPI_CHECK(MPI_Type_contiguous MPI_CHECK(MPI_Type_contiguous
(param->transferSize / sizeof(IOR_size_t), (hints->transferSize / sizeof(IOR_size_t),
MPI_LONG_LONG_INT, &param->transferType), MPI_LONG_LONG_INT, & mfd->transferType),
"cannot create contiguous datatype"); "cannot create contiguous datatype");
MPI_CHECK(MPI_Type_commit(&param->transferType), MPI_CHECK(MPI_Type_commit(& mfd->transferType),
"cannot commit datatype"); "cannot commit datatype");
if (param->filePerProc) { if (hints->filePerProc) {
offsetFactor = 0; offsetFactor = 0;
tasksPerFile = 1; tasksPerFile = 1;
} else { } else {
offsetFactor = (rank + rankOffset) % param->numTasks; offsetFactor = (rank + rankOffset) % hints->numTasks;
tasksPerFile = param->numTasks; tasksPerFile = hints->numTasks;
} }
/* /*
@ -239,37 +305,38 @@ static void *MPIIO_Open(char *testFileName, IOR_param_t * param)
(2, fileTypeStruct.globalSizes, (2, fileTypeStruct.globalSizes,
fileTypeStruct.localSizes, fileTypeStruct.localSizes,
fileTypeStruct.startIndices, MPI_ORDER_C, fileTypeStruct.startIndices, MPI_ORDER_C,
param->transferType, &param->fileType), mfd->transferType, & mfd->fileType),
"cannot create subarray"); "cannot create subarray");
MPI_CHECK(MPI_Type_commit(&param->fileType), MPI_CHECK(MPI_Type_commit(& mfd->fileType),
"cannot commit datatype"); "cannot commit datatype");
if(! param->dryRun){ if(! hints->dryRun){
MPI_CHECK(MPI_File_set_view(*fd, (MPI_Offset) 0, MPI_CHECK(MPI_File_set_view(mfd->fd, (MPI_Offset) 0,
param->transferType, mfd->transferType,
param->fileType, "native", mfd->fileType, "native",
(MPI_Info) MPI_INFO_NULL), (MPI_Info) MPI_INFO_NULL),
"cannot set file view"); "cannot set file view");
} }
} }
if (mpiHints != MPI_INFO_NULL) if (mpiHints != MPI_INFO_NULL)
MPI_CHECK(MPI_Info_free(&mpiHints), "MPI_Info_free failed"); MPI_CHECK(MPI_Info_free(&mpiHints), "MPI_Info_free failed");
return ((void *)fd); return ((void *) mfd);
} }
/* /*
* Write or read access to file using the MPIIO interface. * Write or read access to file using the MPIIO interface.
*/ */
static IOR_offset_t MPIIO_Xfer(int access, void *fd, IOR_size_t * buffer, static IOR_offset_t MPIIO_Xfer(int access, aiori_fd_t * fdp, IOR_size_t * buffer,
IOR_offset_t length, IOR_param_t * param) IOR_offset_t length, IOR_offset_t offset, aiori_mod_opt_t * module_options)
{ {
/* NOTE: The second arg is (void *) for reads, and (const void *) /* NOTE: The second arg is (void *) for reads, and (const void *)
for writes. Therefore, one of the two sets of assignments below for writes. Therefore, one of the two sets of assignments below
will get "assignment from incompatible pointer-type" warnings, will get "assignment from incompatible pointer-type" warnings,
if we only use this one set of signatures. */ if we only use this one set of signatures. */
mpiio_options_t * param = (mpiio_options_t*) module_options;
if(param->dryRun) if(hints->dryRun)
return length; return length;
mpiio_fd_t * mfd = (mpiio_fd_t*) fdp;
int (MPIAPI * Access) (MPI_File, void *, int, int (MPIAPI * Access) (MPI_File, void *, int,
MPI_Datatype, MPI_Status *); MPI_Datatype, MPI_Status *);
@ -319,7 +386,7 @@ static IOR_offset_t MPIIO_Xfer(int access, void *fd, IOR_size_t * buffer,
*/ */
if (param->useFileView) { if (param->useFileView) {
/* find offset in file */ /* find offset in file */
if (SeekOffset(*(MPI_File *) fd, param->offset, param) < if (SeekOffset(mfd->fd, offset, module_options) <
0) { 0) {
/* if unsuccessful */ /* if unsuccessful */
length = -1; length = -1;
@ -331,24 +398,24 @@ static IOR_offset_t MPIIO_Xfer(int access, void *fd, IOR_size_t * buffer,
* e.g., 'IOR -s 2 -b 32K -t 32K -a MPIIO -S' * e.g., 'IOR -s 2 -b 32K -t 32K -a MPIIO -S'
*/ */
if (param->useStridedDatatype) { if (param->useStridedDatatype) {
length = param->segmentCount; length = hints->segmentCount;
} else { } else {
length = 1; length = 1;
} }
if (param->collective) { if (hints->collective) {
/* individual, collective call */ /* individual, collective call */
MPI_CHECK(Access_all MPI_CHECK(Access_all
(*(MPI_File *) fd, buffer, length, (mfd->fd, buffer, length,
param->transferType, &status), mfd->transferType, &status),
"cannot access collective"); "cannot access collective");
} else { } else {
/* individual, noncollective call */ /* individual, noncollective call */
MPI_CHECK(Access MPI_CHECK(Access
(*(MPI_File *) fd, buffer, length, (mfd->fd, buffer, length,
param->transferType, &status), mfd->transferType, &status),
"cannot access noncollective"); "cannot access noncollective");
} }
length *= param->transferSize; /* for return value in bytes */ length *= hints->transferSize; /* for return value in bytes */
} }
} else { } else {
/* /*
@ -358,7 +425,7 @@ static IOR_offset_t MPIIO_Xfer(int access, void *fd, IOR_size_t * buffer,
if (param->useSharedFilePointer) { if (param->useSharedFilePointer) {
/* find offset in file */ /* find offset in file */
if (SeekOffset if (SeekOffset
(*(MPI_File *) fd, param->offset, param) < 0) { (mfd->fd, offset, module_options) < 0) {
/* if unsuccessful */ /* if unsuccessful */
length = -1; length = -1;
} else { } else {
@ -374,63 +441,64 @@ static IOR_offset_t MPIIO_Xfer(int access, void *fd, IOR_size_t * buffer,
"useSharedFilePointer not implemented\n"); "useSharedFilePointer not implemented\n");
} }
} else { } else {
if (param->collective) { if (hints->collective) {
/* explicit, collective call */ /* explicit, collective call */
MPI_CHECK(Access_at_all MPI_CHECK(Access_at_all
(*(MPI_File *) fd, param->offset, (mfd->fd, offset,
buffer, length, MPI_BYTE, &status), buffer, length, MPI_BYTE, &status),
"cannot access explicit, collective"); "cannot access explicit, collective");
} else { } else {
/* explicit, noncollective call */ /* explicit, noncollective call */
MPI_CHECK(Access_at MPI_CHECK(Access_at
(*(MPI_File *) fd, param->offset, (mfd->fd, offset,
buffer, length, MPI_BYTE, &status), buffer, length, MPI_BYTE, &status),
"cannot access explicit, noncollective"); "cannot access explicit, noncollective");
} }
} }
} }
if((access == WRITE) && (param->fsyncPerWrite == TRUE))
MPIIO_Fsync(fd, param);
return (length); return (length);
} }
/* /*
* Perform fsync(). * Perform fsync().
*/ */
static void MPIIO_Fsync(void *fdp, IOR_param_t * param) static void MPIIO_Fsync(aiori_fd_t *fdp, aiori_mod_opt_t * module_options)
{ {
if(param->dryRun) mpiio_options_t * param = (mpiio_options_t*) module_options;
if(hints->dryRun)
return; return;
if (MPI_File_sync(*(MPI_File *)fdp) != MPI_SUCCESS) mpiio_fd_t * mfd = (mpiio_fd_t*) fdp;
if (MPI_File_sync(mfd->fd) != MPI_SUCCESS)
EWARN("fsync() failed"); EWARN("fsync() failed");
} }
/* /*
* Close a file through the MPIIO interface. * Close a file through the MPIIO interface.
*/ */
static void MPIIO_Close(void *fd, IOR_param_t * param) static void MPIIO_Close(aiori_fd_t *fdp, aiori_mod_opt_t * module_options)
{ {
if(! param->dryRun){ mpiio_options_t * param = (mpiio_options_t*) module_options;
MPI_CHECK(MPI_File_close((MPI_File *) fd), "cannot close file"); mpiio_fd_t * mfd = (mpiio_fd_t*) fdp;
if(! hints->dryRun){
MPI_CHECK(MPI_File_close(& mfd->fd), "cannot close file");
} }
if ((param->useFileView == TRUE) && (param->fd_fppReadCheck == NULL)) { if (param->useFileView == TRUE) {
/* /*
* need to free the datatype, so done in the close process * need to free the datatype, so done in the close process
*/ */
MPI_CHECK(MPI_Type_free(&param->fileType), MPI_CHECK(MPI_Type_free(& mfd->fileType), "cannot free MPI file datatype");
"cannot free MPI file datatype"); MPI_CHECK(MPI_Type_free(& mfd->transferType), "cannot free MPI transfer datatype");
MPI_CHECK(MPI_Type_free(&param->transferType),
"cannot free MPI transfer datatype");
} }
free(fd); free(fdp);
} }
/* /*
* Delete a file through the MPIIO interface. * Delete a file through the MPIIO interface.
*/ */
void MPIIO_Delete(char *testFileName, IOR_param_t * param) void MPIIO_Delete(char *testFileName, aiori_mod_opt_t * module_options)
{ {
if(param->dryRun) mpiio_options_t * param = (mpiio_options_t*) module_options;
if(hints->dryRun)
return; return;
MPI_CHECKF(MPI_File_delete(testFileName, (MPI_Info) MPI_INFO_NULL), MPI_CHECKF(MPI_File_delete(testFileName, (MPI_Info) MPI_INFO_NULL),
"cannot delete file: %s", testFileName); "cannot delete file: %s", testFileName);
@ -452,36 +520,37 @@ static char* MPIIO_GetVersion()
* Seek to offset in file using the MPIIO interface. * Seek to offset in file using the MPIIO interface.
*/ */
static IOR_offset_t SeekOffset(MPI_File fd, IOR_offset_t offset, static IOR_offset_t SeekOffset(MPI_File fd, IOR_offset_t offset,
IOR_param_t * param) aiori_mod_opt_t * module_options)
{ {
mpiio_options_t * param = (mpiio_options_t*) module_options;
int offsetFactor, tasksPerFile; int offsetFactor, tasksPerFile;
IOR_offset_t tempOffset; IOR_offset_t tempOffset;
tempOffset = offset; tempOffset = offset;
if (param->filePerProc) { if (hints->filePerProc) {
offsetFactor = 0; offsetFactor = 0;
tasksPerFile = 1; tasksPerFile = 1;
} else { } else {
offsetFactor = (rank + rankOffset) % param->numTasks; offsetFactor = (rank + rankOffset) % hints->numTasks;
tasksPerFile = param->numTasks; tasksPerFile = hints->numTasks;
} }
if (param->useFileView) { if (param->useFileView) {
/* recall that offsets in a file view are /* recall that offsets in a file view are
counted in units of transfer size */ counted in units of transfer size */
if (param->filePerProc) { if (hints->filePerProc) {
tempOffset = tempOffset / param->transferSize; tempOffset = tempOffset / hints->transferSize;
} else { } else {
/* /*
* this formula finds a file view offset for a task * this formula finds a file view offset for a task
* from an absolute offset * from an absolute offset
*/ */
tempOffset = ((param->blockSize / param->transferSize) tempOffset = ((hints->blockSize / hints->transferSize)
* (tempOffset / * (tempOffset /
(param->blockSize * tasksPerFile))) (hints->blockSize * tasksPerFile)))
+ (((tempOffset % (param->blockSize * tasksPerFile)) + (((tempOffset % (hints->blockSize * tasksPerFile))
- (offsetFactor * param->blockSize)) - (offsetFactor * hints->blockSize))
/ param->transferSize); / hints->transferSize);
} }
} }
MPI_CHECK(MPI_File_seek(fd, tempOffset, MPI_SEEK_SET), MPI_CHECK(MPI_File_seek(fd, tempOffset, MPI_SEEK_SET),
@ -493,17 +562,18 @@ static IOR_offset_t SeekOffset(MPI_File fd, IOR_offset_t offset,
* Use MPI_File_get_size() to return aggregate file size. * Use MPI_File_get_size() to return aggregate file size.
* NOTE: This function is used by the HDF5 and NCMPI backends. * NOTE: This function is used by the HDF5 and NCMPI backends.
*/ */
IOR_offset_t MPIIO_GetFileSize(IOR_param_t * test, MPI_Comm testComm, IOR_offset_t MPIIO_GetFileSize(aiori_mod_opt_t * module_options, MPI_Comm testComm,
char *testFileName) char *testFileName)
{ {
if(test->dryRun) mpiio_options_t * test = (mpiio_options_t*) module_options;
if(hints->dryRun)
return 0; return 0;
IOR_offset_t aggFileSizeFromStat, tmpMin, tmpMax, tmpSum; IOR_offset_t aggFileSizeFromStat, tmpMin, tmpMax, tmpSum;
MPI_File fd; MPI_File fd;
MPI_Comm comm; MPI_Comm comm;
MPI_Info mpiHints = MPI_INFO_NULL; MPI_Info mpiHints = MPI_INFO_NULL;
if (test->filePerProc == TRUE) { if (hints->filePerProc == TRUE) {
comm = MPI_COMM_SELF; comm = MPI_COMM_SELF;
} else { } else {
comm = testComm; comm = testComm;
@ -519,7 +589,7 @@ IOR_offset_t MPIIO_GetFileSize(IOR_param_t * test, MPI_Comm testComm,
if (mpiHints != MPI_INFO_NULL) if (mpiHints != MPI_INFO_NULL)
MPI_CHECK(MPI_Info_free(&mpiHints), "MPI_Info_free failed"); MPI_CHECK(MPI_Info_free(&mpiHints), "MPI_Info_free failed");
if (test->filePerProc == TRUE) { if (hints->filePerProc == TRUE) {
MPI_CHECK(MPI_Allreduce(&aggFileSizeFromStat, &tmpSum, 1, MPI_CHECK(MPI_Allreduce(&aggFileSizeFromStat, &tmpSum, 1,
MPI_LONG_LONG_INT, MPI_SUM, testComm), MPI_LONG_LONG_INT, MPI_SUM, testComm),
"cannot total data moved"); "cannot total data moved");

View File

@ -68,31 +68,67 @@
#endif #endif
/**************************** P R O T O T Y P E S *****************************/ /**************************** P R O T O T Y P E S *****************************/
static IOR_offset_t POSIX_Xfer(int, void *, IOR_size_t *, static IOR_offset_t POSIX_Xfer(int, aiori_fd_t *, IOR_size_t *,
IOR_offset_t, IOR_param_t *); IOR_offset_t, IOR_offset_t, aiori_mod_opt_t *);
static void POSIX_Fsync(void *, IOR_param_t *); static void POSIX_Fsync(aiori_fd_t *, aiori_mod_opt_t *);
static void POSIX_Sync(IOR_param_t * ); static void POSIX_Sync(aiori_mod_opt_t * );
static int POSIX_check_params(aiori_mod_opt_t * options);
/************************** O P T I O N S *****************************/ /************************** O P T I O N S *****************************/
typedef struct{ typedef struct{
/* in case of a change, please update depending MMAP module too */ /* in case of a change, please update depending MMAP module too */
int direct_io; int direct_io;
/* Lustre variables */
int lustre_set_striping; /* flag that we need to set lustre striping */
int lustre_stripe_count;
int lustre_stripe_size;
int lustre_start_ost;
int lustre_ignore_locks;
/* gpfs variables */
int gpfs_hint_access; /* use gpfs "access range" hint */
int gpfs_release_token; /* immediately release GPFS tokens after
creating or opening a file */
/* beegfs variables */
int beegfs_numTargets; /* number storage targets to use */
int beegfs_chunkSize; /* srtipe pattern for new files */
} posix_options_t; } posix_options_t;
option_help * POSIX_options(void ** init_backend_options, void * init_values){ option_help * POSIX_options(aiori_mod_opt_t ** init_backend_options, aiori_mod_opt_t * init_values){
posix_options_t * o = malloc(sizeof(posix_options_t)); posix_options_t * o = malloc(sizeof(posix_options_t));
if (init_values != NULL){ if (init_values != NULL){
memcpy(o, init_values, sizeof(posix_options_t)); memcpy(o, init_values, sizeof(posix_options_t));
}else{ }else{
memset(o, 0, sizeof(posix_options_t));
o->direct_io = 0; o->direct_io = 0;
o->lustre_start_ost = -1;
o->beegfs_numTargets = -1;
o->beegfs_chunkSize = -1;
} }
*init_backend_options = o; *init_backend_options = (aiori_mod_opt_t*) o;
option_help h [] = { option_help h [] = {
{0, "posix.odirect", "Direct I/O Mode", OPTION_FLAG, 'd', & o->direct_io}, {0, "posix.odirect", "Direct I/O Mode", OPTION_FLAG, 'd', & o->direct_io},
#ifdef HAVE_BEEGFS_BEEGFS_H
{0, "posix.beegfs.NumTargets", "", OPTION_OPTIONAL_ARGUMENT, 'd', & o->beegfs_numTargets},
{0, "posix.beegfs.ChunkSize", "", OPTION_OPTIONAL_ARGUMENT, 'd', & o->beegfs_chunkSize},
#endif
#ifdef HAVE_GPFS_FCNTL_H
{0, "posix.gpfs.hintaccess", "", OPTION_FLAG, 'd', & o->gpfs_hint_access},
{0, "posix.gpfs.releasetoken", "", OPTION_OPTIONAL_ARGUMENT, 'd', & o->gpfs_release_token},
#endif
#ifdef HAVE_LUSTRE_LUSTRE_USER_H
{0, "posix.lustre.stripecount", "", OPTION_OPTIONAL_ARGUMENT, 'd', & o->lustre_stripe_count},
{0, "posix.lustre.stripesize", "", OPTION_OPTIONAL_ARGUMENT, 'd', & o->lustre_stripe_size},
{0, "posix.lustre.startost", "", OPTION_OPTIONAL_ARGUMENT, 'd', & o->lustre_start_ost},
{0, "posix.lustre.ignorelocks", "", OPTION_FLAG, 'd', & o->lustre_ignore_locks},
#endif
LAST_OPTION LAST_OPTION
}; };
option_help * help = malloc(sizeof(h)); option_help * help = malloc(sizeof(h));
@ -113,6 +149,7 @@ ior_aiori_t posix_aiori = {
.xfer = POSIX_Xfer, .xfer = POSIX_Xfer,
.close = POSIX_Close, .close = POSIX_Close,
.delete = POSIX_Delete, .delete = POSIX_Delete,
.xfer_hints = aiori_posix_xfer_hints,
.get_version = aiori_get_version, .get_version = aiori_get_version,
.fsync = POSIX_Fsync, .fsync = POSIX_Fsync,
.get_file_size = POSIX_GetFileSize, .get_file_size = POSIX_GetFileSize,
@ -123,11 +160,26 @@ ior_aiori_t posix_aiori = {
.stat = aiori_posix_stat, .stat = aiori_posix_stat,
.get_options = POSIX_options, .get_options = POSIX_options,
.enable_mdtest = true, .enable_mdtest = true,
.sync = POSIX_Sync .sync = POSIX_Sync,
.check_params = POSIX_check_params
}; };
/***************************** F U N C T I O N S ******************************/ /***************************** F U N C T I O N S ******************************/
static aiori_xfer_hint_t * hints = NULL;
void aiori_posix_xfer_hints(aiori_xfer_hint_t * params){
hints = params;
}
static int POSIX_check_params(aiori_mod_opt_t * param){
posix_options_t * o = (posix_options_t*) param;
if (o->beegfs_chunkSize != -1 && (!ISPOWEROFTWO(o->beegfs_chunkSize) || o->beegfs_chunkSize < (1<<16)))
ERR("beegfsChunkSize must be a power of two and >64k");
if(o->lustre_stripe_count != -1 || o->lustre_stripe_size != 0)
o->lustre_set_striping = 1;
return 0;
}
#ifdef HAVE_GPFS_FCNTL_H #ifdef HAVE_GPFS_FCNTL_H
void gpfs_free_all_locks(int fd) void gpfs_free_all_locks(int fd)
@ -151,7 +203,7 @@ void gpfs_free_all_locks(int fd)
EWARNF("gpfs_fcntl(%d, ...) release all locks hint failed.", fd); EWARNF("gpfs_fcntl(%d, ...) release all locks hint failed.", fd);
} }
} }
void gpfs_access_start(int fd, IOR_offset_t length, IOR_param_t *param, int access) void gpfs_access_start(int fd, IOR_offset_t length, int access)
{ {
int rc; int rc;
struct { struct {
@ -165,17 +217,17 @@ void gpfs_access_start(int fd, IOR_offset_t length, IOR_param_t *param, int acce
take_locks.access.structLen = sizeof(take_locks.access); take_locks.access.structLen = sizeof(take_locks.access);
take_locks.access.structType = GPFS_ACCESS_RANGE; take_locks.access.structType = GPFS_ACCESS_RANGE;
take_locks.access.start = param->offset; take_locks.access.start = hints->offset;
take_locks.access.length = length; take_locks.access.length = length;
take_locks.access.isWrite = (access == WRITE); take_locks.access.isWrite = (access == WRITE);
rc = gpfs_fcntl(fd, &take_locks); rc = gpfs_fcntl(fd, &take_locks);
if (verbose >= VERBOSE_2 && rc != 0) { if (verbose >= VERBOSE_2 && rc != 0) {
EWARNF("gpfs_fcntl(fd, ...) access range hint failed.", fd); EWARNF("gpfs_fcntl(%d, ...) access range hint failed.", fd);
} }
} }
void gpfs_access_end(int fd, IOR_offset_t length, IOR_param_t *param, int access) void gpfs_access_end(int fd, IOR_offset_t length, int access)
{ {
int rc; int rc;
struct { struct {
@ -190,12 +242,12 @@ void gpfs_access_end(int fd, IOR_offset_t length, IOR_param_t *param, int access
free_locks.free.structLen = sizeof(free_locks.free); free_locks.free.structLen = sizeof(free_locks.free);
free_locks.free.structType = GPFS_FREE_RANGE; free_locks.free.structType = GPFS_FREE_RANGE;
free_locks.free.start = param->offset; free_locks.free.start = hints->offset;
free_locks.free.length = length; free_locks.free.length = length;
rc = gpfs_fcntl(fd, &free_locks); rc = gpfs_fcntl(fd, &free_locks);
if (verbose >= VERBOSE_2 && rc != 0) { if (verbose >= VERBOSE_2 && rc != 0) {
EWARNF("gpfs_fcntl(fd, ...) free range hint failed.", fd); EWARNF("gpfs_fcntl(%d, ...) free range hint failed.", fd);
} }
} }
@ -318,7 +370,7 @@ bool beegfs_createFilePath(char* filepath, mode_t mode, int numTargets, int chun
/* /*
* Creat and open a file through the POSIX interface. * Creat and open a file through the POSIX interface.
*/ */
void *POSIX_Create(char *testFileName, IOR_param_t * param) aiori_fd_t *POSIX_Create(char *testFileName, int flags, aiori_mod_opt_t * param)
{ {
int fd_oflag = O_BINARY; int fd_oflag = O_BINARY;
int mode = 0664; int mode = 0664;
@ -327,13 +379,13 @@ void *POSIX_Create(char *testFileName, IOR_param_t * param)
fd = (int *)malloc(sizeof(int)); fd = (int *)malloc(sizeof(int));
if (fd == NULL) if (fd == NULL)
ERR("Unable to malloc file descriptor"); ERR("Unable to malloc file descriptor");
posix_options_t * o = (posix_options_t*) param->backend_options; posix_options_t * o = (posix_options_t*) param;
if (o->direct_io == TRUE){ if (o->direct_io == TRUE){
set_o_direct_flag(&fd_oflag); set_o_direct_flag(&fd_oflag);
} }
if(param->dryRun) if(hints->dryRun)
return 0; return (aiori_fd_t*) 0;
#ifdef HAVE_LUSTRE_LUSTRE_USER_H #ifdef HAVE_LUSTRE_LUSTRE_USER_H
/* Add a #define for FASYNC if not available, as it forms part of /* Add a #define for FASYNC if not available, as it forms part of
@ -341,12 +393,11 @@ void *POSIX_Create(char *testFileName, IOR_param_t * param)
#ifndef FASYNC #ifndef FASYNC
#define FASYNC 00020000 /* fcntl, for BSD compatibility */ #define FASYNC 00020000 /* fcntl, for BSD compatibility */
#endif #endif
if (o->lustre_set_striping) {
if (param->lustre_set_striping) {
/* In the single-shared-file case, task 0 has to creat the /* In the single-shared-file case, task 0 has to creat the
file with the Lustre striping options before any other processes file with the Lustre striping options before any other processes
open the file */ open the file */
if (!param->filePerProc && rank != 0) { if (!hints->filePerProc && rank != 0) {
MPI_CHECK(MPI_Barrier(testComm), "barrier error"); MPI_CHECK(MPI_Barrier(testComm), "barrier error");
fd_oflag |= O_RDWR; fd_oflag |= O_RDWR;
*fd = open64(testFileName, fd_oflag, mode); *fd = open64(testFileName, fd_oflag, mode);
@ -358,9 +409,9 @@ void *POSIX_Create(char *testFileName, IOR_param_t * param)
/* Setup Lustre IOCTL striping pattern structure */ /* Setup Lustre IOCTL striping pattern structure */
opts.lmm_magic = LOV_USER_MAGIC; opts.lmm_magic = LOV_USER_MAGIC;
opts.lmm_stripe_size = param->lustre_stripe_size; opts.lmm_stripe_size = o->lustre_stripe_size;
opts.lmm_stripe_offset = param->lustre_start_ost; opts.lmm_stripe_offset = o->lustre_start_ost;
opts.lmm_stripe_count = param->lustre_stripe_count; opts.lmm_stripe_count = o->lustre_stripe_count;
/* File needs to be opened O_EXCL because we cannot set /* File needs to be opened O_EXCL because we cannot set
* Lustre striping information on a pre-existing file.*/ * Lustre striping information on a pre-existing file.*/
@ -383,7 +434,7 @@ void *POSIX_Create(char *testFileName, IOR_param_t * param)
MPI_CHECK(MPI_Abort(MPI_COMM_WORLD, -1), MPI_CHECK(MPI_Abort(MPI_COMM_WORLD, -1),
"MPI_Abort() error"); "MPI_Abort() error");
} }
if (!param->filePerProc) if (!hints->filePerProc)
MPI_CHECK(MPI_Barrier(testComm), MPI_CHECK(MPI_Barrier(testComm),
"barrier error"); "barrier error");
} }
@ -393,12 +444,12 @@ void *POSIX_Create(char *testFileName, IOR_param_t * param)
fd_oflag |= O_CREAT | O_RDWR; fd_oflag |= O_CREAT | O_RDWR;
#ifdef HAVE_BEEGFS_BEEGFS_H #ifdef HAVE_BEEGFS_BEEGFS_H
if (beegfs_isOptionSet(param->beegfs_chunkSize) if (beegfs_isOptionSet(o->beegfs_chunkSize)
|| beegfs_isOptionSet(param->beegfs_numTargets)) { || beegfs_isOptionSet(o->beegfs_numTargets)) {
bool result = beegfs_createFilePath(testFileName, bool result = beegfs_createFilePath(testFileName,
mode, mode,
param->beegfs_numTargets, o->beegfs_numTargets,
param->beegfs_chunkSize); o->beegfs_chunkSize);
if (result) { if (result) {
fd_oflag &= ~O_CREAT; fd_oflag &= ~O_CREAT;
} else { } else {
@ -415,7 +466,7 @@ void *POSIX_Create(char *testFileName, IOR_param_t * param)
#ifdef HAVE_LUSTRE_LUSTRE_USER_H #ifdef HAVE_LUSTRE_LUSTRE_USER_H
} }
if (param->lustre_ignore_locks) { if (o->lustre_ignore_locks) {
int lustre_ioctl_flags = LL_FILE_IGNORE_LOCK; int lustre_ioctl_flags = LL_FILE_IGNORE_LOCK;
if (ioctl(*fd, LL_IOC_SETFLAGS, &lustre_ioctl_flags) == -1) if (ioctl(*fd, LL_IOC_SETFLAGS, &lustre_ioctl_flags) == -1)
ERRF("ioctl(%d, LL_IOC_SETFLAGS, ...) failed", *fd); ERRF("ioctl(%d, LL_IOC_SETFLAGS, ...) failed", *fd);
@ -426,35 +477,31 @@ void *POSIX_Create(char *testFileName, IOR_param_t * param)
/* in the single shared file case, immediately release all locks, with /* in the single shared file case, immediately release all locks, with
* the intent that we can avoid some byte range lock revocation: * the intent that we can avoid some byte range lock revocation:
* everyone will be writing/reading from individual regions */ * everyone will be writing/reading from individual regions */
if (param->gpfs_release_token ) { if (o->gpfs_release_token ) {
gpfs_free_all_locks(*fd); gpfs_free_all_locks(*fd);
} }
#endif #endif
return ((void *)fd); return (aiori_fd_t*) fd;
} }
/* /*
* Creat a file through mknod interface. * Creat a file through mknod interface.
*/ */
void *POSIX_Mknod(char *testFileName) int POSIX_Mknod(char *testFileName)
{ {
int *fd; int ret;
fd = (int *)malloc(sizeof(int)); ret = mknod(testFileName, S_IFREG | S_IRUSR, 0);
if (fd == NULL) if (ret < 0)
ERR("Unable to malloc file descriptor"); ERR("mknod failed");
*fd = mknod(testFileName, S_IFREG | S_IRUSR, 0); return ret;
if (*fd < 0)
ERR("mknod failed");
return ((void *)fd);
} }
/* /*
* Open a file through the POSIX interface. * Open a file through the POSIX interface.
*/ */
void *POSIX_Open(char *testFileName, IOR_param_t * param) aiori_fd_t *POSIX_Open(char *testFileName, int flags, aiori_mod_opt_t * param)
{ {
int fd_oflag = O_BINARY; int fd_oflag = O_BINARY;
int *fd; int *fd;
@ -463,21 +510,21 @@ void *POSIX_Open(char *testFileName, IOR_param_t * param)
if (fd == NULL) if (fd == NULL)
ERR("Unable to malloc file descriptor"); ERR("Unable to malloc file descriptor");
posix_options_t * o = (posix_options_t*) param->backend_options; posix_options_t * o = (posix_options_t*) param;
if (o->direct_io == TRUE) if (o->direct_io == TRUE)
set_o_direct_flag(&fd_oflag); set_o_direct_flag(&fd_oflag);
fd_oflag |= O_RDWR; fd_oflag |= O_RDWR;
if(param->dryRun) if(hints->dryRun)
return 0; return (aiori_fd_t*) 0;
*fd = open64(testFileName, fd_oflag); *fd = open64(testFileName, fd_oflag);
if (*fd < 0) if (*fd < 0)
ERRF("open64(\"%s\", %d) failed", testFileName, fd_oflag); ERRF("open64(\"%s\", %d) failed", testFileName, fd_oflag);
#ifdef HAVE_LUSTRE_LUSTRE_USER_H #ifdef HAVE_LUSTRE_LUSTRE_USER_H
if (param->lustre_ignore_locks) { if (o->lustre_ignore_locks) {
int lustre_ioctl_flags = LL_FILE_IGNORE_LOCK; int lustre_ioctl_flags = LL_FILE_IGNORE_LOCK;
if (verbose >= VERBOSE_1) { if (verbose >= VERBOSE_1) {
fprintf(stdout, fprintf(stdout,
@ -489,40 +536,41 @@ void *POSIX_Open(char *testFileName, IOR_param_t * param)
#endif /* HAVE_LUSTRE_LUSTRE_USER_H */ #endif /* HAVE_LUSTRE_LUSTRE_USER_H */
#ifdef HAVE_GPFS_FCNTL_H #ifdef HAVE_GPFS_FCNTL_H
if(param->gpfs_release_token) { if(o->gpfs_release_token) {
gpfs_free_all_locks(*fd); gpfs_free_all_locks(*fd);
} }
#endif #endif
return ((void *)fd); return (aiori_fd_t*) fd;
} }
/* /*
* Write or read access to file using the POSIX interface. * Write or read access to file using the POSIX interface.
*/ */
static IOR_offset_t POSIX_Xfer(int access, void *file, IOR_size_t * buffer, static IOR_offset_t POSIX_Xfer(int access, aiori_fd_t *file, IOR_size_t * buffer,
IOR_offset_t length, IOR_param_t * param) IOR_offset_t length, IOR_offset_t offset, aiori_mod_opt_t * param)
{ {
int xferRetries = 0; int xferRetries = 0;
long long remaining = (long long)length; long long remaining = (long long)length;
char *ptr = (char *)buffer; char *ptr = (char *)buffer;
long long rc; long long rc;
int fd; int fd;
posix_options_t * o = (posix_options_t*) param;
if(param->dryRun) if(hints->dryRun)
return length; return length;
fd = *(int *)file; fd = *(int *)file;
#ifdef HAVE_GPFS_FCNTL_H #ifdef HAVE_GPFS_FCNTL_H
if (param->gpfs_hint_access) { if (o->gpfs_hint_access) {
gpfs_access_start(fd, length, param, access); gpfs_access_start(fd, length, access);
} }
#endif #endif
/* seek to offset */ /* seek to offset */
if (lseek64(fd, param->offset, SEEK_SET) == -1) if (lseek64(fd, offset, SEEK_SET) == -1)
ERRF("lseek64(%d, %lld, SEEK_SET) failed", fd, param->offset); ERRF("lseek64(%d, %lld, SEEK_SET) failed", fd, offset);
while (remaining > 0) { while (remaining > 0) {
/* write/read file */ /* write/read file */
@ -531,20 +579,21 @@ static IOR_offset_t POSIX_Xfer(int access, void *file, IOR_size_t * buffer,
fprintf(stdout, fprintf(stdout,
"task %d writing to offset %lld\n", "task %d writing to offset %lld\n",
rank, rank,
param->offset + length - remaining); offset + length - remaining);
} }
rc = write(fd, ptr, remaining); rc = write(fd, ptr, remaining);
if (rc == -1) if (rc == -1)
ERRF("write(%d, %p, %lld) failed", ERRF("write(%d, %p, %lld) failed",
fd, (void*)ptr, remaining); fd, (void*)ptr, remaining);
if (param->fsyncPerWrite == TRUE) if (hints->fsyncPerWrite == TRUE){
POSIX_Fsync(&fd, param); POSIX_Fsync((aiori_fd_t*) &fd, param);
}
} else { /* READ or CHECK */ } else { /* READ or CHECK */
if (verbose >= VERBOSE_4) { if (verbose >= VERBOSE_4) {
fprintf(stdout, fprintf(stdout,
"task %d reading from offset %lld\n", "task %d reading from offset %lld\n",
rank, rank,
param->offset + length - remaining); offset + length - remaining);
} }
rc = read(fd, ptr, remaining); rc = read(fd, ptr, remaining);
if (rc == 0) if (rc == 0)
@ -560,8 +609,8 @@ static IOR_offset_t POSIX_Xfer(int access, void *file, IOR_size_t * buffer,
rank, rank,
access == WRITE ? "write()" : "read()", access == WRITE ? "write()" : "read()",
rc, remaining, rc, remaining,
param->offset + length - remaining); offset + length - remaining);
if (param->singleXferAttempt == TRUE) if (hints->singleXferAttempt == TRUE)
MPI_CHECK(MPI_Abort(MPI_COMM_WORLD, -1), MPI_CHECK(MPI_Abort(MPI_COMM_WORLD, -1),
"barrier error"); "barrier error");
if (xferRetries > MAX_RETRY) if (xferRetries > MAX_RETRY)
@ -574,7 +623,7 @@ static IOR_offset_t POSIX_Xfer(int access, void *file, IOR_size_t * buffer,
xferRetries++; xferRetries++;
} }
#ifdef HAVE_GPFS_FCNTL_H #ifdef HAVE_GPFS_FCNTL_H
if (param->gpfs_hint_access) { if (o->gpfs_hint_access) {
gpfs_access_end(fd, length, param, access); gpfs_access_end(fd, length, param, access);
} }
#endif #endif
@ -584,14 +633,14 @@ static IOR_offset_t POSIX_Xfer(int access, void *file, IOR_size_t * buffer,
/* /*
* Perform fsync(). * Perform fsync().
*/ */
static void POSIX_Fsync(void *fd, IOR_param_t * param) static void POSIX_Fsync(aiori_fd_t *fd, aiori_mod_opt_t * param)
{ {
if (fsync(*(int *)fd) != 0) if (fsync(*(int *)fd) != 0)
EWARNF("fsync(%d) failed", *(int *)fd); EWARNF("fsync(%d) failed", *(int *)fd);
} }
static void POSIX_Sync(IOR_param_t * param) static void POSIX_Sync(aiori_mod_opt_t * param)
{ {
int ret = system("sync"); int ret = system("sync");
if (ret != 0){ if (ret != 0){
@ -603,9 +652,9 @@ static void POSIX_Sync(IOR_param_t * param)
/* /*
* Close a file through the POSIX interface. * Close a file through the POSIX interface.
*/ */
void POSIX_Close(void *fd, IOR_param_t * param) void POSIX_Close(aiori_fd_t *fd, aiori_mod_opt_t * param)
{ {
if(param->dryRun) if(hints->dryRun)
return; return;
if (close(*(int *)fd) != 0) if (close(*(int *)fd) != 0)
ERRF("close(%d) failed", *(int *)fd); ERRF("close(%d) failed", *(int *)fd);
@ -615,9 +664,9 @@ void POSIX_Close(void *fd, IOR_param_t * param)
/* /*
* Delete a file through the POSIX interface. * Delete a file through the POSIX interface.
*/ */
void POSIX_Delete(char *testFileName, IOR_param_t * param) void POSIX_Delete(char *testFileName, aiori_mod_opt_t * param)
{ {
if(param->dryRun) if(hints->dryRun)
return; return;
if (unlink(testFileName) != 0){ if (unlink(testFileName) != 0){
EWARNF("[RANK %03d]: unlink() of file \"%s\" failed\n", EWARNF("[RANK %03d]: unlink() of file \"%s\" failed\n",
@ -628,10 +677,10 @@ void POSIX_Delete(char *testFileName, IOR_param_t * param)
/* /*
* Use POSIX stat() to return aggregate file size. * Use POSIX stat() to return aggregate file size.
*/ */
IOR_offset_t POSIX_GetFileSize(IOR_param_t * test, MPI_Comm testComm, IOR_offset_t POSIX_GetFileSize(aiori_mod_opt_t * test, MPI_Comm testComm,
char *testFileName) char *testFileName)
{ {
if(test->dryRun) if(hints->dryRun)
return 0; return 0;
struct stat stat_buf; struct stat stat_buf;
IOR_offset_t aggFileSizeFromStat, tmpMin, tmpMax, tmpSum; IOR_offset_t aggFileSizeFromStat, tmpMin, tmpMax, tmpSum;
@ -641,7 +690,7 @@ IOR_offset_t POSIX_GetFileSize(IOR_param_t * test, MPI_Comm testComm,
} }
aggFileSizeFromStat = stat_buf.st_size; aggFileSizeFromStat = stat_buf.st_size;
if (test->filePerProc == TRUE) { if (hints->filePerProc == TRUE) {
MPI_CHECK(MPI_Allreduce(&aggFileSizeFromStat, &tmpSum, 1, MPI_CHECK(MPI_Allreduce(&aggFileSizeFromStat, &tmpSum, 1,
MPI_LONG_LONG_INT, MPI_SUM, testComm), MPI_LONG_LONG_INT, MPI_SUM, testComm),
"cannot total data moved"); "cannot total data moved");

View File

@ -137,9 +137,6 @@ static void *RADOS_Create_Or_Open(char *testFileName, IOR_param_t * param, int c
RADOS_Cluster_Init(param); RADOS_Cluster_Init(param);
if (param->useO_DIRECT == TRUE)
WARN("direct I/O mode is not implemented in RADOS\n");
oid = strdup(testFileName); oid = strdup(testFileName);
if (!oid) if (!oid)
ERR("unable to allocate RADOS oid"); ERR("unable to allocate RADOS oid");

View File

@ -157,8 +157,8 @@ static void EMC_Close(void*, IOR_param_t*);
static void S3_Delete(char*, IOR_param_t*); static void S3_Delete(char*, IOR_param_t*);
static void S3_Fsync(void*, IOR_param_t*); static void S3_Fsync(void*, IOR_param_t*);
static IOR_offset_t S3_GetFileSize(IOR_param_t*, MPI_Comm, char*); static IOR_offset_t S3_GetFileSize(IOR_param_t*, MPI_Comm, char*);
static void S3_init(); static void S3_init(void * options);
static void S3_finalize(); static void S3_finalize(void * options);
static int S3_check_params(IOR_param_t *); static int S3_check_params(IOR_param_t *);
@ -218,14 +218,14 @@ ior_aiori_t s3_emc_aiori = {
}; };
static void S3_init(){ static void S3_init(void * options){
/* This is supposed to be done before *any* threads are created. /* This is supposed to be done before *any* threads are created.
* Could MPI_Init() create threads (or call multi-threaded * Could MPI_Init() create threads (or call multi-threaded
* libraries)? We'll assume so. */ * libraries)? We'll assume so. */
AWS4C_CHECK( aws_init() ); AWS4C_CHECK( aws_init() );
} }
static void S3_finalize(){ static void S3_finalize(void * options){
/* done once per program, after exiting all threads. /* done once per program, after exiting all threads.
* NOTE: This fn doesn't return a value that can be checked for success. */ * NOTE: This fn doesn't return a value that can be checked for success. */
aws_cleanup(); aws_cleanup();
@ -241,10 +241,10 @@ static int S3_check_params(IOR_param_t * test){
if (Nto1 && (s != 1) && (b != t)) { if (Nto1 && (s != 1) && (b != t)) {
ERR("N:1 (strided) requires xfer-size == block-size"); ERR("N:1 (strided) requires xfer-size == block-size");
return 0; return 1;
} }
return 1; return 0;
} }
/* modelled on similar macros in iordef.h */ /* modelled on similar macros in iordef.h */

View File

@ -76,6 +76,9 @@ ior_aiori_t *available_aiori[] = {
#ifdef USE_RADOS_AIORI #ifdef USE_RADOS_AIORI
&rados_aiori, &rados_aiori,
#endif #endif
#ifdef USE_CEPHFS_AIORI
&cephfs_aiori,
#endif
#ifdef USE_GFARM_AIORI #ifdef USE_GFARM_AIORI
&gfarm_aiori, &gfarm_aiori,
#endif #endif
@ -152,47 +155,68 @@ void aiori_supported_apis(char * APIs, char * APIs_legacy, enum bench_type type)
* This function provides a AIORI statfs for POSIX-compliant filesystems. It * This function provides a AIORI statfs for POSIX-compliant filesystems. It
* uses statvfs is available and falls back on statfs. * uses statvfs is available and falls back on statfs.
*/ */
int aiori_posix_statfs (const char *path, ior_aiori_statfs_t *stat_buf, IOR_param_t * param) int aiori_posix_statfs (const char *path, ior_aiori_statfs_t *stat_buf, aiori_mod_opt_t * module_options)
{ {
int ret; // find the parent directory
char * fileName = strdup(path);
int i;
int directoryFound = FALSE;
/* get directory for outfile */
i = strlen(fileName);
while (i-- > 0) {
if (fileName[i] == '/') {
fileName[i] = '\0';
directoryFound = TRUE;
break;
}
}
/* if no directory/, use '.' */
if (directoryFound == FALSE) {
strcpy(fileName, ".");
}
int ret;
#if defined(HAVE_STATVFS) #if defined(HAVE_STATVFS)
struct statvfs statfs_buf; struct statvfs statfs_buf;
ret = statvfs (path, &statfs_buf); ret = statvfs (fileName, &statfs_buf);
#else #else
struct statfs statfs_buf; struct statfs statfs_buf;
ret = statfs (path, &statfs_buf); ret = statfs (fileName, &statfs_buf);
#endif #endif
if (-1 == ret) { if (-1 == ret) {
return -1; perror("POSIX couldn't call statvfs");
} return -1;
}
stat_buf->f_bsize = statfs_buf.f_bsize; stat_buf->f_bsize = statfs_buf.f_bsize;
stat_buf->f_blocks = statfs_buf.f_blocks; stat_buf->f_blocks = statfs_buf.f_blocks;
stat_buf->f_bfree = statfs_buf.f_bfree; stat_buf->f_bfree = statfs_buf.f_bfree;
stat_buf->f_files = statfs_buf.f_files; stat_buf->f_files = statfs_buf.f_files;
stat_buf->f_ffree = statfs_buf.f_ffree; stat_buf->f_ffree = statfs_buf.f_ffree;
return 0; free(fileName);
return 0;
} }
int aiori_posix_mkdir (const char *path, mode_t mode, IOR_param_t * param) int aiori_posix_mkdir (const char *path, mode_t mode, aiori_mod_opt_t * module_options)
{ {
return mkdir (path, mode); return mkdir (path, mode);
} }
int aiori_posix_rmdir (const char *path, IOR_param_t * param) int aiori_posix_rmdir (const char *path, aiori_mod_opt_t * module_options)
{ {
return rmdir (path); return rmdir (path);
} }
int aiori_posix_access (const char *path, int mode, IOR_param_t * param) int aiori_posix_access (const char *path, int mode, aiori_mod_opt_t * module_options)
{ {
return access (path, mode); return access (path, mode);
} }
int aiori_posix_stat (const char *path, struct stat *buf, IOR_param_t * param) int aiori_posix_stat (const char *path, struct stat *buf, aiori_mod_opt_t * module_options)
{ {
return stat (path, buf); return stat (path, buf);
} }
@ -202,92 +226,6 @@ char* aiori_get_version()
return ""; return "";
} }
static bool is_initialized = false;
static void init_or_fini_internal(const ior_aiori_t *test_backend,
const bool init)
{
if (init)
{
if (test_backend->initialize)
test_backend->initialize();
}
else
{
if (test_backend->finalize)
test_backend->finalize();
}
}
static void init_or_fini(IOR_test_t *tests, const bool init)
{
/* Sanity check, we were compiled with SOME backend, right? */
if (0 == aiori_count ()) {
ERR("No IO backends compiled into aiori. "
"Run 'configure --with-<backend>', and recompile.");
}
/* Pointer to the initialize of finalize function */
/* if tests is NULL, initialize or finalize all available backends */
if (tests == NULL)
{
for (ior_aiori_t **tmp = available_aiori ; *tmp != NULL; ++tmp)
init_or_fini_internal(*tmp, init);
return;
}
for (IOR_test_t *t = tests; t != NULL; t = t->next)
{
IOR_param_t *params = &t->params;
assert(params != NULL);
const ior_aiori_t *test_backend = params->backend;
assert(test_backend != NULL);
init_or_fini_internal(test_backend, init);
}
}
/**
* Initialize IO backends.
*
* @param[in] tests Pointers to the first test
*
* This function initializes all backends which will be used. If tests is NULL
* all available backends are initialized.
*/
void aiori_initialize(IOR_test_t *tests)
{
if (is_initialized)
return;
init_or_fini(tests, true);
is_initialized = true;
}
/**
* Finalize IO backends.
*
* @param[in] tests Pointers to the first test
*
* This function finalizes all backends which were used. If tests is NULL
* all available backends are finialized.
*/
void aiori_finalize(IOR_test_t *tests)
{
if (!is_initialized)
return;
is_initialized = false;
init_or_fini(tests, false);
}
const ior_aiori_t *aiori_select (const char *api) const ior_aiori_t *aiori_select (const char *api)
{ {
char warn_str[256] = {0}; char warn_str[256] = {0};

View File

@ -24,7 +24,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <stdbool.h> #include <stdbool.h>
#include "ior.h"
#include "iordef.h" /* IOR Definitions */ #include "iordef.h" /* IOR Definitions */
#include "option.h" #include "option.h"
@ -63,31 +62,61 @@ typedef struct ior_aiori_statfs {
uint64_t f_ffree; uint64_t f_ffree;
} ior_aiori_statfs_t; } ior_aiori_statfs_t;
/*
This structure contains information about the expected IO pattern that may be used to optimize data access. Optimally, it should be stored for each file descriptor, at the moment it can only be set globally per aiori backend module.
*/
typedef struct aiori_xfer_hint_t{
int dryRun; /* do not perform any I/Os just run evtl. inputs print dummy output */
int filePerProc; /* single file or file-per-process */
int collective; /* collective I/O */
int numTasks; /* number of tasks for test */
int numNodes; /* number of nodes for test */
int randomOffset; /* access is to random offsets */
int fsyncPerWrite; /* fsync() after each write */
IOR_offset_t segmentCount; /* number of segments (or HDF5 datasets) */
IOR_offset_t blockSize; /* contiguous bytes to write per task */
IOR_offset_t transferSize; /* size of transfer in bytes */
IOR_offset_t expectedAggFileSize; /* calculated aggregate file size */
int singleXferAttempt; /* do not retry transfer if incomplete */
} aiori_xfer_hint_t;
/* this is a dummy structure to create some type safety */
typedef struct aiori_mod_opt_t{
void * dummy;
} aiori_mod_opt_t;
typedef struct aiori_fd_t{
void * dummy;
} aiori_fd_t;
typedef struct ior_aiori { typedef struct ior_aiori {
char *name; char *name;
char *name_legacy; char *name_legacy;
void *(*create)(char *, IOR_param_t *); aiori_fd_t *(*create)(char *, int iorflags, aiori_mod_opt_t *);
void *(*mknod)(char *); int (*mknod)(char *);
void *(*open)(char *, IOR_param_t *); aiori_fd_t *(*open)(char *, int iorflags, aiori_mod_opt_t *);
IOR_offset_t (*xfer)(int, void *, IOR_size_t *, /*
IOR_offset_t, IOR_param_t *); Allow to set generic transfer options that shall be applied to any subsequent IO call.
void (*close)(void *, IOR_param_t *); */
void (*delete)(char *, IOR_param_t *); void (*xfer_hints)(aiori_xfer_hint_t * params);
char* (*get_version)(); IOR_offset_t (*xfer)(int access, aiori_fd_t *, IOR_size_t *,
void (*fsync)(void *, IOR_param_t *); IOR_offset_t size, IOR_offset_t offset, aiori_mod_opt_t *);
IOR_offset_t (*get_file_size)(IOR_param_t *, MPI_Comm, char *); void (*close)(aiori_fd_t *, aiori_mod_opt_t *);
int (*statfs) (const char *, ior_aiori_statfs_t *, IOR_param_t * param); void (*delete)(char *, aiori_mod_opt_t *);
int (*mkdir) (const char *path, mode_t mode, IOR_param_t * param); char* (*get_version)(void);
int (*rmdir) (const char *path, IOR_param_t * param); void (*fsync)(aiori_fd_t *, aiori_mod_opt_t *);
int (*access) (const char *path, int mode, IOR_param_t * param); IOR_offset_t (*get_file_size)(aiori_mod_opt_t * module_options, MPI_Comm, char *);
int (*stat) (const char *path, struct stat *buf, IOR_param_t * param); int (*statfs) (const char *, ior_aiori_statfs_t *, aiori_mod_opt_t * module_options);
void (*initialize)(); /* called once per program before MPI is started */ int (*mkdir) (const char *path, mode_t mode, aiori_mod_opt_t * module_options);
void (*finalize)(); /* called once per program after MPI is shutdown */ int (*rmdir) (const char *path, aiori_mod_opt_t * module_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 */ int (*access) (const char *path, int mode, aiori_mod_opt_t * module_options);
int (*stat) (const char *path, struct stat *buf, aiori_mod_opt_t * module_options);
void (*initialize)(aiori_mod_opt_t * options); /* called once per program before MPI is started */
void (*finalize)(aiori_mod_opt_t * options); /* called once per program after MPI is shutdown */
option_help * (*get_options)(aiori_mod_opt_t ** init_backend_options, aiori_mod_opt_t* init_values); /* initializes the backend options as well and returns the pointer to the option help structure */
int (*check_params)(aiori_mod_opt_t *); /* check if the provided module_optionseters for the given test and the module options are correct, if they aren't print a message and exit(1) or return 1*/
void (*sync)(aiori_mod_opt_t * ); /* synchronize every pending operation for this storage */
bool enable_mdtest; bool enable_mdtest;
int (*check_params)(IOR_param_t *); /* check if the provided parameters for the given test and the module options are correct, if they aren't print a message and exit(1) or return 1*/
void (*sync)(IOR_param_t * ); /* synchronize every pending operation for this storage */
} ior_aiori_t; } ior_aiori_t;
enum bench_type { enum bench_type {
@ -110,10 +139,9 @@ extern ior_aiori_t s3_aiori;
extern ior_aiori_t s3_plus_aiori; extern ior_aiori_t s3_plus_aiori;
extern ior_aiori_t s3_emc_aiori; extern ior_aiori_t s3_emc_aiori;
extern ior_aiori_t rados_aiori; extern ior_aiori_t rados_aiori;
extern ior_aiori_t cephfs_aiori;
extern ior_aiori_t gfarm_aiori; extern ior_aiori_t gfarm_aiori;
void aiori_initialize(IOR_test_t * tests);
void aiori_finalize(IOR_test_t * tests);
const ior_aiori_t *aiori_select (const char *api); const ior_aiori_t *aiori_select (const char *api);
int aiori_count (void); int aiori_count (void);
void aiori_supported_apis(char * APIs, char * APIs_legacy, enum bench_type type); void aiori_supported_apis(char * APIs, char * APIs_legacy, enum bench_type type);
@ -124,26 +152,26 @@ void * airoi_update_module_options(const ior_aiori_t * backend, options_all_t *
const char *aiori_default (void); const char *aiori_default (void);
/* some generic POSIX-based backend calls */ /* some generic POSIX-based backend calls */
char * aiori_get_version(); char * aiori_get_version (void);
int aiori_posix_statfs (const char *path, ior_aiori_statfs_t *stat_buf, IOR_param_t * param); int aiori_posix_statfs (const char *path, ior_aiori_statfs_t *stat_buf, aiori_mod_opt_t * module_options);
int aiori_posix_mkdir (const char *path, mode_t mode, IOR_param_t * param); int aiori_posix_mkdir (const char *path, mode_t mode, aiori_mod_opt_t * module_options);
int aiori_posix_rmdir (const char *path, IOR_param_t * param); int aiori_posix_rmdir (const char *path, aiori_mod_opt_t * module_options);
int aiori_posix_access (const char *path, int mode, IOR_param_t * param); int aiori_posix_access (const char *path, int mode, aiori_mod_opt_t * module_options);
int aiori_posix_stat (const char *path, struct stat *buf, IOR_param_t * param); int aiori_posix_stat (const char *path, struct stat *buf, aiori_mod_opt_t * module_options);
void aiori_posix_xfer_hints(aiori_xfer_hint_t * params);
void *POSIX_Create(char *testFileName, IOR_param_t * param); aiori_fd_t *POSIX_Create(char *testFileName, int flags, aiori_mod_opt_t * module_options);
void *POSIX_Mknod(char *testFileName); int POSIX_Mknod(char *testFileName);
void *POSIX_Open(char *testFileName, IOR_param_t * param); aiori_fd_t *POSIX_Open(char *testFileName, int flags, aiori_mod_opt_t * module_options);
IOR_offset_t POSIX_GetFileSize(IOR_param_t * test, MPI_Comm testComm, char *testFileName); IOR_offset_t POSIX_GetFileSize(aiori_mod_opt_t * test, MPI_Comm testComm, char *testFileName);
void POSIX_Delete(char *testFileName, IOR_param_t * param); void POSIX_Delete(char *testFileName, aiori_mod_opt_t * module_options);
void POSIX_Close(void *fd, IOR_param_t * param); void POSIX_Close(aiori_fd_t *fd, aiori_mod_opt_t * module_options);
option_help * POSIX_options(void ** init_backend_options, void * init_values); option_help * POSIX_options(aiori_mod_opt_t ** init_backend_options, aiori_mod_opt_t * init_values);
/* NOTE: these 3 MPI-IO functions are exported for reuse by HDF5/PNetCDF */ /* NOTE: these 3 MPI-IO functions are exported for reuse by HDF5/PNetCDF */
void MPIIO_Delete(char *testFileName, IOR_param_t * param); void MPIIO_Delete(char *testFileName, aiori_mod_opt_t * module_options);
IOR_offset_t MPIIO_GetFileSize(IOR_param_t * test, MPI_Comm testComm, IOR_offset_t MPIIO_GetFileSize(aiori_mod_opt_t * options, MPI_Comm testComm, char *testFileName);
char *testFileName); int MPIIO_Access(const char *, int, aiori_mod_opt_t *);
int MPIIO_Access(const char *, int, IOR_param_t *);
#endif /* not _AIORI_H */ #endif /* not _AIORI_H */

View File

@ -17,7 +17,6 @@ void PrintShortSummary(IOR_test_t * test);
void PrintLongSummaryAllTests(IOR_test_t *tests_head); void PrintLongSummaryAllTests(IOR_test_t *tests_head);
void PrintLongSummaryHeader(); void PrintLongSummaryHeader();
void PrintLongSummaryOneTest(IOR_test_t *test); void PrintLongSummaryOneTest(IOR_test_t *test);
void DisplayFreespace(IOR_param_t * test);
void GetTestFileName(char *, IOR_param_t *); void GetTestFileName(char *, IOR_param_t *);
void PrintRemoveTiming(double start, double finish, int rep); void PrintRemoveTiming(double start, double finish, int rep);
void PrintReducedResult(IOR_test_t *test, int access, double bw, double iops, double latency, void PrintReducedResult(IOR_test_t *test, int access, double bw, double iops, double latency,
@ -26,6 +25,9 @@ void PrintTestEnds();
void PrintTableHeader(); void PrintTableHeader();
/* End of ior-output */ /* End of ior-output */
IOR_offset_t *GetOffsetArraySequential(IOR_param_t * test, int pretendRank);
IOR_offset_t *GetOffsetArrayRandom(IOR_param_t * test, int pretendRank, int access);
struct results { struct results {
double min; double min;
double max; double max;

View File

@ -210,7 +210,7 @@ void PrintRepeatStart(){
} }
void PrintTestEnds(){ void PrintTestEnds(){
if (rank != 0 || verbose < VERBOSE_0) { if (rank != 0 || verbose <= VERBOSE_0) {
PrintEndSection(); PrintEndSection();
return; return;
} }
@ -262,7 +262,7 @@ void PrintHeader(int argc, char **argv)
if (outputFormat != OUTPUT_DEFAULT){ if (outputFormat != OUTPUT_DEFAULT){
PrintKeyVal("Version", META_VERSION); PrintKeyVal("Version", META_VERSION);
}else{ }else{
printf("IOR-" META_VERSION ": MPI Coordinated Test of Parallel I/O\n"); fprintf(out_resultfile, "IOR-" META_VERSION ": MPI Coordinated Test of Parallel I/O\n");
} }
PrintKeyVal("Began", CurrentTimeString()); PrintKeyVal("Began", CurrentTimeString());
PrintKeyValStart("Command line"); PrintKeyValStart("Command line");
@ -322,11 +322,8 @@ void ShowTestStart(IOR_param_t *test)
PrintStartSection(); PrintStartSection();
PrintKeyValInt("TestID", test->id); PrintKeyValInt("TestID", test->id);
PrintKeyVal("StartTime", CurrentTimeString()); PrintKeyVal("StartTime", CurrentTimeString());
/* if pvfs2:, then skip */
if (strcasecmp(test->api, "DFS") && ShowFileSystemSize(test);
Regex(test->testFileName, "^[a-z][a-z].*:") == 0) {
DisplayFreespace(test);
}
if (verbose >= VERBOSE_3 || outputFormat == OUTPUT_JSON) { if (verbose >= VERBOSE_3 || outputFormat == OUTPUT_JSON) {
char* data_packets[] = {"g","t","o","i"}; char* data_packets[] = {"g","t","o","i"};
@ -337,7 +334,6 @@ void ShowTestStart(IOR_param_t *test)
PrintKeyVal("api", test->api); PrintKeyVal("api", test->api);
PrintKeyVal("platform", test->platform); PrintKeyVal("platform", test->platform);
PrintKeyVal("testFileName", test->testFileName); PrintKeyVal("testFileName", test->testFileName);
PrintKeyVal("hintsFileName", test->hintsFileName);
PrintKeyValInt("deadlineForStonewall", test->deadlineForStonewalling); PrintKeyValInt("deadlineForStonewall", test->deadlineForStonewalling);
PrintKeyValInt("stoneWallingWearOut", test->stoneWallingWearOut); PrintKeyValInt("stoneWallingWearOut", test->stoneWallingWearOut);
PrintKeyValInt("maxTimeDuration", test->maxTimeDuration); PrintKeyValInt("maxTimeDuration", test->maxTimeDuration);
@ -355,9 +351,7 @@ void ShowTestStart(IOR_param_t *test)
PrintKeyValInt("fsync", test->fsync); PrintKeyValInt("fsync", test->fsync);
PrintKeyValInt("fsyncperwrite", test->fsyncPerWrite); PrintKeyValInt("fsyncperwrite", test->fsyncPerWrite);
PrintKeyValInt("useExistingTestFile", test->useExistingTestFile); PrintKeyValInt("useExistingTestFile", test->useExistingTestFile);
PrintKeyValInt("showHints", test->showHints);
PrintKeyValInt("uniqueDir", test->uniqueDir); PrintKeyValInt("uniqueDir", test->uniqueDir);
PrintKeyValInt("individualDataSets", test->individualDataSets);
PrintKeyValInt("singleXferAttempt", test->singleXferAttempt); PrintKeyValInt("singleXferAttempt", test->singleXferAttempt);
PrintKeyValInt("readFile", test->readFile); PrintKeyValInt("readFile", test->readFile);
PrintKeyValInt("writeFile", test->writeFile); PrintKeyValInt("writeFile", test->writeFile);
@ -368,12 +362,7 @@ void ShowTestStart(IOR_param_t *test)
PrintKeyValInt("randomOffset", test->randomOffset); PrintKeyValInt("randomOffset", test->randomOffset);
PrintKeyValInt("checkWrite", test->checkWrite); PrintKeyValInt("checkWrite", test->checkWrite);
PrintKeyValInt("checkRead", test->checkRead); PrintKeyValInt("checkRead", test->checkRead);
PrintKeyValInt("preallocate", test->preallocate);
PrintKeyValInt("useFileView", test->useFileView);
PrintKeyValInt("setAlignment", test->setAlignment);
PrintKeyValInt("storeFileOffset", test->storeFileOffset); PrintKeyValInt("storeFileOffset", test->storeFileOffset);
PrintKeyValInt("useSharedFilePointer", test->useSharedFilePointer);
PrintKeyValInt("useStridedDatatype", test->useStridedDatatype);
PrintKeyValInt("keepFile", test->keepFile); PrintKeyValInt("keepFile", test->keepFile);
PrintKeyValInt("keepFileWithError", test->keepFileWithError); PrintKeyValInt("keepFileWithError", test->keepFileWithError);
PrintKeyValInt("quitOnError", test->quitOnError); PrintKeyValInt("quitOnError", test->quitOnError);
@ -452,14 +441,10 @@ void ShowSetup(IOR_param_t *params)
if(params->dryRun){ if(params->dryRun){
PrintKeyValInt("dryRun", params->dryRun); PrintKeyValInt("dryRun", params->dryRun);
} }
if(params->verbose) {
#ifdef HAVE_LUSTRE_LUSTRE_USER_H PrintKeyValInt("verbose", params->verbose);
if (params->lustre_set_striping) {
PrintKeyVal("Lustre stripe size", ((params->lustre_stripe_size == 0) ? "Use default" :
HumanReadable(params->lustre_stripe_size, BASE_TWO)));
PrintKeyValInt("Lustre stripe count", params->lustre_stripe_count);
} }
#endif /* HAVE_LUSTRE_LUSTRE_USER_H */
if (params->deadlineForStonewalling > 0) { if (params->deadlineForStonewalling > 0) {
PrintKeyValInt("stonewallingTime", params->deadlineForStonewalling); PrintKeyValInt("stonewallingTime", params->deadlineForStonewalling);
PrintKeyValInt("stoneWallingWearOut", params->stoneWallingWearOut ); PrintKeyValInt("stoneWallingWearOut", params->stoneWallingWearOut );
@ -535,7 +520,7 @@ static void PrintLongSummaryOneOperation(IOR_test_t *test, const int access)
struct results *ops; struct results *ops;
int reps; int reps;
if (rank != 0 || verbose < VERBOSE_0) if (rank != 0 || verbose <= VERBOSE_0)
return; return;
reps = params->repetitions; reps = params->repetitions;
@ -650,7 +635,7 @@ void PrintLongSummaryOneTest(IOR_test_t *test)
void PrintLongSummaryHeader() void PrintLongSummaryHeader()
{ {
if (rank != 0 || verbose < VERBOSE_0) if (rank != 0 || verbose <= VERBOSE_0)
return; return;
if(outputFormat != OUTPUT_DEFAULT){ if(outputFormat != OUTPUT_DEFAULT){
return; return;
@ -670,7 +655,7 @@ void PrintLongSummaryHeader()
void PrintLongSummaryAllTests(IOR_test_t *tests_head) void PrintLongSummaryAllTests(IOR_test_t *tests_head)
{ {
IOR_test_t *tptr; IOR_test_t *tptr;
if (rank != 0 || verbose < VERBOSE_0) if (rank != 0 || verbose <= VERBOSE_0)
return; return;
PrintArrayEnd(); PrintArrayEnd();
@ -703,7 +688,7 @@ void PrintShortSummary(IOR_test_t * test)
int reps; int reps;
int i; int i;
if (rank != 0 || verbose < VERBOSE_0) if (rank != 0 || verbose <= VERBOSE_0)
return; return;
PrintArrayEnd(); PrintArrayEnd();
@ -740,41 +725,9 @@ void PrintShortSummary(IOR_test_t * test)
} }
} }
/*
* Display freespace (df).
*/
void DisplayFreespace(IOR_param_t * test)
{
char fileName[MAX_STR] = { 0 };
int i;
int directoryFound = FALSE;
/* get outfile name */
GetTestFileName(fileName, test);
/* get directory for outfile */
i = strlen(fileName);
while (i-- > 0) {
if (fileName[i] == '/') {
fileName[i] = '\0';
directoryFound = TRUE;
break;
}
}
/* if no directory/, use '.' */
if (directoryFound == FALSE) {
strcpy(fileName, ".");
}
ShowFileSystemSize(fileName);
}
void PrintRemoveTiming(double start, double finish, int rep) void PrintRemoveTiming(double start, double finish, int rep)
{ {
if (rank != 0 || verbose < VERBOSE_0) if (rank != 0 || verbose <= VERBOSE_0)
return; return;
if (outputFormat == OUTPUT_DEFAULT){ if (outputFormat == OUTPUT_DEFAULT){

275
src/ior.c
View File

@ -55,9 +55,50 @@ static void InitTests(IOR_test_t * , MPI_Comm);
static void TestIoSys(IOR_test_t *); static void TestIoSys(IOR_test_t *);
static void ValidateTests(IOR_param_t *); static void ValidateTests(IOR_param_t *);
static IOR_offset_t WriteOrRead(IOR_param_t *test, IOR_results_t *results, static IOR_offset_t WriteOrRead(IOR_param_t *test, IOR_results_t *results,
void *fd, const int access, aiori_fd_t *fd, const int access,
IOR_io_buffers *ioBuffers); IOR_io_buffers *ioBuffers);
static void ior_set_xfer_hints(IOR_param_t * p){
aiori_xfer_hint_t * hints = & p->hints;
hints->dryRun = p->dryRun;
hints->filePerProc = p->filePerProc;
hints->collective = p->collective;
hints->numTasks = p->numTasks;
hints->numNodes = p->numNodes;
hints->randomOffset = p->randomOffset;
hints->fsyncPerWrite = p->fsyncPerWrite;
hints->segmentCount = p->segmentCount;
hints->blockSize = p->blockSize;
hints->transferSize = p->transferSize;
hints->expectedAggFileSize = p->expectedAggFileSize;
hints->singleXferAttempt = p->singleXferAttempt;
if(backend->xfer_hints){
backend->xfer_hints(hints);
}
}
static void test_initialize(IOR_test_t * test){
verbose = test->params.verbose;
backend = test->params.backend;
if(backend->initialize){
backend->initialize(test->params.backend_options);
}
ior_set_xfer_hints(& test->params);
if (rank == 0 && verbose >= VERBOSE_0) {
ShowTestStart(& test->params);
}
}
static void test_finalize(IOR_test_t * test){
backend = test->params.backend;
if(backend->finalize){
backend->finalize(test->params.backend_options);
}
}
IOR_test_t * ior_run(int argc, char **argv, MPI_Comm world_com, FILE * world_out){ IOR_test_t * ior_run(int argc, char **argv, MPI_Comm world_com, FILE * world_out){
IOR_test_t *tests_head; IOR_test_t *tests_head;
IOR_test_t *tptr; IOR_test_t *tptr;
@ -76,14 +117,12 @@ IOR_test_t * ior_run(int argc, char **argv, MPI_Comm world_com, FILE * world_out
/* perform each test */ /* perform each test */
for (tptr = tests_head; tptr != NULL; tptr = tptr->next) { for (tptr = tests_head; tptr != NULL; tptr = tptr->next) {
test_initialize(tptr);
totalErrorCount = 0; totalErrorCount = 0;
verbose = tptr->params.verbose;
if (rank == 0 && verbose >= VERBOSE_0) {
ShowTestStart(&tptr->params);
}
TestIoSys(tptr); TestIoSys(tptr);
tptr->results->errors = totalErrorCount; tptr->results->errors = totalErrorCount;
ShowTestEnd(tptr); ShowTestEnd(tptr);
test_finalize(tptr);
} }
PrintLongSummaryAllTests(tests_head); PrintLongSummaryAllTests(tests_head);
@ -122,17 +161,11 @@ int ior_main(int argc, char **argv)
InitTests(tests_head, mpi_comm_world); InitTests(tests_head, mpi_comm_world);
verbose = tests_head->params.verbose; verbose = tests_head->params.verbose;
aiori_initialize(tests_head);
PrintHeader(argc, argv); PrintHeader(argc, argv);
/* perform each test */ /* perform each test */
for (tptr = tests_head; tptr != NULL; tptr = tptr->next) { for (tptr = tests_head; tptr != NULL; tptr = tptr->next) {
verbose = tptr->params.verbose; test_initialize(tptr);
if (rank == 0 && verbose >= VERBOSE_0) {
backend = tptr->params.backend;
ShowTestStart(&tptr->params);
}
// This is useful for trapping a running MPI process. While // This is useful for trapping a running MPI process. While
// this is sleeping, run the script 'testing/hdfs/gdb.attach' // this is sleeping, run the script 'testing/hdfs/gdb.attach'
@ -144,18 +177,17 @@ int ior_main(int argc, char **argv)
TestIoSys(tptr); TestIoSys(tptr);
ShowTestEnd(tptr); ShowTestEnd(tptr);
test_finalize(tptr);
} }
if (verbose < 0) if (verbose <= VERBOSE_0)
/* always print final summary */ /* always print final summary */
verbose = 0; verbose = VERBOSE_1;
PrintLongSummaryAllTests(tests_head); PrintLongSummaryAllTests(tests_head);
/* display finish time */ /* display finish time */
PrintTestEnds(); PrintTestEnds();
aiori_finalize(tests_head);
MPI_CHECK(MPI_Finalize(), "cannot finalize MPI"); MPI_CHECK(MPI_Finalize(), "cannot finalize MPI");
DestroyTests(tests_head); DestroyTests(tests_head);
@ -176,10 +208,6 @@ void init_IOR_Param_t(IOR_param_t * p)
assert (NULL != default_aiori); assert (NULL != default_aiori);
memset(p, 0, sizeof(IOR_param_t)); memset(p, 0, sizeof(IOR_param_t));
p->mode = IOR_IRUSR | IOR_IWUSR | IOR_IRGRP | IOR_IWGRP;
p->openFlags = IOR_RDWR | IOR_CREAT;
p->api = strdup(default_aiori); p->api = strdup(default_aiori);
p->platform = strdup("HOST(OSTYPE)"); p->platform = strdup("HOST(OSTYPE)");
p->testFileName = strdup("testFile"); p->testFileName = strdup("testFile");
@ -205,8 +233,6 @@ void init_IOR_Param_t(IOR_param_t * p)
p->randomSeed = -1; p->randomSeed = -1;
p->incompressibleSeed = 573; p->incompressibleSeed = 573;
p->testComm = mpi_comm_world; p->testComm = mpi_comm_world;
p->setAlignment = 1;
p->lustre_start_ost = -1;
hdfs_user = getenv("USER"); hdfs_user = getenv("USER");
if (!hdfs_user) if (!hdfs_user)
@ -220,9 +246,6 @@ void init_IOR_Param_t(IOR_param_t * p)
p->URI = NULL; p->URI = NULL;
p->part_number = 0; p->part_number = 0;
p->beegfs_numTargets = -1;
p->beegfs_chunkSize = -1;
} }
static void static void
@ -253,8 +276,13 @@ DisplayOutliers(int numTasks,
strcpy(accessString, "read"); strcpy(accessString, "read");
} }
if (fabs(timerVal - mean) > (double)outlierThreshold) { if (fabs(timerVal - mean) > (double)outlierThreshold) {
fprintf(out_logfile, "WARNING: for task %d, %s %s is %f\n", char hostname[MAX_STR];
rank, accessString, timeString, timerVal); int ret = gethostname(hostname, MAX_STR);
if (ret != 0)
strcpy(hostname, "unknown");
fprintf(out_logfile, "WARNING: for %s, task %d, %s %s is %f\n",
hostname, rank, accessString, timeString, timerVal);
fprintf(out_logfile, " (mean=%f, stddev=%f)\n", mean, sd); fprintf(out_logfile, " (mean=%f, stddev=%f)\n", mean, sd);
fflush(out_logfile); fflush(out_logfile);
} }
@ -356,7 +384,7 @@ CompareBuffers(void *expectedBuffer,
if (verbose >= VERBOSE_3) { if (verbose >= VERBOSE_3) {
fprintf(out_logfile, fprintf(out_logfile,
"[%d] At file byte offset %lld, comparing %llu-byte transfer\n", "[%d] At file byte offset %lld, comparing %llu-byte transfer\n",
rank, test->offset, (long long)size); rank, (long long) offset, (long long)size);
} }
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
if (testbuf[i] != goodbuf[i]) { if (testbuf[i] != goodbuf[i]) {
@ -365,7 +393,7 @@ CompareBuffers(void *expectedBuffer,
fprintf(out_logfile, fprintf(out_logfile,
"[%d] At transfer buffer #%lld, index #%lld (file byte offset %lld):\n", "[%d] At transfer buffer #%lld, index #%lld (file byte offset %lld):\n",
rank, transferCount - 1, (long long)i, rank, transferCount - 1, (long long)i,
test->offset + (long long) offset +
(IOR_size_t) (i * sizeof(IOR_size_t))); (IOR_size_t) (i * sizeof(IOR_size_t)));
fprintf(out_logfile, "[%d] %s0x", rank, bufferLabel1); fprintf(out_logfile, "[%d] %s0x", rank, bufferLabel1);
fprintf(out_logfile, "%016llx\n", goodbuf[i]); fprintf(out_logfile, "%016llx\n", goodbuf[i]);
@ -381,10 +409,10 @@ CompareBuffers(void *expectedBuffer,
} }
} else if (verbose >= VERBOSE_5 && i % 4 == 0) { } else if (verbose >= VERBOSE_5 && i % 4 == 0) {
fprintf(out_logfile, fprintf(out_logfile,
"[%d] PASSED offset = %lld bytes, transfer %lld\n", "[%d] PASSED offset = %lu bytes, transfer %lld\n",
rank, rank,
((i * sizeof(unsigned long long)) + ((i * sizeof(unsigned long long)) +
test->offset), transferCount); offset), transferCount);
fprintf(out_logfile, "[%d] GOOD %s0x", rank, bufferLabel1); fprintf(out_logfile, "[%d] GOOD %s0x", rank, bufferLabel1);
for (j = 0; j < 4; j++) for (j = 0; j < 4; j++)
fprintf(out_logfile, "%016llx ", goodbuf[i + j]); fprintf(out_logfile, "%016llx ", goodbuf[i + j]);
@ -407,8 +435,8 @@ CompareBuffers(void *expectedBuffer,
"%lld errors between buffer indices %lld and %lld.\n", "%lld errors between buffer indices %lld and %lld.\n",
(long long)errorCount, (long long)first, (long long)errorCount, (long long)first,
(long long)last); (long long)last);
fprintf(out_logfile, "[%d] File byte offset = %lld:\n", rank, fprintf(out_logfile, "[%d] File byte offset = %lu:\n", rank,
((first * sizeof(unsigned long long)) + test->offset)); ((first * sizeof(unsigned long long)) + offset));
fprintf(out_logfile, "[%d] %s0x", rank, bufferLabel1); fprintf(out_logfile, "[%d] %s0x", rank, bufferLabel1);
for (j = first; j < length && j < first + 4; j++) for (j = first; j < length && j < first + 4; j++)
@ -503,8 +531,6 @@ void AllocResults(IOR_test_t *test)
if (test->results != NULL) if (test->results != NULL)
return; return;
IOR_param_t * params = & test->params;
reps = test->params.repetitions; reps = test->params.repetitions;
test->results = (IOR_results_t *) safeMalloc(sizeof(IOR_results_t) * reps); test->results = (IOR_results_t *) safeMalloc(sizeof(IOR_results_t) * reps);
} }
@ -824,15 +850,15 @@ static char *PrependDir(IOR_param_t * test, char *rootDir)
sprintf(dir + i + 1, "%d", (rank + rankOffset) % test->numTasks); sprintf(dir + i + 1, "%d", (rank + rankOffset) % test->numTasks);
/* dir doesn't exist, so create */ /* dir doesn't exist, so create */
if (backend->access(dir, F_OK, test) != 0) { if (backend->access(dir, F_OK, test->backend_options) != 0) {
if (backend->mkdir(dir, S_IRWXU, test) < 0) { if (backend->mkdir(dir, S_IRWXU, test->backend_options) < 0) {
ERRF("cannot create directory: %s", dir); ERRF("cannot create directory: %s", dir);
} }
/* check if correct permissions */ /* check if correct permissions */
} else if (backend->access(dir, R_OK, test) != 0 || } else if (backend->access(dir, R_OK, test->backend_options) != 0 ||
backend->access(dir, W_OK, test) != 0 || backend->access(dir, W_OK, test->backend_options) != 0 ||
backend->access(dir, X_OK, test) != 0) { backend->access(dir, X_OK, test->backend_options) != 0) {
ERRF("invalid directory permissions: %s", dir); ERRF("invalid directory permissions: %s", dir);
} }
@ -893,7 +919,7 @@ ReduceIterResults(IOR_test_t *test, double *timer, const int rep, const int acce
* number of I/Os issued from that task; then reduce and display the * number of I/Os issued from that task; then reduce and display the
* minimum (best) latency achieved. So what is reported is the average * minimum (best) latency achieved. So what is reported is the average
* latency of all ops from a single task, then taking the minimum of * latency of all ops from a single task, then taking the minimum of
* that between all tasks. */ * that between all tasks. */
latency = (timer[3] - timer[2]) / (params->blockSize / params->transferSize); latency = (timer[3] - timer[2]) / (params->blockSize / params->transferSize);
MPI_CHECK(MPI_Reduce(&latency, &minlatency, 1, MPI_DOUBLE, MPI_CHECK(MPI_Reduce(&latency, &minlatency, 1, MPI_DOUBLE,
MPI_MIN, 0, testComm), "MPI_Reduce()"); MPI_MIN, 0, testComm), "MPI_Reduce()");
@ -919,24 +945,24 @@ static void RemoveFile(char *testFileName, int filePerProc, IOR_param_t * test)
rankOffset = 0; rankOffset = 0;
GetTestFileName(testFileName, test); GetTestFileName(testFileName, test);
} }
if (backend->access(testFileName, F_OK, test) == 0) { if (backend->access(testFileName, F_OK, test->backend_options) == 0) {
if (verbose >= VERBOSE_3) { if (verbose >= VERBOSE_3) {
fprintf(out_logfile, "task %d removing %s\n", rank, fprintf(out_logfile, "task %d removing %s\n", rank,
testFileName); testFileName);
} }
backend->delete(testFileName, test); backend->delete(testFileName, test->backend_options);
} }
if (test->reorderTasksRandom == TRUE) { if (test->reorderTasksRandom == TRUE) {
rankOffset = tmpRankOffset; rankOffset = tmpRankOffset;
GetTestFileName(testFileName, test); GetTestFileName(testFileName, test);
} }
} else { } else {
if ((rank == 0) && (backend->access(testFileName, F_OK, test) == 0)) { if ((rank == 0) && (backend->access(testFileName, F_OK, test->backend_options) == 0)) {
if (verbose >= VERBOSE_3) { if (verbose >= VERBOSE_3) {
fprintf(out_logfile, "task %d removing %s\n", rank, fprintf(out_logfile, "task %d removing %s\n", rank,
testFileName); testFileName);
} }
backend->delete(testFileName, test); backend->delete(testFileName, test->backend_options);
} }
} }
} }
@ -1231,7 +1257,7 @@ static void TestIoSys(IOR_test_t *test)
double startTime; double startTime;
int pretendRank; int pretendRank;
int rep; int rep;
void *fd; aiori_fd_t *fd;
MPI_Group orig_group, new_group; MPI_Group orig_group, new_group;
int range[3]; int range[3];
IOR_offset_t dataMoved; /* for data rate calculation */ IOR_offset_t dataMoved; /* for data rate calculation */
@ -1257,7 +1283,7 @@ static void TestIoSys(IOR_test_t *test)
return; return;
} }
if (rank == 0 && verbose >= VERBOSE_1) { if (rank == 0 && verbose >= VERBOSE_1) {
fprintf(out_logfile, "Participating tasks: %d\n", params->numTasks); fprintf(out_logfile, "Participating tasks : %d\n", params->numTasks);
fflush(out_logfile); fflush(out_logfile);
} }
if (rank == 0 && params->reorderTasks == TRUE && verbose >= VERBOSE_1) { if (rank == 0 && params->reorderTasks == TRUE && verbose >= VERBOSE_1) {
@ -1265,7 +1291,6 @@ static void TestIoSys(IOR_test_t *test)
"Using reorderTasks '-C' (useful to avoid read cache in client)\n"); "Using reorderTasks '-C' (useful to avoid read cache in client)\n");
fflush(out_logfile); fflush(out_logfile);
} }
backend = params->backend;
/* show test setup */ /* show test setup */
if (rank == 0 && verbose >= VERBOSE_0) if (rank == 0 && verbose >= VERBOSE_0)
ShowSetup(params); ShowSetup(params);
@ -1277,7 +1302,7 @@ static void TestIoSys(IOR_test_t *test)
/* IO Buffer Setup */ /* IO Buffer Setup */
if (params->setTimeStampSignature) { // initialize the buffer properly if (params->setTimeStampSignature) { // initialize the buffer properly
params->timeStampSignatureValue = (unsigned int)params->setTimeStampSignature; params->timeStampSignatureValue = (unsigned int) params->setTimeStampSignature;
} }
XferBuffersSetup(&ioBuffers, params, pretendRank); XferBuffersSetup(&ioBuffers, params, pretendRank);
reseed_incompressible_prng = TRUE; // reset pseudo random generator, necessary to guarantee the next call to FillBuffer produces the same value as it is right now reseed_incompressible_prng = TRUE; // reset pseudo random generator, necessary to guarantee the next call to FillBuffer produces the same value as it is right now
@ -1299,12 +1324,12 @@ static void TestIoSys(IOR_test_t *test)
} }
params->timeStampSignatureValue = params->timeStampSignatureValue =
(unsigned int)currentTime; (unsigned int)currentTime;
if (verbose >= VERBOSE_2) { }
fprintf(out_logfile, if (verbose >= VERBOSE_2) {
"Using Time Stamp %u (0x%x) for Data Signature\n", fprintf(out_logfile,
params->timeStampSignatureValue, "Using Time Stamp %u (0x%x) for Data Signature\n",
params->timeStampSignatureValue); params->timeStampSignatureValue,
} params->timeStampSignatureValue);
} }
if (rep == 0 && verbose >= VERBOSE_0) { if (rep == 0 && verbose >= VERBOSE_0) {
PrintTableHeader(); PrintTableHeader();
@ -1339,7 +1364,7 @@ static void TestIoSys(IOR_test_t *test)
MPI_CHECK(MPI_Barrier(testComm), "barrier error"); MPI_CHECK(MPI_Barrier(testComm), "barrier error");
params->open = WRITE; params->open = WRITE;
timer[0] = GetTimeStamp(); timer[0] = GetTimeStamp();
fd = backend->create(testFileName, params); fd = backend->create(testFileName, IOR_WRONLY | IOR_CREAT | IOR_TRUNC, params->backend_options);
timer[1] = GetTimeStamp(); timer[1] = GetTimeStamp();
if (params->intraTestBarriers) if (params->intraTestBarriers)
MPI_CHECK(MPI_Barrier(testComm), MPI_CHECK(MPI_Barrier(testComm),
@ -1360,14 +1385,14 @@ static void TestIoSys(IOR_test_t *test)
MPI_CHECK(MPI_Barrier(testComm), MPI_CHECK(MPI_Barrier(testComm),
"barrier error"); "barrier error");
timer[4] = GetTimeStamp(); timer[4] = GetTimeStamp();
backend->close(fd, params); backend->close(fd, params->backend_options);
timer[5] = GetTimeStamp(); timer[5] = GetTimeStamp();
MPI_CHECK(MPI_Barrier(testComm), "barrier error"); MPI_CHECK(MPI_Barrier(testComm), "barrier error");
/* get the size of the file just written */ /* get the size of the file just written */
results[rep].write.aggFileSizeFromStat = results[rep].write.aggFileSizeFromStat =
backend->get_file_size(params, testComm, testFileName); backend->get_file_size(params->backend_options, testComm, testFileName);
/* check if stat() of file doesn't equal expected file size, /* check if stat() of file doesn't equal expected file size,
use actual amount of byte moved */ use actual amount of byte moved */
@ -1413,9 +1438,9 @@ static void TestIoSys(IOR_test_t *test)
GetTestFileName(testFileName, params); GetTestFileName(testFileName, params);
params->open = WRITECHECK; params->open = WRITECHECK;
fd = backend->open(testFileName, params); fd = backend->open(testFileName, IOR_RDONLY, params->backend_options);
dataMoved = WriteOrRead(params, &results[rep], fd, WRITECHECK, &ioBuffers); dataMoved = WriteOrRead(params, &results[rep], fd, WRITECHECK, &ioBuffers);
backend->close(fd, params); backend->close(fd, params->backend_options);
rankOffset = 0; rankOffset = 0;
} }
/* /*
@ -1485,7 +1510,7 @@ static void TestIoSys(IOR_test_t *test)
MPI_CHECK(MPI_Barrier(testComm), "barrier error"); MPI_CHECK(MPI_Barrier(testComm), "barrier error");
params->open = READ; params->open = READ;
timer[0] = GetTimeStamp(); timer[0] = GetTimeStamp();
fd = backend->open(testFileName, params); fd = backend->open(testFileName, IOR_RDONLY, params->backend_options);
timer[1] = GetTimeStamp(); timer[1] = GetTimeStamp();
if (params->intraTestBarriers) if (params->intraTestBarriers)
MPI_CHECK(MPI_Barrier(testComm), MPI_CHECK(MPI_Barrier(testComm),
@ -1502,12 +1527,12 @@ static void TestIoSys(IOR_test_t *test)
MPI_CHECK(MPI_Barrier(testComm), MPI_CHECK(MPI_Barrier(testComm),
"barrier error"); "barrier error");
timer[4] = GetTimeStamp(); timer[4] = GetTimeStamp();
backend->close(fd, params); backend->close(fd, params->backend_options);
timer[5] = GetTimeStamp(); timer[5] = GetTimeStamp();
/* get the size of the file just read */ /* get the size of the file just read */
results[rep].read.aggFileSizeFromStat = results[rep].read.aggFileSizeFromStat =
backend->get_file_size(params, testComm, backend->get_file_size(params->backend_options, testComm,
testFileName); testFileName);
/* check if stat() of file doesn't equal expected file size, /* check if stat() of file doesn't equal expected file size,
@ -1588,8 +1613,6 @@ static void ValidateTests(IOR_param_t * test)
ERR("block size must be non-negative integer"); ERR("block size must be non-negative integer");
if ((test->transferSize % sizeof(IOR_size_t)) != 0) if ((test->transferSize % sizeof(IOR_size_t)) != 0)
ERR("transfer size must be a multiple of access size"); ERR("transfer size must be a multiple of access size");
if (test->setAlignment < 0)
ERR("alignment must be non-negative integer");
if (test->transferSize < 0) if (test->transferSize < 0)
ERR("transfer size must be non-negative integer"); ERR("transfer size must be non-negative integer");
if (test->transferSize == 0) { if (test->transferSize == 0) {
@ -1614,11 +1637,6 @@ static void ValidateTests(IOR_param_t * test)
&& (test->blockSize < sizeof(IOR_size_t) && (test->blockSize < sizeof(IOR_size_t)
|| test->transferSize < sizeof(IOR_size_t))) || test->transferSize < sizeof(IOR_size_t)))
ERR("block/transfer size may not be smaller than IOR_size_t for NCMPI"); ERR("block/transfer size may not be smaller than IOR_size_t for NCMPI");
if ((test->useFileView == TRUE)
&& (sizeof(MPI_Aint) < 8) /* used for 64-bit datatypes */
&&((test->numTasks * test->blockSize) >
(2 * (IOR_offset_t) GIBIBYTE)))
ERR("segment size must be < 2GiB");
if ((strcasecmp(test->api, "POSIX") != 0) && test->singleXferAttempt) if ((strcasecmp(test->api, "POSIX") != 0) && test->singleXferAttempt)
WARN_RESET("retry only available in POSIX", WARN_RESET("retry only available in POSIX",
test, &defaults, singleXferAttempt); test, &defaults, singleXferAttempt);
@ -1626,43 +1644,13 @@ static void ValidateTests(IOR_param_t * test)
&& (strcasecmp(test->api, "MPIIO") != 0) && (strcasecmp(test->api, "MPIIO") != 0)
&& (strcasecmp(test->api, "MMAP") != 0) && (strcasecmp(test->api, "MMAP") != 0)
&& (strcasecmp(test->api, "HDFS") != 0) && (strcasecmp(test->api, "HDFS") != 0)
&& (strcasecmp(test->api, "DFS") != 0)
&& (strcasecmp(test->api, "DAOS") != 0)
&& (strcasecmp(test->api, "Gfarm") != 0) && (strcasecmp(test->api, "Gfarm") != 0)
&& (strcasecmp(test->api, "RADOS") != 0)) && test->fsync) && (strcasecmp(test->api, "RADOS") != 0)
&& (strcasecmp(test->api, "CEPHFS") != 0)) && test->fsync)
WARN_RESET("fsync() not supported in selected backend", WARN_RESET("fsync() not supported in selected backend",
test, &defaults, fsync); test, &defaults, fsync);
if ((strcasecmp(test->api, "MPIIO") != 0) && test->preallocate)
WARN_RESET("preallocation only available in MPIIO",
test, &defaults, preallocate);
if ((strcasecmp(test->api, "MPIIO") != 0) && test->useFileView)
WARN_RESET("file view only available in MPIIO",
test, &defaults, useFileView);
if ((strcasecmp(test->api, "MPIIO") != 0) && test->useSharedFilePointer)
WARN_RESET("shared file pointer only available in MPIIO",
test, &defaults, useSharedFilePointer);
if ((strcasecmp(test->api, "MPIIO") == 0) && test->useSharedFilePointer)
WARN_RESET("shared file pointer not implemented",
test, &defaults, useSharedFilePointer);
if ((strcasecmp(test->api, "MPIIO") != 0) && test->useStridedDatatype)
WARN_RESET("strided datatype only available in MPIIO",
test, &defaults, useStridedDatatype);
if ((strcasecmp(test->api, "MPIIO") == 0) && test->useStridedDatatype)
WARN_RESET("strided datatype not implemented",
test, &defaults, useStridedDatatype);
if ((strcasecmp(test->api, "MPIIO") == 0)
&& test->useStridedDatatype && (test->blockSize < sizeof(IOR_size_t)
|| test->transferSize <
sizeof(IOR_size_t)))
ERR("need larger file size for strided datatype in MPIIO");
if ((strcasecmp(test->api, "POSIX") == 0) && test->showHints)
WARN_RESET("hints not available in POSIX",
test, &defaults, showHints);
if ((strcasecmp(test->api, "POSIX") == 0) && test->collective)
WARN_RESET("collective not available in POSIX",
test, &defaults, collective);
if ((strcasecmp(test->api, "MMAP") == 0) && test->fsyncPerWrite
&& (test->transferSize & (sysconf(_SC_PAGESIZE) - 1)))
ERR("transfer size must be aligned with PAGESIZE for MMAP with fsyncPerWrite");
/* parameter consitency */ /* parameter consitency */
if (test->reorderTasks == TRUE && test->reorderTasksRandom == TRUE) if (test->reorderTasks == TRUE && test->reorderTasksRandom == TRUE)
ERR("Both Constant and Random task re-ordering specified. Choose one and resubmit"); ERR("Both Constant and Random task re-ordering specified. Choose one and resubmit");
@ -1676,51 +1664,19 @@ static void ValidateTests(IOR_param_t * test)
ERR("random offset not available with read check option (use write check)"); ERR("random offset not available with read check option (use write check)");
if (test->randomOffset && test->storeFileOffset) if (test->randomOffset && test->storeFileOffset)
ERR("random offset not available with store file offset option)"); ERR("random offset not available with store file offset option)");
if ((strcasecmp(test->api, "MPIIO") == 0) && test->randomOffset
&& test->collective)
ERR("random offset not available with collective MPIIO");
if ((strcasecmp(test->api, "MPIIO") == 0) && test->randomOffset
&& test->useFileView)
ERR("random offset not available with MPIIO fileviews");
if ((strcasecmp(test->api, "HDF5") == 0) && test->randomOffset) if ((strcasecmp(test->api, "HDF5") == 0) && test->randomOffset)
ERR("random offset not available with HDF5"); ERR("random offset not available with HDF5");
if ((strcasecmp(test->api, "NCMPI") == 0) && test->randomOffset) if ((strcasecmp(test->api, "NCMPI") == 0) && test->randomOffset)
ERR("random offset not available with NCMPI"); ERR("random offset not available with NCMPI");
if ((strcasecmp(test->api, "HDF5") != 0) && test->individualDataSets)
WARN_RESET("individual datasets only available in HDF5",
test, &defaults, individualDataSets);
if ((strcasecmp(test->api, "HDF5") == 0) && test->individualDataSets)
WARN_RESET("individual data sets not implemented",
test, &defaults, individualDataSets);
if ((strcasecmp(test->api, "NCMPI") == 0) && test->filePerProc) if ((strcasecmp(test->api, "NCMPI") == 0) && test->filePerProc)
ERR("file-per-proc not available in current NCMPI"); ERR("file-per-proc not available in current NCMPI");
if (test->noFill) {
if (strcasecmp(test->api, "HDF5") != 0) {
ERR("'no fill' option only available in HDF5");
} else {
/* check if hdf5 available */
#if defined (H5_VERS_MAJOR) && defined (H5_VERS_MINOR)
/* no-fill option not available until hdf5-1.6.x */
#if (H5_VERS_MAJOR > 0 && H5_VERS_MINOR > 5)
;
#else
ERRF("'no fill' option not available in %s",
test->apiVersion);
#endif
#else
WARN("unable to determine HDF5 version for 'no fill' usage");
#endif
}
}
if (test->useExistingTestFile && test->lustre_set_striping)
ERR("Lustre stripe options are incompatible with useExistingTestFile");
backend = test->backend;
ior_set_xfer_hints(test);
/* allow the backend to validate the options */ /* allow the backend to validate the options */
if(test->backend->check_params){ if(test->backend->check_params){
int check = test->backend->check_params(test); int check = test->backend->check_params(test->backend_options);
if (check == 0){ if (check){
ERR("The backend returned that the test parameters are invalid."); ERR("The backend returned that the test parameters are invalid.");
} }
} }
@ -1733,8 +1689,7 @@ static void ValidateTests(IOR_param_t * test)
* @param pretendRank int pretended Rank for shifting the offsest corectly * @param pretendRank int pretended Rank for shifting the offsest corectly
* @return IOR_offset_t * @return IOR_offset_t
*/ */
static IOR_offset_t *GetOffsetArraySequential(IOR_param_t * test, IOR_offset_t *GetOffsetArraySequential(IOR_param_t * test, int pretendRank)
int pretendRank)
{ {
IOR_offset_t i, j, k = 0; IOR_offset_t i, j, k = 0;
IOR_offset_t offsets; IOR_offset_t offsets;
@ -1783,8 +1738,7 @@ static IOR_offset_t *GetOffsetArraySequential(IOR_param_t * test,
* @return IOR_offset_t * @return IOR_offset_t
* @return * @return
*/ */
static IOR_offset_t *GetOffsetArrayRandom(IOR_param_t * test, int pretendRank, IOR_offset_t *GetOffsetArrayRandom(IOR_param_t * test, int pretendRank, int access)
int access)
{ {
int seed; int seed;
IOR_offset_t i, value, tmp; IOR_offset_t i, value, tmp;
@ -1854,7 +1808,7 @@ static IOR_offset_t *GetOffsetArrayRandom(IOR_param_t * test, int pretendRank,
} }
static IOR_offset_t WriteOrReadSingle(IOR_offset_t pairCnt, IOR_offset_t *offsetArray, int pretendRank, static IOR_offset_t WriteOrReadSingle(IOR_offset_t pairCnt, IOR_offset_t *offsetArray, int pretendRank,
IOR_offset_t * transferCount, int * errors, IOR_param_t * test, int * fd, IOR_io_buffers* ioBuffers, int access){ IOR_offset_t * transferCount, int * errors, IOR_param_t * test, aiori_fd_t * fd, IOR_io_buffers* ioBuffers, int access){
IOR_offset_t amtXferred = 0; IOR_offset_t amtXferred = 0;
IOR_offset_t transfer; IOR_offset_t transfer;
@ -1862,26 +1816,26 @@ static IOR_offset_t WriteOrReadSingle(IOR_offset_t pairCnt, IOR_offset_t *offset
void *checkBuffer = ioBuffers->checkBuffer; void *checkBuffer = ioBuffers->checkBuffer;
void *readCheckBuffer = ioBuffers->readCheckBuffer; void *readCheckBuffer = ioBuffers->readCheckBuffer;
test->offset = offsetArray[pairCnt]; IOR_offset_t offset = offsetArray[pairCnt]; // this looks inappropriate
transfer = test->transferSize; transfer = test->transferSize;
if (access == WRITE) { if (access == WRITE) {
/* fills each transfer with a unique pattern /* fills each transfer with a unique pattern
* containing the offset into the file */ * containing the offset into the file */
if (test->storeFileOffset == TRUE) { if (test->storeFileOffset == TRUE) {
FillBuffer(buffer, test, test->offset, pretendRank); FillBuffer(buffer, test, offset, pretendRank);
} }
amtXferred = amtXferred = backend->xfer(access, fd, buffer, transfer, offset, test->backend_options);
backend->xfer(access, fd, buffer, transfer, test);
if (amtXferred != transfer) if (amtXferred != transfer)
ERR("cannot write to file"); ERR("cannot write to file");
if (test->fsyncPerWrite)
backend->fsync(fd, test->backend_options);
if (test->interIODelay > 0){ if (test->interIODelay > 0){
struct timespec wait = {test->interIODelay / 1000 / 1000, 1000l * (test->interIODelay % 1000000)}; struct timespec wait = {test->interIODelay / 1000 / 1000, 1000l * (test->interIODelay % 1000000)};
nanosleep( & wait, NULL); nanosleep( & wait, NULL);
} }
} else if (access == READ) { } else if (access == READ) {
amtXferred = amtXferred = backend->xfer(access, fd, buffer, transfer, offset, test->backend_options);
backend->xfer(access, fd, buffer, transfer, test);
if (amtXferred != transfer) if (amtXferred != transfer)
ERR("cannot read from file"); ERR("cannot read from file");
if (test->interIODelay > 0){ if (test->interIODelay > 0){
@ -1892,10 +1846,10 @@ static IOR_offset_t WriteOrReadSingle(IOR_offset_t pairCnt, IOR_offset_t *offset
memset(checkBuffer, 'a', transfer); memset(checkBuffer, 'a', transfer);
if (test->storeFileOffset == TRUE) { if (test->storeFileOffset == TRUE) {
FillBuffer(readCheckBuffer, test, test->offset, pretendRank); FillBuffer(readCheckBuffer, test, offset, pretendRank);
} }
amtXferred = backend->xfer(access, fd, checkBuffer, transfer, test); amtXferred = backend->xfer(access, fd, checkBuffer, transfer, offset, test->backend_options);
if (amtXferred != transfer) if (amtXferred != transfer)
ERR("cannot read from file write check"); ERR("cannot read from file write check");
(*transferCount)++; (*transferCount)++;
@ -1905,12 +1859,12 @@ static IOR_offset_t WriteOrReadSingle(IOR_offset_t pairCnt, IOR_offset_t *offset
} else if (access == READCHECK) { } else if (access == READCHECK) {
memset(checkBuffer, 'a', transfer); memset(checkBuffer, 'a', transfer);
amtXferred = backend->xfer(access, fd, checkBuffer, transfer, test); amtXferred = backend->xfer(access, fd, checkBuffer, transfer, offset, test->backend_options);
if (amtXferred != transfer){ if (amtXferred != transfer){
ERR("cannot read from file"); ERR("cannot read from file");
} }
if (test->storeFileOffset == TRUE) { if (test->storeFileOffset == TRUE) {
FillBuffer(readCheckBuffer, test, test->offset, pretendRank); FillBuffer(readCheckBuffer, test, offset, pretendRank);
} }
*errors += CompareBuffers(readCheckBuffer, checkBuffer, transfer, *transferCount, test, READCHECK); *errors += CompareBuffers(readCheckBuffer, checkBuffer, transfer, *transferCount, test, READCHECK);
} }
@ -1922,7 +1876,7 @@ static IOR_offset_t WriteOrReadSingle(IOR_offset_t pairCnt, IOR_offset_t *offset
* out the data to each block in transfer sizes, until the remainder left is 0. * out the data to each block in transfer sizes, until the remainder left is 0.
*/ */
static IOR_offset_t WriteOrRead(IOR_param_t *test, IOR_results_t *results, static IOR_offset_t WriteOrRead(IOR_param_t *test, IOR_results_t *results,
void *fd, const int access, IOR_io_buffers *ioBuffers) aiori_fd_t *fd, const int access, IOR_io_buffers *ioBuffers)
{ {
int errors = 0; int errors = 0;
IOR_offset_t transferCount = 0; IOR_offset_t transferCount = 0;
@ -1955,6 +1909,13 @@ static IOR_offset_t WriteOrRead(IOR_param_t *test, IOR_results_t *results,
hitStonewall = ((test->deadlineForStonewalling != 0 hitStonewall = ((test->deadlineForStonewalling != 0
&& (GetTimeStamp() - startForStonewall) && (GetTimeStamp() - startForStonewall)
> test->deadlineForStonewalling)) || (test->stoneWallingWearOutIterations != 0 && pairCnt == test->stoneWallingWearOutIterations) ; > test->deadlineForStonewalling)) || (test->stoneWallingWearOutIterations != 0 && pairCnt == test->stoneWallingWearOutIterations) ;
if ( test->collective && test->deadlineForStonewalling ) {
// if collective-mode, you'll get a HANG, if some rank 'accidentally' leave this loop
// it absolutely must be an 'all or none':
MPI_CHECK(MPI_Bcast(&hitStonewall, 1, MPI_INT, 0, MPI_COMM_WORLD), "hitStonewall broadcast failed");
}
} }
if (test->stoneWallingWearOut){ if (test->stoneWallingWearOut){
if (verbose >= VERBOSE_1){ if (verbose >= VERBOSE_1){
@ -1995,7 +1956,7 @@ static IOR_offset_t WriteOrRead(IOR_param_t *test, IOR_results_t *results,
free(offsetArray); free(offsetArray);
if (access == WRITE && test->fsync == TRUE) { if (access == WRITE && test->fsync == TRUE) {
backend->fsync(fd, test); /*fsync after all accesses */ backend->fsync(fd, test->backend_options); /*fsync after all accesses */
} }
return (dataMoved); return (dataMoved);
} }

View File

@ -35,10 +35,11 @@
typedef void *rados_t; typedef void *rados_t;
typedef void *rados_ioctx_t; typedef void *rados_ioctx_t;
#endif #endif
#include "option.h" #include "option.h"
#include "iordef.h" #include "iordef.h"
#include "aiori.h"
#define ISPOWEROFTWO(x) ((x != 0) && !(x & (x - 1)))
/******************** DATA Packet Type ***************************************/ /******************** DATA Packet Type ***************************************/
/* Holds the types of data packets: generic, offset, timestamp, incompressible */ /* Holds the types of data packets: generic, offset, timestamp, incompressible */
@ -79,29 +80,25 @@ typedef struct IO_BUFFERS
* USER_GUIDE * USER_GUIDE
*/ */
struct ior_aiori;
typedef struct typedef struct
{ {
const struct ior_aiori * backend; const struct ior_aiori * backend;
char * debug; /* debug info string */ char * debug; /* debug info string */
unsigned int mode; /* file permissions */
unsigned int openFlags; /* open flags (see also <open>) */
int referenceNumber; /* user supplied reference number */ int referenceNumber; /* user supplied reference number */
char * api; /* API for I/O */ char * api; /* API for I/O */
char * apiVersion; /* API version */ char * apiVersion; /* API version */
char * platform; /* platform type */ char * platform; /* platform type */
char * testFileName; /* full name for test */ char * testFileName; /* full name for test */
char * testFileName_fppReadCheck;/* filename for fpp read check */
char * hintsFileName; /* full name for hints file */
char * options; /* options string */ char * options; /* options string */
// intermediate options // intermediate options
int collective; /* collective I/O */
MPI_Comm testComm; /* MPI communicator */
int dryRun; /* do not perform any I/Os just run evtl. inputs print dummy output */ int dryRun; /* do not perform any I/Os just run evtl. inputs print dummy output */
int dualMount; /* dual mount points */ int dualMount; /* dual mount points */
int numTasks; /* number of tasks for test */ int numTasks; /* number of tasks for test */
int numNodes; /* number of nodes for test */ int numNodes; /* number of nodes for test */
int numTasksOnNode0; /* number of tasks on node 0 (usually all the same, but don't have to be, use with caution) */ int numTasksOnNode0; /* number of tasks on node 0 (usually all the same, but don't have to be, use with caution) */
int tasksBlockMapping; /* are the tasks in contiguous blocks across nodes or round-robin */ int tasksBlockMapping; /* are the tasks in contiguous blocks across nodes or round-robin */
int repetitions; /* number of repetitions of test */ int repetitions; /* number of repetitions of test */
int repCounter; /* rep counter */ int repCounter; /* rep counter */
int multiFile; /* multiple files */ int multiFile; /* multiple files */
@ -121,17 +118,11 @@ typedef struct
int keepFileWithError; /* don't delete the testfile with errors */ int keepFileWithError; /* don't delete the testfile with errors */
int errorFound; /* error found in data check */ int errorFound; /* error found in data check */
int quitOnError; /* quit code when error in check */ int quitOnError; /* quit code when error in check */
int collective; /* collective I/O */
IOR_offset_t segmentCount; /* number of segments (or HDF5 datasets) */ IOR_offset_t segmentCount; /* number of segments (or HDF5 datasets) */
IOR_offset_t blockSize; /* contiguous bytes to write per task */ IOR_offset_t blockSize; /* contiguous bytes to write per task */
IOR_offset_t transferSize; /* size of transfer in bytes */ IOR_offset_t transferSize; /* size of transfer in bytes */
IOR_offset_t offset; /* offset for read/write */
IOR_offset_t expectedAggFileSize; /* calculated aggregate file size */ IOR_offset_t expectedAggFileSize; /* calculated aggregate file size */
int preallocate; /* preallocate file size */
int useFileView; /* use MPI_File_set_view */
int useSharedFilePointer; /* use shared file pointer */
int useStridedDatatype; /* put strided access into datatype */
int showHints; /* show hints */
int summary_every_test; /* flag to print summary every test, not just at end */ int summary_every_test; /* flag to print summary every test, not just at end */
int uniqueDir; /* use unique directory for each fpp */ int uniqueDir; /* use unique directory for each fpp */
int useExistingTestFile; /* do not delete test file before access */ int useExistingTestFile; /* do not delete test file before access */
@ -146,7 +137,6 @@ typedef struct
int verbose; /* verbosity */ int verbose; /* verbosity */
int setTimeStampSignature; /* set time stamp signature */ int setTimeStampSignature; /* set time stamp signature */
unsigned int timeStampSignatureValue; /* value for time stamp signature */ unsigned int timeStampSignatureValue; /* value for time stamp signature */
void * fd_fppReadCheck; /* additional fd for fpp read check */
int randomSeed; /* random seed for write/read check */ int randomSeed; /* random seed for write/read check */
unsigned int incompressibleSeed; /* random seed for incompressible file creation */ unsigned int incompressibleSeed; /* random seed for incompressible file creation */
int randomOffset; /* access is to random offsets */ int randomOffset; /* access is to random offsets */
@ -164,16 +154,6 @@ typedef struct
int fsyncPerWrite; /* fsync() after each write */ int fsyncPerWrite; /* fsync() after each write */
int fsync; /* fsync() after write */ int fsync; /* fsync() after write */
/* MPI variables */
MPI_Comm testComm; /* MPI communicator */
MPI_Datatype transferType; /* datatype for transfer */
MPI_Datatype fileType; /* filetype for file view */
/* HDF5 variables */
int individualDataSets; /* datasets not shared by all procs */
int noFill; /* no fill in file creation */
IOR_offset_t setAlignment; /* alignment in bytes */
/* HDFS variables */ /* HDFS variables */
char * hdfs_user; /* copied from ENV, for now */ char * hdfs_user; /* copied from ENV, for now */
const char* hdfs_name_node; const char* hdfs_name_node;
@ -193,23 +173,10 @@ typedef struct
/* NCMPI variables */ /* NCMPI variables */
int var_id; /* variable id handle for data set */ int var_id; /* variable id handle for data set */
/* Lustre variables */
int lustre_stripe_count;
int lustre_stripe_size;
int lustre_start_ost;
int lustre_set_striping; /* flag that we need to set lustre striping */
int lustre_ignore_locks;
/* gpfs variables */
int gpfs_hint_access; /* use gpfs "access range" hint */
int gpfs_release_token; /* immediately release GPFS tokens after
creating or opening a file */
/* beegfs variables */
int beegfs_numTargets; /* number storage targets to use */
int beegfs_chunkSize; /* srtipe pattern for new files */
int id; /* test's unique ID */ int id; /* test's unique ID */
int intraTestBarriers; /* barriers between open/op and op/close */ int intraTestBarriers; /* barriers between open/op and op/close */
aiori_xfer_hint_t hints;
} IOR_param_t; } IOR_param_t;
/* each pointer for a single test */ /* each pointer for a single test */
@ -242,7 +209,7 @@ typedef struct IOR_test_t {
IOR_test_t *CreateTest(IOR_param_t *init_params, int test_num); IOR_test_t *CreateTest(IOR_param_t *init_params, int test_num);
void AllocResults(IOR_test_t *test); void AllocResults(IOR_test_t *test);
char * GetPlatformName(); char * GetPlatformName(void);
void init_IOR_Param_t(IOR_param_t *p); void init_IOR_Param_t(IOR_param_t *p);
/* /*

View File

@ -181,13 +181,13 @@ typedef long long int IOR_size_t;
/* display error message and terminate execution */ /* display error message and terminate execution */
#define ERR(MSG) do { \ #define ERR_ERRNO(MSG) do { \
ERRF("%s", MSG); \ ERRF("%s", MSG); \
} while (0) } while (0)
/* display a simple error message (i.e. errno is not set) and terminate execution */ /* display a simple error message (i.e. errno is not set) and terminate execution */
#define ERR_SIMPLE(MSG) do { \ #define ERR(MSG) do { \
fprintf(stdout, "ior ERROR: %s, (%s:%d)\n", \ fprintf(stdout, "ior ERROR: %s, (%s:%d)\n", \
MSG, __FILE__, __LINE__); \ MSG, __FILE__, __LINE__); \
fflush(stdout); \ fflush(stdout); \

View File

@ -166,8 +166,9 @@ static uid_t uid;
/* Use the POSIX backend by default */ /* Use the POSIX backend by default */
static const ior_aiori_t *backend; static const ior_aiori_t *backend;
static void * backend_options;
static IOR_param_t param; static aiori_xfer_hint_t hints;
static char * api = NULL;
/* This structure describes the processing status for stonewalling */ /* This structure describes the processing status for stonewalling */
typedef struct{ typedef struct{
@ -274,9 +275,9 @@ static void prep_testdir(int j, int dir_iter){
static void phase_end(){ static void phase_end(){
if (call_sync){ if (call_sync){
if(! backend->sync){ if(! backend->sync){
FAIL("Error, backend does not provide the sync method, but your requested to use sync."); FAIL("Error, backend does not provide the sync method, but you requested to use sync.\n");
} }
backend->sync(& param); backend->sync(backend_options);
} }
if (barriers) { if (barriers) {
@ -318,11 +319,11 @@ static void create_remove_dirs (const char *path, bool create, uint64_t itemNum)
VERBOSE(3,5,"create_remove_items_helper (dirs %s): curr_item is '%s'", operation, curr_item); VERBOSE(3,5,"create_remove_items_helper (dirs %s): curr_item is '%s'", operation, curr_item);
if (create) { if (create) {
if (backend->mkdir(curr_item, DIRMODE, &param) == -1) { if (backend->mkdir(curr_item, DIRMODE, backend_options) == -1) {
FAIL("unable to create directory %s", curr_item); FAIL("unable to create directory %s", curr_item);
} }
} else { } else {
if (backend->rmdir(curr_item, &param) == -1) { if (backend->rmdir(curr_item, backend_options) == -1) {
FAIL("unable to remove directory %s", curr_item); FAIL("unable to remove directory %s", curr_item);
} }
} }
@ -339,13 +340,13 @@ static void remove_file (const char *path, uint64_t itemNum) {
sprintf(curr_item, "%s/file.%s"LLU"", path, rm_name, itemNum); sprintf(curr_item, "%s/file.%s"LLU"", path, rm_name, itemNum);
VERBOSE(3,5,"create_remove_items_helper (non-dirs remove): curr_item is '%s'", curr_item); VERBOSE(3,5,"create_remove_items_helper (non-dirs remove): curr_item is '%s'", curr_item);
if (!(shared_file && rank != 0)) { if (!(shared_file && rank != 0)) {
backend->delete (curr_item, &param); backend->delete (curr_item, backend_options);
} }
} }
static void create_file (const char *path, uint64_t itemNum) { static void create_file (const char *path, uint64_t itemNum) {
char curr_item[MAX_PATHLEN]; char curr_item[MAX_PATHLEN];
void *aiori_fh; aiori_fd_t *aiori_fh = NULL;
if ( (itemNum % ITEM_COUNT==0 && (itemNum != 0))) { if ( (itemNum % ITEM_COUNT==0 && (itemNum != 0))) {
VERBOSE(3,5,"create file: "LLU"", itemNum); VERBOSE(3,5,"create file: "LLU"", itemNum);
@ -355,36 +356,32 @@ static void create_file (const char *path, uint64_t itemNum) {
sprintf(curr_item, "%s/file.%s"LLU"", path, mk_name, itemNum); sprintf(curr_item, "%s/file.%s"LLU"", path, mk_name, itemNum);
VERBOSE(3,5,"create_remove_items_helper (non-dirs create): curr_item is '%s'", curr_item); VERBOSE(3,5,"create_remove_items_helper (non-dirs create): curr_item is '%s'", curr_item);
if (collective_creates) { if (make_node) {
param.openFlags = IOR_WRONLY; int ret;
VERBOSE(3,5,"create_remove_items_helper : mknod..." );
ret = backend->mknod (curr_item);
if (ret != 0)
FAIL("unable to mknode file %s", curr_item);
return;
} else if (collective_creates) {
VERBOSE(3,5,"create_remove_items_helper (collective): open..." ); VERBOSE(3,5,"create_remove_items_helper (collective): open..." );
if (make_node) aiori_fh = backend->open (curr_item, IOR_WRONLY | IOR_CREAT, backend_options);
aiori_fh = backend->mknod (curr_item); if (NULL == aiori_fh)
else
aiori_fh = backend->open (curr_item, &param);
if (NULL == aiori_fh) {
FAIL("unable to open file %s", curr_item); FAIL("unable to open file %s", curr_item);
}
/* /*
* !collective_creates * !collective_creates
*/ */
} else { } else {
param.openFlags = IOR_CREAT | IOR_WRONLY; hints.filePerProc = !shared_file;
param.filePerProc = !shared_file;
param.mode = FILEMODE;
VERBOSE(3,5,"create_remove_items_helper (non-collective, shared): open..." ); VERBOSE(3,5,"create_remove_items_helper (non-collective, shared): open..." );
if (make_node) aiori_fh = backend->create (curr_item, IOR_WRONLY | IOR_CREAT, backend_options);
aiori_fh = backend->mknod (curr_item); if (NULL == aiori_fh)
else
aiori_fh = backend->create (curr_item, &param);
if (NULL == aiori_fh) {
FAIL("unable to create file %s", curr_item); FAIL("unable to create file %s", curr_item);
}
} }
if (write_bytes > 0) { if (write_bytes > 0) {
@ -394,17 +391,14 @@ static void create_file (const char *path, uint64_t itemNum) {
* According to Bill Loewe, writes are only done one time, so they are always at * According to Bill Loewe, writes are only done one time, so they are always at
* offset 0 (zero). * offset 0 (zero).
*/ */
param.offset = 0; hints.fsyncPerWrite = sync_file;
param.fsyncPerWrite = sync_file; if ( write_bytes != (size_t) backend->xfer (WRITE, aiori_fh, (IOR_size_t *) write_buffer, write_bytes, 0, backend_options)) {
if ( write_bytes != (size_t) backend->xfer (WRITE, aiori_fh, (IOR_size_t *) write_buffer, write_bytes, &param)) {
FAIL("unable to write file %s", curr_item); FAIL("unable to write file %s", curr_item);
} }
} }
VERBOSE(3,5,"create_remove_items_helper: close..." ); VERBOSE(3,5,"create_remove_items_helper: close..." );
backend->close (aiori_fh, backend_options);
if (!make_node)
backend->close (aiori_fh, &param);
} }
/* helper for creating/removing items */ /* helper for creating/removing items */
@ -448,20 +442,18 @@ void collective_helper(const int dirs, const int create, const char* path, uint6
VERBOSE(3,5,"create file: %s", curr_item); VERBOSE(3,5,"create file: %s", curr_item);
if (create) { if (create) {
void *aiori_fh; aiori_fd_t *aiori_fh;
//create files //create files
param.openFlags = IOR_WRONLY | IOR_CREAT; aiori_fh = backend->create (curr_item, IOR_WRONLY | IOR_CREAT, backend_options);
param.mode = FILEMODE;
aiori_fh = backend->create (curr_item, &param);
if (NULL == aiori_fh) { if (NULL == aiori_fh) {
FAIL("unable to create file %s", curr_item); FAIL("unable to create file %s", curr_item);
} }
backend->close (aiori_fh, &param); backend->close (aiori_fh, backend_options);
} else if (!(shared_file && rank != 0)) { } else if (!(shared_file && rank != 0)) {
//remove files //remove files
backend->delete (curr_item, &param); backend->delete (curr_item, backend_options);
} }
if(CHECK_STONE_WALL(progress)){ if(CHECK_STONE_WALL(progress)){
progress->items_done = i + 1; progress->items_done = i + 1;
@ -618,7 +610,7 @@ void mdtest_stat(const int random, const int dirs, const long dir_iter, const ch
/* below temp used to be hiername */ /* below temp used to be hiername */
VERBOSE(3,5,"mdtest_stat %4s: %s", (dirs ? "dir" : "file"), item); VERBOSE(3,5,"mdtest_stat %4s: %s", (dirs ? "dir" : "file"), item);
if (-1 == backend->stat (item, &buf, &param)) { if (-1 == backend->stat (item, &buf, backend_options)) {
FAIL("unable to stat %s %s", dirs ? "directory" : "file", item); FAIL("unable to stat %s %s", dirs ? "directory" : "file", item);
} }
} }
@ -629,14 +621,14 @@ void mdtest_stat(const int random, const int dirs, const long dir_iter, const ch
void mdtest_read(int random, int dirs, const long dir_iter, char *path) { void mdtest_read(int random, int dirs, const long dir_iter, char *path) {
uint64_t parent_dir, item_num = 0; uint64_t parent_dir, item_num = 0;
char item[MAX_PATHLEN], temp[MAX_PATHLEN]; char item[MAX_PATHLEN], temp[MAX_PATHLEN];
void *aiori_fh; aiori_fd_t *aiori_fh;
VERBOSE(1,-1,"Entering mdtest_read on %s", path ); VERBOSE(1,-1,"Entering mdtest_read on %s", path );
/* allocate read buffer */ /* allocate read buffer */
if (read_bytes > 0) { if (read_bytes > 0) {
read_buffer = (char *)malloc(read_bytes); int alloc_res = posix_memalign((void**)&read_buffer, sysconf(_SC_PAGESIZE), read_bytes);
if (read_buffer == NULL) { if (alloc_res) {
FAIL("out of memory"); FAIL("out of memory");
} }
@ -715,8 +707,7 @@ void mdtest_read(int random, int dirs, const long dir_iter, char *path) {
VERBOSE(3,5,"mdtest_read file: %s", item); VERBOSE(3,5,"mdtest_read file: %s", item);
/* open file for reading */ /* open file for reading */
param.openFlags = O_RDONLY; aiori_fh = backend->open (item, O_RDONLY, backend_options);
aiori_fh = backend->open (item, &param);
if (NULL == aiori_fh) { if (NULL == aiori_fh) {
FAIL("unable to open file %s", item); FAIL("unable to open file %s", item);
} }
@ -724,7 +715,7 @@ void mdtest_read(int random, int dirs, const long dir_iter, char *path) {
/* read file */ /* read file */
if (read_bytes > 0) { if (read_bytes > 0) {
read_buffer[0] = 42; /* use a random value to ensure that the read_buffer is now different from the expected buffer and read isn't sometimes NOOP */ read_buffer[0] = 42; /* use a random value to ensure that the read_buffer is now different from the expected buffer and read isn't sometimes NOOP */
if (read_bytes != (size_t) backend->xfer (READ, aiori_fh, (IOR_size_t *) read_buffer, read_bytes, &param)) { if (read_bytes != (size_t) backend->xfer (READ, aiori_fh, (IOR_size_t *) read_buffer, read_bytes, 0, backend_options)) {
FAIL("unable to read file %s", item); FAIL("unable to read file %s", item);
} }
if(verify_read){ if(verify_read){
@ -736,7 +727,7 @@ void mdtest_read(int random, int dirs, const long dir_iter, char *path) {
} }
/* close file */ /* close file */
backend->close (aiori_fh, &param); backend->close (aiori_fh, backend_options);
} }
} }
@ -1491,7 +1482,7 @@ void show_file_system_size(char *file_system) {
VERBOSE(1,-1,"Entering show_file_system_size on %s", file_system ); VERBOSE(1,-1,"Entering show_file_system_size on %s", file_system );
ret = backend->statfs (file_system, &stat_buf, &param); ret = backend->statfs (file_system, &stat_buf, backend_options);
if (0 != ret) { if (0 != ret) {
FAIL("unable to stat file system %s", file_system); FAIL("unable to stat file system %s", file_system);
} }
@ -1516,7 +1507,7 @@ void show_file_system_size(char *file_system) {
* 100; * 100;
if (realpath(file_system, real_path) == NULL) { if (realpath(file_system, real_path) == NULL) {
FAIL("unable to use realpath() on file system %s", file_system); WARN("unable to use realpath() on file system");
} }
@ -1555,9 +1546,6 @@ void display_freespace(char *testdirpath)
strcpy(dirpath, "."); strcpy(dirpath, ".");
} }
if (param.api && strcasecmp(param.api, "DFS") == 0)
return;
VERBOSE(3,5,"Before show_file_system_size, dirpath is '%s'", dirpath ); VERBOSE(3,5,"Before show_file_system_size, dirpath is '%s'", dirpath );
show_file_system_size(dirpath); show_file_system_size(dirpath);
VERBOSE(3,5, "After show_file_system_size, dirpath is '%s'\n", dirpath ); VERBOSE(3,5, "After show_file_system_size, dirpath is '%s'\n", dirpath );
@ -1579,7 +1567,7 @@ void create_remove_directory_tree(int create,
if (create) { if (create) {
VERBOSE(2,5,"Making directory '%s'", dir); VERBOSE(2,5,"Making directory '%s'", dir);
if (-1 == backend->mkdir (dir, DIRMODE, &param)) { if (-1 == backend->mkdir (dir, DIRMODE, backend_options)) {
fprintf(out_logfile, "error could not create directory '%s'\n", dir); fprintf(out_logfile, "error could not create directory '%s'\n", dir);
} }
#ifdef HAVE_LUSTRE_LUSTREAPI #ifdef HAVE_LUSTRE_LUSTREAPI
@ -1597,7 +1585,7 @@ void create_remove_directory_tree(int create,
if (!create) { if (!create) {
VERBOSE(2,5,"Remove directory '%s'", dir); VERBOSE(2,5,"Remove directory '%s'", dir);
if (-1 == backend->rmdir(dir, &param)) { if (-1 == backend->rmdir(dir, backend_options)) {
FAIL("Unable to remove directory %s", dir); FAIL("Unable to remove directory %s", dir);
} }
} }
@ -1613,7 +1601,7 @@ void create_remove_directory_tree(int create,
if (create) { if (create) {
VERBOSE(2,5,"Making directory '%s'", temp_path); VERBOSE(2,5,"Making directory '%s'", temp_path);
if (-1 == backend->mkdir(temp_path, DIRMODE, &param)) { if (-1 == backend->mkdir(temp_path, DIRMODE, backend_options)) {
FAIL("Unable to create directory %s", temp_path); FAIL("Unable to create directory %s", temp_path);
} }
} }
@ -1624,7 +1612,7 @@ void create_remove_directory_tree(int create,
if (!create) { if (!create) {
VERBOSE(2,5,"Remove directory '%s'", temp_path); VERBOSE(2,5,"Remove directory '%s'", temp_path);
if (-1 == backend->rmdir(temp_path, &param)) { if (-1 == backend->rmdir(temp_path, backend_options)) {
FAIL("Unable to remove directory %s", temp_path); FAIL("Unable to remove directory %s", temp_path);
} }
} }
@ -1653,8 +1641,8 @@ static void mdtest_iteration(int i, int j, MPI_Group testgroup, mdtest_results_t
prep_testdir(j, dir_iter); prep_testdir(j, dir_iter);
VERBOSE(2,5,"main (for j loop): making testdir, '%s'", testdir ); VERBOSE(2,5,"main (for j loop): making testdir, '%s'", testdir );
if ((rank < path_count) && backend->access(testdir, F_OK, &param) != 0) { if ((rank < path_count) && backend->access(testdir, F_OK, backend_options) != 0) {
if (backend->mkdir(testdir, DIRMODE, &param) != 0) { if (backend->mkdir(testdir, DIRMODE, backend_options) != 0) {
FAIL("Unable to create test directory %s", testdir); FAIL("Unable to create test directory %s", testdir);
} }
#ifdef HAVE_LUSTRE_LUSTREAPI #ifdef HAVE_LUSTRE_LUSTREAPI
@ -1834,9 +1822,9 @@ static void mdtest_iteration(int i, int j, MPI_Group testgroup, mdtest_results_t
for (int dir_iter = 0; dir_iter < directory_loops; dir_iter ++){ for (int dir_iter = 0; dir_iter < directory_loops; dir_iter ++){
prep_testdir(j, dir_iter); prep_testdir(j, dir_iter);
if ((rank < path_count) && backend->access(testdir, F_OK, &param) == 0) { if ((rank < path_count) && backend->access(testdir, F_OK, backend_options) == 0) {
//if (( rank == 0 ) && access(testdir, F_OK) == 0) { //if (( rank == 0 ) && access(testdir, F_OK) == 0) {
if (backend->rmdir(testdir, &param) == -1) { if (backend->rmdir(testdir, backend_options) == -1) {
FAIL("unable to remove directory %s", testdir); FAIL("unable to remove directory %s", testdir);
} }
} }
@ -1917,9 +1905,10 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE *
aiori_supported_apis(APIs, APIs_legacy, MDTEST); aiori_supported_apis(APIs, APIs_legacy, MDTEST);
char apiStr[1024]; char apiStr[1024];
sprintf(apiStr, "API for I/O [%s]", APIs); sprintf(apiStr, "API for I/O [%s]", APIs);
memset(& hints, 0, sizeof(hints));
option_help options [] = { option_help options [] = {
{'a', NULL, apiStr, OPTION_OPTIONAL_ARGUMENT, 's', & param.api}, {'a', NULL, apiStr, OPTION_OPTIONAL_ARGUMENT, 's', & api},
{'b', NULL, "branching factor of hierarchical directory structure", OPTION_OPTIONAL_ARGUMENT, 'd', & branch_factor}, {'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}, {'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}, {'B', NULL, "no barriers between phases", OPTION_OPTIONAL_ARGUMENT, 'd', & no_barriers},
@ -1964,17 +1953,26 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE *
}; };
options_all_t * global_options = airoi_create_all_module_options(options); options_all_t * global_options = airoi_create_all_module_options(options);
option_parse(argc, argv, global_options); option_parse(argc, argv, global_options);
updateParsedOptions(& param, global_options); backend = aiori_select(api);
if (backend == NULL)
ERR("Unrecognized I/O API");
backend_options = airoi_update_module_options(backend, global_options);
free(global_options->modules); free(global_options->modules);
free(global_options); free(global_options);
backend = param.backend;
MPI_Comm_rank(testComm, &rank); MPI_Comm_rank(testComm, &rank);
MPI_Comm_size(testComm, &size); MPI_Comm_size(testComm, &size);
if (backend->initialize) if (backend->initialize){
backend->initialize(); backend->initialize(backend_options);
}
if(backend->xfer_hints){
backend->xfer_hints(& hints);
}
if(backend->check_params){
backend->check_params(backend_options);
}
pid = getpid(); pid = getpid();
uid = getuid(); uid = getuid();
@ -2014,7 +2012,7 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE *
valid_tests(); valid_tests();
// option_print_current(options); // option_print_current(options);
VERBOSE(1,-1, "api : %s", param.api); VERBOSE(1,-1, "api : %s", api);
VERBOSE(1,-1, "barriers : %s", ( barriers ? "True" : "False" )); VERBOSE(1,-1, "barriers : %s", ( barriers ? "True" : "False" ));
VERBOSE(1,-1, "collective_creates : %s", ( collective_creates ? "True" : "False" )); VERBOSE(1,-1, "collective_creates : %s", ( collective_creates ? "True" : "False" ));
VERBOSE(1,-1, "create_only : %s", ( create_only ? "True" : "False" )); VERBOSE(1,-1, "create_only : %s", ( create_only ? "True" : "False" ));
@ -2127,8 +2125,8 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE *
/* allocate and initialize write buffer with # */ /* allocate and initialize write buffer with # */
if (write_bytes > 0) { if (write_bytes > 0) {
write_buffer = (char *)malloc(write_bytes); int alloc_res = posix_memalign((void**)&write_buffer, sysconf(_SC_PAGESIZE), write_bytes);
if (write_buffer == NULL) { if (alloc_res) {
FAIL("out of memory"); FAIL("out of memory");
} }
generate_memory_pattern(write_buffer, write_bytes); generate_memory_pattern(write_buffer, write_bytes);
@ -2146,8 +2144,8 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE *
} }
/* if directory does not exist, create it */ /* if directory does not exist, create it */
if ((rank < path_count) && backend->access(testdirpath, F_OK, &param) != 0) { if ((rank < path_count) && backend->access(testdirpath, F_OK, backend_options) != 0) {
if (backend->mkdir(testdirpath, DIRMODE, &param) != 0) { if (backend->mkdir(testdirpath, DIRMODE, backend_options) != 0) {
FAIL("Unable to create test directory path %s", testdirpath); FAIL("Unable to create test directory path %s", testdirpath);
} }
} }
@ -2265,8 +2263,9 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE *
free(rand_array); free(rand_array);
} }
if (backend->finalize) if (backend->finalize){
backend->finalize(NULL); backend->finalize(backend_options);
}
return summary_table; return summary_table;
} }

View File

@ -241,116 +241,141 @@ static void option_parse_token(char ** argv, int * flag_parsed_next, int * requi
} }
*flag_parsed_next = 0; *flag_parsed_next = 0;
for(int m = 0; m < opt_all->module_count; m++ ){ // just skip over the first dash so we don't have to handle it everywhere below
option_help * args = opt_all->modules[m].options; if(txt[0] != '-'){
if(args == NULL) continue; *error = 1;
// try to find matching option help return;
for(option_help * o = args; o->shortVar != 0 || o->longVar != 0 || o->help != NULL ; o++ ){ }
if( o->shortVar == 0 && o->longVar == 0 ){ txt++;
// section
continue; // support groups of multiple flags like -vvv or -vq
} for(int flag_index = 0; flag_index < strlen(txt); ++flag_index){
if ( (txt[0] == '-' && o->shortVar == txt[1]) || (strlen(txt) > 2 && txt[0] == '-' && txt[1] == '-' && o->longVar != NULL && strcmp(txt + 2, o->longVar) == 0)){ // don't loop looking for multiple flags if we already processed a long option
// now process the option. if(txt[0] == '-' && flag_index > 0)
switch(o->arg){ break;
case (OPTION_FLAG):{
assert(o->type == 'd'); for(int m = 0; m < opt_all->module_count; m++ ){
if(arg != NULL){ option_help * args = opt_all->modules[m].options;
int val = atoi(arg); if(args == NULL) continue;
(*(int*) o->variable) = (val < 0) ? 0 : val; // try to find matching option help
}else{ for(option_help * o = args; o->shortVar != 0 || o->longVar != 0 || o->help != NULL ; o++ ){
(*(int*) o->variable)++; if( o->shortVar == 0 && o->longVar == 0 ){
} // section
break; continue;
} }
case (OPTION_OPTIONAL_ARGUMENT): if ( (o->shortVar == txt[flag_index]) || (strlen(txt) > 2 && txt[0] == '-' && o->longVar != NULL && strcmp(txt + 1, o->longVar) == 0)){
case (OPTION_REQUIRED_ARGUMENT):{ // now process the option.
// check if next is an argument switch(o->arg){
if(arg == NULL){ case (OPTION_FLAG):{
if(o->shortVar == txt[1] && txt[2] != 0){ assert(o->type == 'd');
arg = & txt[2]; if(arg != NULL){
int val = atoi(arg);
(*(int*) o->variable) = (val < 0) ? 0 : val;
}else{ }else{
// simply take the next value as argument (*(int*) o->variable)++;
i++;
arg = argv[1];
*flag_parsed_next = 1;
} }
break;
} }
case (OPTION_OPTIONAL_ARGUMENT):
if(arg == NULL){ case (OPTION_REQUIRED_ARGUMENT):{
const char str[] = {o->shortVar, 0}; // check if next is an argument
printf("Error, argument missing for option %s\n", (o->longVar != NULL) ? o->longVar : str); if(arg == NULL){
exit(1); if(o->shortVar == txt[0] && txt[1] != 0){
} arg = & txt[1];
}else{
switch(o->type){ // simply take the next value as argument
case('p'):{ i++;
// call the function in the variable arg = argv[1];
void(*fp)() = o->variable; *flag_parsed_next = 1;
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'):{ if(arg == NULL){
(*(char **) o->variable) = strdup(arg); const char str[] = {o->shortVar, 0};
break; printf("Error, argument missing for option %s\n", (o->longVar != NULL) ? o->longVar : str);
exit(1);
} }
case('c'):{
(*(char *)o->variable) = arg[0]; switch(o->type){
if(strlen(arg) > 1){ case('p'):{
printf("Error, ignoring remainder of string for option %c (%s).\n", o->shortVar, o->longVar); // call the function in the variable
void(*fp)() = o->variable;
fp(arg);
break;
} }
break; case('F'):{
} *(double*) o->variable = atof(arg);
case('l'):{ break;
*(long long*) o->variable = string_to_bytes(arg); }
break; case('f'):{
} *(float*) o->variable = atof(arg);
case('u'):{ break;
*(uint64_t*) o->variable = string_to_bytes(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);
break;
} }
default:
printf("ERROR: Unknown option type %c\n", o->type);
} }
} }
} if(replaced_equal){
if(replaced_equal){ arg[-1] = '=';
arg[-1] = '='; }
}
if(o->arg == OPTION_REQUIRED_ARGUMENT){ if(o->arg == OPTION_REQUIRED_ARGUMENT){
(*requiredArgsSeen)++; (*requiredArgsSeen)++;
} }
return; return;
}
} }
} }
} }
if(strcmp(txt, "-h") == 0 || strcmp(txt, "--help") == 0){ if(strcmp(txt, "h") == 0 || strcmp(txt, "-help") == 0){
*print_help = 1; *print_help = 1;
}else{ }else{
*error = 1; *error = 1;
} }
} }
int option_parse_str(char*val, options_all_t * opt_all){
int flag_parsed_next;
int error = 0;
int requiredArgsSeen = 0;
int print_help = 0;
char * argv[2] = {val, NULL};
option_parse_token(argv, & flag_parsed_next, & requiredArgsSeen, opt_all, & error, & print_help);
return error;
}
int option_parse_key_value(char * key, char *val, options_all_t * opt_all){ int option_parse_key_value(char * key, char *val, options_all_t * opt_all){
int flag_parsed_next; int flag_parsed_next;
int error = 0; int error = 0;

View File

@ -23,10 +23,12 @@ typedef struct{
void * variable; void * variable;
} option_help; } option_help;
typedef struct aiori_mod_opt_t aiori_mod_opt_t;
typedef struct{ typedef struct{
char * prefix; // may be NULL to include it in the standard name char * prefix; // may be NULL to include it in the standard name
option_help * options; option_help * options;
void * defaults; // these default values are taken from the command line aiori_mod_opt_t * defaults; // these default values are taken from the command line
} option_module; } option_module;
typedef struct{ typedef struct{
@ -38,9 +40,9 @@ typedef struct{
int64_t string_to_bytes(char *size_str); int64_t string_to_bytes(char *size_str);
void option_print_current(option_help * args); void option_print_current(option_help * args);
//@return the number of parsed arguments //@return the number of parsed arguments
int option_parse(int argc, char ** argv, options_all_t * args); int option_parse(int argc, char ** argv, options_all_t * args);
int option_parse_str(char*val, options_all_t * opt_all);
/* Parse a single line */ /* Parse a single line */
int option_parse_key_value(char * key, char * value, options_all_t * opt_all); int option_parse_key_value(char * key, char * value, options_all_t * opt_all);

View File

@ -32,8 +32,6 @@
#include "option.h" #include "option.h"
#include "aiori.h" #include "aiori.h"
#define ISPOWEROFTWO(x) ((x != 0) && !(x & (x - 1)))
IOR_param_t initialTestParams; IOR_param_t initialTestParams;
option_help * createGlobalOptions(IOR_param_t * params); option_help * createGlobalOptions(IOR_param_t * params);
@ -63,24 +61,6 @@ static void CheckRunSettings(IOR_test_t *tests)
params->writeFile = TRUE; params->writeFile = TRUE;
} }
/* If only read or write is requested, then fix the default
* openFlags to not be open RDWR. It matters in the case
* of HDFS, which doesn't support opening RDWR.
* (We assume int-valued params are exclusively 0 or 1.)
*/
if ((params->openFlags & IOR_RDWR)
&& ((params->readFile | params->checkRead | params->checkWrite)
^ params->writeFile)) {
params->openFlags &= ~(IOR_RDWR);
if (params->readFile | params->checkRead) {
params->openFlags |= IOR_RDONLY;
params->openFlags &= ~(IOR_CREAT|IOR_EXCL);
}
else
params->openFlags |= IOR_WRONLY;
}
if(params->dualMount && !params->filePerProc) { if(params->dualMount && !params->filePerProc) {
MPI_CHECK(MPI_Abort(MPI_COMM_WORLD, -1), "Dual Mount can only be used with File Per Process"); MPI_CHECK(MPI_Abort(MPI_COMM_WORLD, -1), "Dual Mount can only be used with File Per Process");
} }
@ -143,8 +123,6 @@ void DecodeDirective(char *line, IOR_param_t *params, options_all_t * module_opt
params->testFileName = strdup(value); params->testFileName = strdup(value);
} else if (strcasecmp(option, "dualmount") == 0){ } else if (strcasecmp(option, "dualmount") == 0){
params->dualMount = atoi(value); params->dualMount = atoi(value);
} else if (strcasecmp(option, "hintsfilename") == 0) {
params->hintsFileName = strdup(value);
} else if (strcasecmp(option, "deadlineforstonewalling") == 0) { } else if (strcasecmp(option, "deadlineforstonewalling") == 0) {
params->deadlineForStonewalling = atoi(value); params->deadlineForStonewalling = atoi(value);
} else if (strcasecmp(option, "stoneWallingWearOut") == 0) { } else if (strcasecmp(option, "stoneWallingWearOut") == 0) {
@ -205,34 +183,16 @@ void DecodeDirective(char *line, IOR_param_t *params, options_all_t * module_opt
params->blockSize = string_to_bytes(value); params->blockSize = string_to_bytes(value);
} else if (strcasecmp(option, "transfersize") == 0) { } else if (strcasecmp(option, "transfersize") == 0) {
params->transferSize = string_to_bytes(value); params->transferSize = string_to_bytes(value);
} else if (strcasecmp(option, "setalignment") == 0) {
params->setAlignment = string_to_bytes(value);
} else if (strcasecmp(option, "singlexferattempt") == 0) { } else if (strcasecmp(option, "singlexferattempt") == 0) {
params->singleXferAttempt = atoi(value); params->singleXferAttempt = atoi(value);
} else if (strcasecmp(option, "individualdatasets") == 0) {
params->individualDataSets = atoi(value);
} else if (strcasecmp(option, "intraTestBarriers") == 0) { } else if (strcasecmp(option, "intraTestBarriers") == 0) {
params->intraTestBarriers = atoi(value); params->intraTestBarriers = atoi(value);
} else if (strcasecmp(option, "nofill") == 0) {
params->noFill = atoi(value);
} else if (strcasecmp(option, "verbose") == 0) { } else if (strcasecmp(option, "verbose") == 0) {
params->verbose = atoi(value); params->verbose = atoi(value);
} else if (strcasecmp(option, "settimestampsignature") == 0) { } else if (strcasecmp(option, "settimestampsignature") == 0) {
params->setTimeStampSignature = atoi(value); params->setTimeStampSignature = atoi(value);
} else if (strcasecmp(option, "collective") == 0) {
params->collective = atoi(value);
} else if (strcasecmp(option, "preallocate") == 0) {
params->preallocate = atoi(value);
} else if (strcasecmp(option, "storefileoffset") == 0) { } else if (strcasecmp(option, "storefileoffset") == 0) {
params->storeFileOffset = atoi(value); params->storeFileOffset = atoi(value);
} else if (strcasecmp(option, "usefileview") == 0) {
params->useFileView = atoi(value);
} else if (strcasecmp(option, "usesharedfilepointer") == 0) {
params->useSharedFilePointer = atoi(value);
} else if (strcasecmp(option, "usestrideddatatype") == 0) {
params->useStridedDatatype = atoi(value);
} else if (strcasecmp(option, "showhints") == 0) {
params->showHints = atoi(value);
} else if (strcasecmp(option, "uniqueDir") == 0) { } else if (strcasecmp(option, "uniqueDir") == 0) {
params->uniqueDir = atoi(value); params->uniqueDir = atoi(value);
} else if (strcasecmp(option, "useexistingtestfile") == 0) { } else if (strcasecmp(option, "useexistingtestfile") == 0) {
@ -249,53 +209,6 @@ void DecodeDirective(char *line, IOR_param_t *params, options_all_t * module_opt
} else if (strcasecmp(option, "memoryPerNode") == 0) { } else if (strcasecmp(option, "memoryPerNode") == 0) {
params->memoryPerNode = NodeMemoryStringToBytes(value); params->memoryPerNode = NodeMemoryStringToBytes(value);
params->memoryPerTask = 0; params->memoryPerTask = 0;
} else if (strcasecmp(option, "lustrestripecount") == 0) {
#ifndef HAVE_LUSTRE_LUSTRE_USER_H
ERR("ior was not compiled with Lustre support");
#endif
params->lustre_stripe_count = atoi(value);
params->lustre_set_striping = 1;
} else if (strcasecmp(option, "lustrestripesize") == 0) {
#ifndef HAVE_LUSTRE_LUSTRE_USER_H
ERR("ior was not compiled with Lustre support");
#endif
params->lustre_stripe_size = string_to_bytes(value);
params->lustre_set_striping = 1;
} else if (strcasecmp(option, "lustrestartost") == 0) {
#ifndef HAVE_LUSTRE_LUSTRE_USER_H
ERR("ior was not compiled with Lustre support");
#endif
params->lustre_start_ost = atoi(value);
params->lustre_set_striping = 1;
} else if (strcasecmp(option, "lustreignorelocks") == 0) {
#ifndef HAVE_LUSTRE_LUSTRE_USER_H
ERR("ior was not compiled with Lustre support");
#endif
params->lustre_ignore_locks = atoi(value);
} else if (strcasecmp(option, "gpfshintaccess") == 0) {
#ifndef HAVE_GPFS_FCNTL_H
ERR("ior was not compiled with GPFS hint support");
#endif
params->gpfs_hint_access = atoi(value);
} else if (strcasecmp(option, "gpfsreleasetoken") == 0) {
#ifndef HAVE_GPFS_FCNTL_H
ERR("ior was not compiled with GPFS hint support");
#endif
params->gpfs_release_token = atoi(value);
} else if (strcasecmp(option, "beegfsNumTargets") == 0) {
#ifndef HAVE_BEEGFS_BEEGFS_H
ERR("ior was not compiled with BeeGFS support");
#endif
params->beegfs_numTargets = atoi(value);
if (params->beegfs_numTargets < 1)
ERR("beegfsNumTargets must be >= 1");
} else if (strcasecmp(option, "beegfsChunkSize") == 0) {
#ifndef HAVE_BEEGFS_BEEGFS_H
ERR("ior was not compiled with BeeGFS support");
#endif
params->beegfs_chunkSize = string_to_bytes(value);
if (!ISPOWEROFTWO(params->beegfs_chunkSize) || params->beegfs_chunkSize < (1<<16))
ERR("beegfsChunkSize must be a power of two and >64k");
} else if (strcasecmp(option, "summaryalways") == 0) { } else if (strcasecmp(option, "summaryalways") == 0) {
params->summary_every_test = atoi(value); params->summary_every_test = atoi(value);
} else { } else {
@ -478,7 +391,7 @@ option_help * createGlobalOptions(IOR_param_t * params){
{'a', NULL, apiStr, OPTION_OPTIONAL_ARGUMENT, 's', & params->api}, {'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}, {'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}, {'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', "collective", "Use collective I/O", OPTION_FLAG, 'd', & params->collective},
{'C', NULL, "reorderTasks -- changes task ordering for readback (useful to avoid client cache)", OPTION_FLAG, 'd', & params->reorderTasks}, {'C', NULL, "reorderTasks -- changes task ordering for readback (useful to avoid client cache)", OPTION_FLAG, 'd', & params->reorderTasks},
{'d', NULL, "interTestDelay -- delay between reps in seconds", OPTION_OPTIONAL_ARGUMENT, 'd', & params->interTestDelay}, {'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}, {'D', NULL, "deadlineForStonewalling -- seconds before stopping write or read phase", OPTION_OPTIONAL_ARGUMENT, 'd', & params->deadlineForStonewalling},
@ -495,34 +408,25 @@ option_help * createGlobalOptions(IOR_param_t * params){
* after all the arguments are in and we know which it keep. * 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}, {'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, "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, "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, "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}, {'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}, {'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, "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}, {'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 are participating in the test (overrides MPI)", OPTION_OPTIONAL_ARGUMENT, 'd', & params->numTasks}, {'N', NULL, "numTasks -- number of tasks that are participating in the test (overrides MPI)", OPTION_OPTIONAL_ARGUMENT, 'd', & params->numTasks},
{'o', NULL, "testFile -- full name for test", OPTION_OPTIONAL_ARGUMENT, 's', & params->testFileName}, {'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}, {'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, "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}, {'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, "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}, {'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, "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, "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}, {'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, "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, "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, "writeFile -- write file", OPTION_FLAG, 'd', & params->writeFile},
{'W', NULL, "checkWrite -- check read after write", OPTION_FLAG, 'd', & params->checkWrite}, {'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, "singleXferAttempt -- do not retry transfer if incomplete", OPTION_FLAG, 'd', & params->singleXferAttempt},
@ -551,7 +455,7 @@ IOR_test_t *ParseCommandLine(int argc, char **argv)
IOR_test_t *tests = NULL; IOR_test_t *tests = NULL;
GetPlatformName(initialTestParams.platform); initialTestParams.platform = GetPlatformName();
option_help * options = createGlobalOptions( & initialTestParams); option_help * options = createGlobalOptions( & initialTestParams);
parameters = & initialTestParams; parameters = & initialTestParams;

8
src/test/Makefile.am Executable file
View File

@ -0,0 +1,8 @@
LDFLAGS = $(extraLDFLAGS)
LDADD = ../libaiori.a $(extraLDADD)
# Add test here
TESTS = testlib testexample
check_PROGRAMS = $(TESTS)
testexample_SOURCES = example.c
testlib_SOURCES = lib.c

31
src/test/example.c Normal file
View File

@ -0,0 +1,31 @@
#include <assert.h>
#include <ior.h>
#include <ior-internal.h>
// build a single test via, e.g., mpicc example.c -I ../src/ ../src/libaiori.a -lm
int main(){
IOR_param_t test;
init_IOR_Param_t(& test);
test.blockSize = 10;
test.transferSize = 10;
test.segmentCount = 5;
test.numTasks = 2;
// having an individual file
test.filePerProc = 1;
IOR_offset_t * offsets;
offsets = GetOffsetArraySequential(& test, 0);
assert(offsets[0] == 0);
assert(offsets[1] == 10);
assert(offsets[2] == 20);
assert(offsets[3] == 30);
assert(offsets[4] == 40);
// for(int i = 0; i < test.segmentCount; i++){
// printf("%lld\n", (long long int) offsets[i]);
// }
printf("OK\n");
return 0;
}

View File

@ -47,6 +47,7 @@
#include "utilities.h" #include "utilities.h"
#include "aiori.h" #include "aiori.h"
#include "ior.h" #include "ior.h"
#include "ior-internal.h"
/************************** D E C L A R A T I O N S ***************************/ /************************** D E C L A R A T I O N S ***************************/
@ -146,7 +147,7 @@ void updateParsedOptions(IOR_param_t * options, options_all_t * global_options){
} }
const ior_aiori_t * backend = aiori_select(options->api); const ior_aiori_t * backend = aiori_select(options->api);
if (backend == NULL) if (backend == NULL)
ERR_SIMPLE("unrecognized I/O API"); ERR("Unrecognized I/O API");
options->backend = backend; options->backend = backend;
/* copy the actual module options into the test */ /* copy the actual module options into the test */
@ -272,6 +273,15 @@ int QueryNodeMapping(MPI_Comm comm, int print_nodemap) {
* tasks on node rank 0. * tasks on node rank 0.
*/ */
int GetNumNodes(MPI_Comm comm) { int GetNumNodes(MPI_Comm comm) {
if (getenv("IOR_FAKE_NODES")){
int numNodes = atoi(getenv("IOR_FAKE_NODES"));
int rank;
MPI_Comm_rank(comm, & rank);
if(rank == 0){
printf("Fake number of node: using %d\n", numNodes);
}
return numNodes;
}
#if MPI_VERSION >= 3 #if MPI_VERSION >= 3
MPI_Comm shared_comm; MPI_Comm shared_comm;
int shared_rank = 0; int shared_rank = 0;
@ -338,6 +348,15 @@ int GetNumTasks(MPI_Comm comm) {
* method will return the same value it always has. * method will return the same value it always has.
*/ */
int GetNumTasksOnNode0(MPI_Comm comm) { int GetNumTasksOnNode0(MPI_Comm comm) {
if (getenv("IOR_FAKE_TASK_PER_NODES")){
int tasksPerNode = atoi(getenv("IOR_FAKE_TASK_PER_NODES"));
int rank;
MPI_Comm_rank(comm, & rank);
if(rank == 0){
printf("Fake tasks per node: using %d\n", tasksPerNode);
}
return tasksPerNode;
}
#if MPI_VERSION >= 3 #if MPI_VERSION >= 3
MPI_Comm shared_comm; MPI_Comm shared_comm;
int shared_rank = 0; int shared_rank = 0;
@ -368,15 +387,6 @@ int GetNumTasksOnNode0(MPI_Comm comm) {
int size; int size;
MPI_Comm_size(comm, & size); MPI_Comm_size(comm, & size);
/* for debugging and testing */ /* for debugging and testing */
if (getenv("IOR_FAKE_TASK_PER_NODES")){
int tasksPerNode = atoi(getenv("IOR_FAKE_TASK_PER_NODES"));
int rank;
MPI_Comm_rank(comm, & rank);
if(rank == 0){
printf("Fake tasks per node: using %d\n", tasksPerNode);
}
return tasksPerNode;
}
char localhost[MAX_PATHLEN], char localhost[MAX_PATHLEN],
hostname[MAX_PATHLEN]; hostname[MAX_PATHLEN];
int count = 1, int count = 1,
@ -556,88 +566,66 @@ IOR_offset_t StringToBytes(char *size_str)
/* /*
* Displays size of file system and percent of data blocks and inodes used. * Displays size of file system and percent of data blocks and inodes used.
*/ */
void ShowFileSystemSize(char *fileSystem) void ShowFileSystemSize(IOR_param_t * test) // this might be converted to an AIORI call
{ {
#ifndef _WIN32 /* FIXME */ ior_aiori_statfs_t stat;
char realPath[PATH_MAX]; if(! test->backend->statfs){
char *fileSystemUnitStr; WARN("Backend doesn't implement statfs");
long long int totalFileSystemSize; return;
long long int freeFileSystemSize; }
long long int totalInodes; char filename[MAX_PATHLEN];
long long int freeInodes; GetTestFileName(filename, test);
double totalFileSystemSizeHR; int ret = test->backend->statfs(filename, & stat, test->backend_options);
double usedFileSystemPercentage; if( ret != 0 ){
double usedInodePercentage; WARN("Backend returned error during statfs");
#ifdef __sun /* SunOS does not support statfs(), instead uses statvfs() */ return;
struct statvfs statusBuffer; }
#else /* !__sun */ long long int totalFileSystemSize;
struct statfs statusBuffer; long long int freeFileSystemSize;
#endif /* __sun */ long long int totalInodes;
long long int freeInodes;
double totalFileSystemSizeHR;
double usedFileSystemPercentage;
double usedInodePercentage;
char *fileSystemUnitStr;
#ifdef __sun totalFileSystemSize = stat.f_blocks * stat.f_bsize;
if (statvfs(fileSystem, &statusBuffer) != 0) { freeFileSystemSize = stat.f_bfree * stat.f_bsize;
ERR("unable to statvfs() file system"); usedFileSystemPercentage = (1 - ((double)freeFileSystemSize / (double)totalFileSystemSize)) * 100;
} totalFileSystemSizeHR = (double)totalFileSystemSize / (double)(1<<30);
#else /* !__sun */
if (statfs(fileSystem, &statusBuffer) != 0) {
ERR("unable to statfs() file system");
}
#endif /* __sun */
/* data blocks */ /* inodes */
#ifdef __sun totalInodes = stat.f_files;
totalFileSystemSize = statusBuffer.f_blocks * statusBuffer.f_frsize; freeInodes = stat.f_ffree;
freeFileSystemSize = statusBuffer.f_bfree * statusBuffer.f_frsize; usedInodePercentage = (1 - ((double)freeInodes / (double)totalInodes)) * 100;
#else /* !__sun */
totalFileSystemSize = statusBuffer.f_blocks * statusBuffer.f_bsize;
freeFileSystemSize = statusBuffer.f_bfree * statusBuffer.f_bsize;
#endif /* __sun */
usedFileSystemPercentage = (1 - ((double)freeFileSystemSize fileSystemUnitStr = "GiB";
/ (double)totalFileSystemSize)) * 100; if (totalFileSystemSizeHR > 1024) {
totalFileSystemSizeHR = totalFileSystemSizeHR = (double)totalFileSystemSize / (double)((long long)1<<40);
(double)totalFileSystemSize / (double)(1<<30); fileSystemUnitStr = "TiB";
fileSystemUnitStr = "GiB"; }
if (totalFileSystemSizeHR > 1024) { if(outputFormat == OUTPUT_DEFAULT){
totalFileSystemSizeHR = (double)totalFileSystemSize / (double)((long long)1<<40); fprintf(out_resultfile, "%-20s: %s\n", "Path", filename);
fileSystemUnitStr = "TiB"; fprintf(out_resultfile, "%-20s: %.1f %s Used FS: %2.1f%% ",
} "FS", totalFileSystemSizeHR, fileSystemUnitStr,
usedFileSystemPercentage);
fprintf(out_resultfile, "Inodes: %.1f Mi Used Inodes: %2.1f%%\n",
(double)totalInodes / (double)(1<<20),
usedInodePercentage);
fflush(out_logfile);
}else if(outputFormat == OUTPUT_JSON){
fprintf(out_resultfile, " , \"Path\": \"%s\",", filename);
fprintf(out_resultfile, "\"Capacity\": \"%.1f %s\", \"Used Capacity\": \"%2.1f%%\",",
totalFileSystemSizeHR, fileSystemUnitStr,
usedFileSystemPercentage);
fprintf(out_resultfile, "\"Inodes\": \"%.1f Mi\", \"Used Inodes\" : \"%2.1f%%\"\n",
(double)totalInodes / (double)(1<<20),
usedInodePercentage);
}else if(outputFormat == OUTPUT_CSV){
/* inodes */ }
totalInodes = statusBuffer.f_files;
freeInodes = statusBuffer.f_ffree;
usedInodePercentage =
(1 - ((double)freeInodes / (double)totalInodes)) * 100;
/* show results */ return;
if (realpath(fileSystem, realPath) == NULL) {
ERR("unable to use realpath()");
}
if(outputFormat == OUTPUT_DEFAULT){
fprintf(out_resultfile, "%-20s: %s\n", "Path", realPath);
fprintf(out_resultfile, "%-20s: %.1f %s Used FS: %2.1f%% ",
"FS", totalFileSystemSizeHR, fileSystemUnitStr,
usedFileSystemPercentage);
fprintf(out_resultfile, "Inodes: %.1f Mi Used Inodes: %2.1f%%\n",
(double)totalInodes / (double)(1<<20),
usedInodePercentage);
fflush(out_logfile);
}else if(outputFormat == OUTPUT_JSON){
fprintf(out_resultfile, " , \"Path\": \"%s\",", realPath);
fprintf(out_resultfile, "\"Capacity\": \"%.1f %s\", \"Used Capacity\": \"%2.1f%%\",",
totalFileSystemSizeHR, fileSystemUnitStr,
usedFileSystemPercentage);
fprintf(out_resultfile, "\"Inodes\": \"%.1f Mi\", \"Used Inodes\" : \"%2.1f%%\"\n",
(double)totalInodes / (double)(1<<20),
usedInodePercentage);
}else if(outputFormat == OUTPUT_CSV){
}
#endif /* !_WIN32 */
return;
} }
/* /*

View File

@ -47,7 +47,7 @@ void set_o_direct_flag(int *fd);
char *CurrentTimeString(void); char *CurrentTimeString(void);
int Regex(char *, char *); int Regex(char *, char *);
void ShowFileSystemSize(char *); void ShowFileSystemSize(IOR_param_t * test);
void DumpBuffer(void *, size_t); void DumpBuffer(void *, size_t);
void SeedRandGen(MPI_Comm); void SeedRandGen(MPI_Comm);
void SetHints (MPI_Info *, char *); void SetHints (MPI_Info *, char *);