summaryrefslogtreecommitdiffstats
path: root/tools/perform
diff options
context:
space:
mode:
authorAlbert Cheng <acheng@hdfgroup.org>2014-12-17 23:07:24 (GMT)
committerAlbert Cheng <acheng@hdfgroup.org>2014-12-17 23:07:24 (GMT)
commitd9ba0ae35fce3c6fdf2559753093338061588c00 (patch)
tree4160f420ade0df1ebfc561b4e61d55dfd34dc5e8 /tools/perform
parent4c24346fe1c5ff4ff9e4a9ae7ffec2b5ef9cd922 (diff)
downloadhdf5-d9ba0ae35fce3c6fdf2559753093338061588c00.zip
hdf5-d9ba0ae35fce3c6fdf2559753093338061588c00.tar.gz
hdf5-d9ba0ae35fce3c6fdf2559753093338061588c00.tar.bz2
[svn-r25900] HDFFV-9046: reorganize hdf5/perform/ directory
Moved perform/ to tools/perform. Updated all the configure related files for the new location. Tested: h5committested plus tested in jam and kite.
Diffstat (limited to 'tools/perform')
-rw-r--r--tools/perform/CMakeLists.txt140
-rw-r--r--tools/perform/CMakeTests.cmake62
-rw-r--r--tools/perform/COPYING16
-rw-r--r--tools/perform/Makefile.am79
-rw-r--r--tools/perform/Makefile.in1544
-rw-r--r--tools/perform/benchpar.c488
-rwxr-xr-xtools/perform/build_h5perf_alone.sh28
-rwxr-xr-xtools/perform/build_h5perf_serial_alone.sh28
-rw-r--r--tools/perform/chunk.c552
-rwxr-xr-xtools/perform/gen_report.pl527
-rw-r--r--tools/perform/iopipe.c503
-rw-r--r--tools/perform/overhead.c416
-rw-r--r--tools/perform/perf.c482
-rw-r--r--tools/perform/perf_meta.c850
-rw-r--r--tools/perform/pio_engine.c2678
-rw-r--r--tools/perform/pio_perf.c1696
-rw-r--r--tools/perform/pio_perf.h105
-rw-r--r--tools/perform/pio_standalone.c282
-rw-r--r--tools/perform/pio_standalone.h157
-rw-r--r--tools/perform/pio_timer.c258
-rw-r--r--tools/perform/pio_timer.h82
-rw-r--r--tools/perform/sio_engine.c1310
-rw-r--r--tools/perform/sio_perf.c1409
-rw-r--r--tools/perform/sio_perf.h104
-rw-r--r--tools/perform/sio_standalone.c285
-rw-r--r--tools/perform/sio_standalone.h528
-rw-r--r--tools/perform/sio_timer.c197
-rw-r--r--tools/perform/sio_timer.h78
-rw-r--r--tools/perform/zip_perf.c653
29 files changed, 15537 insertions, 0 deletions
diff --git a/tools/perform/CMakeLists.txt b/tools/perform/CMakeLists.txt
new file mode 100644
index 0000000..6887c60
--- /dev/null
+++ b/tools/perform/CMakeLists.txt
@@ -0,0 +1,140 @@
+cmake_minimum_required (VERSION 2.8.11)
+PROJECT (HDF5_PERFORM )
+
+#-----------------------------------------------------------------------------
+# Apply Definitions to compiler in this directory and below
+#-----------------------------------------------------------------------------
+add_definitions (${HDF_EXTRA_C_FLAGS})
+
+#-----------------------------------------------------------------------------
+# Setup include Directories
+#-----------------------------------------------------------------------------
+INCLUDE_DIRECTORIES (${HDF5_TEST_SRC_DIR})
+INCLUDE_DIRECTORIES (${HDF5_TOOLS_SRC_DIR}/lib )
+
+# --------------------------------------------------------------------
+# Add the executables
+# --------------------------------------------------------------------
+#-- Adding test for h5perf_serial
+set (h5perf_serial_SRCS
+ ${HDF5_PERFORM_SOURCE_DIR}/sio_timer.c
+ ${HDF5_PERFORM_SOURCE_DIR}/sio_perf.c
+ ${HDF5_PERFORM_SOURCE_DIR}/sio_engine.c
+)
+add_executable (h5perf_serial ${h5perf_serial_SRCS})
+TARGET_NAMING (h5perf_serial ${LIB_TYPE})
+TARGET_C_PROPERTIES (h5perf_serial " " " ")
+target_link_libraries (h5perf_serial ${HDF5_LIB_TARGET} ${HDF5_TOOLS_LIB_TARGET})
+set_target_properties (h5perf_serial PROPERTIES FOLDER perform)
+
+if (HDF5_BUILD_PERFORM_STANDALONE)
+ #-- Adding test for h5perf_serial_alone
+ set (h5perf_serial_alone_SRCS
+ ${HDF5_PERFORM_SOURCE_DIR}/sio_timer.c
+ ${HDF5_PERFORM_SOURCE_DIR}/sio_perf.c
+ ${HDF5_PERFORM_SOURCE_DIR}/sio_engine.c
+ )
+ add_executable (h5perf_serial_alone ${h5perf_serial_alone_SRCS})
+ set_property (TARGET h5perf_serial_alone
+ APPEND PROPERTY COMPILE_DEFINITIONS STANDALONE
+ )
+ TARGET_NAMING (h5perf_serial_alone ${LIB_TYPE})
+ TARGET_C_PROPERTIES (h5perf_serial_alone " " " ")
+ target_link_libraries (h5perf_serial_alone ${HDF5_LIB_TARGET} ${HDF5_TOOLS_LIB_TARGET})
+ set_target_properties (h5perf_serial_alone PROPERTIES FOLDER perform)
+endif (HDF5_BUILD_PERFORM_STANDALONE)
+
+#-- Adding test for chunk
+set (chunk_SRCS
+ ${HDF5_PERFORM_SOURCE_DIR}/chunk.c
+)
+ADD_EXECUTABLE(chunk ${chunk_SRCS})
+TARGET_NAMING (chunk ${LIB_TYPE})
+TARGET_C_PROPERTIES (chunk " " " ")
+TARGET_LINK_LIBRARIES(chunk ${HDF5_LIB_TARGET} ${HDF5_TOOLS_LIB_TARGET})
+set_target_properties (chunk PROPERTIES FOLDER perform)
+
+#-- Adding test for iopipe
+set (iopipe_SRCS
+ ${HDF5_PERFORM_SOURCE_DIR}/iopipe.c
+)
+add_executable (iopipe ${iopipe_SRCS})
+TARGET_NAMING (iopipe ${LIB_TYPE})
+TARGET_C_PROPERTIES (iopipe " " " ")
+target_link_libraries (iopipe ${HDF5_LIB_TARGET} ${HDF5_TOOLS_LIB_TARGET})
+set_target_properties (iopipe PROPERTIES FOLDER perform)
+
+#-- Adding test for overhead
+set (overhead_SRCS
+ ${HDF5_PERFORM_SOURCE_DIR}/overhead.c
+)
+add_executable (overhead ${overhead_SRCS})
+TARGET_NAMING (overhead ${LIB_TYPE})
+TARGET_C_PROPERTIES (overhead " " " ")
+target_link_libraries (overhead ${HDF5_LIB_TARGET} ${HDF5_TOOLS_LIB_TARGET})
+set_target_properties (overhead PROPERTIES FOLDER perform)
+
+#-- Adding test for perf_meta
+set (perf_meta_SRCS
+ ${HDF5_PERFORM_SOURCE_DIR}/perf_meta.c
+)
+add_executable (perf_meta ${perf_meta_SRCS})
+TARGET_NAMING (perf_meta ${LIB_TYPE})
+TARGET_C_PROPERTIES (perf_meta " " " ")
+target_link_libraries (perf_meta ${HDF5_LIB_TARGET} ${HDF5_TOOLS_LIB_TARGET} ${HDF5_TEST_LIB_TARGET})
+set_target_properties (perf_meta PROPERTIES FOLDER perform)
+
+#-- Adding test for zip_perf
+set (zip_perf_SRCS
+ ${HDF5_PERFORM_SOURCE_DIR}/zip_perf.c
+)
+add_executable (zip_perf ${zip_perf_SRCS})
+TARGET_NAMING (zip_perf ${LIB_TYPE})
+TARGET_C_PROPERTIES (zip_perf " " " ")
+target_link_libraries (zip_perf ${HDF5_TOOLS_LIB_TARGET} ${HDF5_LIB_TARGET})
+set_target_properties (zip_perf PROPERTIES FOLDER perform)
+
+if (H5_HAVE_PARALLEL)
+ #-- Adding test for h5perf
+ set (h5perf_SRCS
+ ${HDF5_PERFORM_SOURCE_DIR}/pio_timer.c
+ ${HDF5_PERFORM_SOURCE_DIR}/pio_perf.c
+ ${HDF5_PERFORM_SOURCE_DIR}/pio_engine.c
+ )
+ add_executable (h5perf ${h5perf_SRCS})
+ TARGET_NAMING (h5perf ${LIB_TYPE})
+ TARGET_C_PROPERTIES (h5perf " " " ")
+ target_link_libraries (h5perf ${HDF5_LIB_TARGET} ${HDF5_TOOLS_LIB_TARGET} ${HDF5_TEST_LIB_TARGET})
+ set_target_properties (h5perf PROPERTIES FOLDER perform)
+
+ if (HDF5_BUILD_PERFORM_STANDALONE)
+ #-- Adding test for h5perf
+ set (h5perf_alone_SRCS
+ ${HDF5_PERFORM_SOURCE_DIR}/pio_timer.c
+ ${HDF5_PERFORM_SOURCE_DIR}/pio_perf.c
+ ${HDF5_PERFORM_SOURCE_DIR}/pio_engine.c
+ )
+ add_executable (h5perf_alone ${h5perf_alone_SRCS})
+ set_property (TARGET h5perf_alone
+ APPEND PROPERTY COMPILE_DEFINITIONS STANDALONE
+ )
+ TARGET_NAMING (h5perf_alone ${LIB_TYPE})
+ TARGET_C_PROPERTIES (h5perf_alone " " " ")
+ target_link_libraries (h5perf_alone ${HDF5_LIB_TARGET} ${HDF5_TOOLS_LIB_TARGET} ${HDF5_TEST_LIB_TARGET})
+ set_target_properties (h5perf_alone PROPERTIES FOLDER perform)
+ endif (HDF5_BUILD_PERFORM_STANDALONE)
+
+ if (HDF5_BUILD_PARALLEL_ALL)
+ #-- Adding test for benchpar
+ set (benchpar_SRCS
+ ${HDF5_PERFORM_SOURCE_DIR}/benchpar.c
+ )
+ add_executable (benchpar ${benchpar_SRCS})
+ TARGET_NAMING (benchpar ${LIB_TYPE})
+ TARGET_C_PROPERTIES (benchpar " " " ")
+ target_link_libraries (benchpar ${HDF5_LIB_TARGET} ${HDF5_TOOLS_LIB_TARGET} ${HDF5_TEST_LIB_TARGET})
+ set_target_properties (benchpar PROPERTIES FOLDER perform)
+ endif (HDF5_BUILD_PARALLEL_ALL)
+endif (H5_HAVE_PARALLEL)
+
+include (CMakeTests.cmake)
diff --git a/tools/perform/CMakeTests.cmake b/tools/perform/CMakeTests.cmake
new file mode 100644
index 0000000..74055d5
--- /dev/null
+++ b/tools/perform/CMakeTests.cmake
@@ -0,0 +1,62 @@
+
+##############################################################################
+##############################################################################
+### T E S T I N G ###
+##############################################################################
+##############################################################################
+
+add_custom_command (
+ TARGET zip_perf
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND}
+ ARGS -E copy_if_different ${HDF5_TOOLS_SRC_DIR}/testfiles/tfilters.h5 ${PROJECT_BINARY_DIR}/tfilters.h5
+)
+
+#-----------------------------------------------------------------------------
+# Add Tests
+#-----------------------------------------------------------------------------
+
+# Remove any output file left over from previous test run
+add_test (
+ NAME PERFORM_h5perform-clear-objects
+ COMMAND ${CMAKE_COMMAND}
+ -E remove
+ chunk.h5
+ iopipe.h5
+ iopipe.raw
+ x-diag-rd.dat
+ x-diag-wr.dat
+ x-rowmaj-rd.dat
+ x-rowmaj-wr.dat
+ x-gnuplot
+)
+
+add_test (NAME PERFORM_h5perf_serial COMMAND $<TARGET_FILE:h5perf_serial>)
+set_tests_properties (PERFORM_h5perf_serial PROPERTIES TIMEOUT 1800)
+
+if (HDF5_BUILD_PERFORM_STANDALONE)
+ add_test (NAME PERFORM_h5perf_serial_alone COMMAND $<TARGET_FILE:h5perf_serial_alone>)
+endif (HDF5_BUILD_PERFORM_STANDALONE)
+
+add_test (NAME PERFORM_chunk COMMAND $<TARGET_FILE:chunk>)
+
+add_test (NAME PERFORM_iopipe COMMAND $<TARGET_FILE:iopipe>)
+
+add_test (NAME PERFORM_overhead COMMAND $<TARGET_FILE:overhead>)
+
+add_test (NAME PERFORM_perf_meta COMMAND $<TARGET_FILE:perf_meta>)
+
+add_test (NAME PERFORM_zip_perf_help COMMAND $<TARGET_FILE:zip_perf> "-h")
+add_test (NAME PERFORM_zip_perf COMMAND $<TARGET_FILE:zip_perf> tfilters.h5)
+
+if (H5_HAVE_PARALLEL)
+ add_test (NAME PERFORM_h5perf COMMAND ${MPIEXEC} ${MPIEXEC_PREFLAGS} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} ${MPIEXEC_POSTFLAGS} $<TARGET_FILE:h5perf>)
+
+ if (HDF5_BUILD_PERFORM_STANDALONE)
+ add_test (NAME PERFORM_h5perf_alone COMMAND ${MPIEXEC} ${MPIEXEC_PREFLAGS} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} ${MPIEXEC_POSTFLAGS} $<TARGET_FILE:h5perf_alone>)
+ endif (HDF5_BUILD_PERFORM_STANDALONE)
+
+ if (HDF5_BUILD_PARALLEL_ALL)
+ add_test (NAME PERFORM_benchpar COMMAND ${MPIEXEC} ${MPIEXEC_PREFLAGS} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} ${MPIEXEC_POSTFLAGS} $<TARGET_FILE:benchpar>)
+ endif (HDF5_BUILD_PARALLEL_ALL)
+endif (H5_HAVE_PARALLEL)
diff --git a/tools/perform/COPYING b/tools/perform/COPYING
new file mode 100644
index 0000000..6903daf
--- /dev/null
+++ b/tools/perform/COPYING
@@ -0,0 +1,16 @@
+
+ Copyright by The HDF Group and
+ The Board of Trustees of the University of Illinois.
+ All rights reserved.
+
+ The files and subdirectories in this directory are part of HDF5.
+ The full HDF5 copyright notice, including terms governing use,
+ modification, and redistribution, is contained in the files COPYING
+ and Copyright.html. COPYING can be found at the root of the source
+ code distribution tree; Copyright.html can be found at the root
+ level of an installed copy of the electronic HDF5 document set and
+ is linked from the top-level documents page. It can also be found
+ at http://www.hdfgroup.org/HDF5/doc/Copyright.html. If you do not
+ have access to either file, you may request a copy from
+ help@hdfgroup.org.
+
diff --git a/tools/perform/Makefile.am b/tools/perform/Makefile.am
new file mode 100644
index 0000000..59c598a
--- /dev/null
+++ b/tools/perform/Makefile.am
@@ -0,0 +1,79 @@
+#
+# Copyright by The HDF Group.
+# Copyright by the Board of Trustees of the University of Illinois.
+# All rights reserved.
+#
+# This file is part of HDF5. The full HDF5 copyright notice, including
+# terms governing use, modification, and redistribution, is contained in
+# the files COPYING and Copyright.html. COPYING can be found at the root
+# of the source code distribution tree; Copyright.html can be found at the
+# root level of an installed copy of the electronic HDF5 document set and
+# is linked from the top-level documents page. It can also be found at
+# http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have
+# access to either file, you may request a copy from help@hdfgroup.org.
+##
+## Makefile.am
+## Run automake to generate a Makefile.in from this file.
+##
+#
+# HDF5 Library Performance Makefile(.in)
+#
+
+include $(top_srcdir)/config/commence.am
+
+AM_CPPFLAGS+=-I$(top_srcdir)/src -I$(top_srcdir)/test -I$(top_srcdir)/tools/lib
+
+# bin_PROGRAMS will be installed.
+if BUILD_PARALLEL_CONDITIONAL
+ bin_PROGRAMS=h5perf_serial h5perf
+else
+ bin_PROGRAMS=h5perf_serial
+endif
+
+# Add h5perf and h5perf_serial specific linker flags here
+h5perf_LDFLAGS = $(LT_STATIC_EXEC) $(AM_LDFLAGS)
+h5perf_serial_LDFLAGS = $(LT_STATIC_EXEC) $(AM_LDFLAGS)
+
+# Some programs are not built or run by default, but can be built by hand or by
+# specifying --enable-build-all at configure time.
+# Also, some of these programs should only be built in parallel.
+# Currently there is no such program.
+if BUILD_PARALLEL_CONDITIONAL
+ PARA_BUILD_ALL=
+endif
+if BUILD_ALL_CONDITIONAL
+ BUILD_ALL_PROGS=$(PARA_BUILD_ALL)
+endif
+
+# Define programs that will be run in 'make check'
+# List them in the order they should be run.
+# Parallel test programs.
+if BUILD_PARALLEL_CONDITIONAL
+ TEST_PROG_PARA=h5perf perf
+endif
+# Serial test programs.
+TEST_PROG = iopipe chunk overhead zip_perf perf_meta h5perf_serial $(BUILD_ALL_PROGS)
+
+# check_PROGRAMS will be built but not installed. Do not any executable
+# that is in bin_PROGRAMS already. Otherwise, it will be removed twice in
+# "make clean" and some systems, e.g., AIX, do not like it.
+check_PROGRAMS= iopipe chunk overhead zip_perf perf_meta $(BUILD_ALL_PROGS) perf
+
+h5perf_SOURCES=pio_perf.c pio_engine.c pio_timer.c
+h5perf_serial_SOURCES=sio_perf.c sio_engine.c sio_timer.c
+
+# These are the files that `make clean' (and derivatives) will remove from
+# this directory.
+CLEANFILES=*.h5 *.raw *.dat x-gnuplot perftest.out
+
+# All of the programs depend on the main hdf5 library, and some of them
+# depend on test or tools library.
+LDADD=$(LIBHDF5)
+h5perf_LDADD=$(LIBH5TOOLS) $(LIBH5TEST) $(LIBHDF5)
+h5perf_serial_LDADD=$(LIBH5TOOLS) $(LIBH5TEST) $(LIBHDF5)
+perf_LDADD=$(LIBH5TEST) $(LIBHDF5)
+iopipe_LDADD=$(LIBH5TEST) $(LIBHDF5)
+zip_perf_LDADD=$(LIBH5TOOLS) $(LIBH5TEST) $(LIBHDF5)
+perf_meta_LDADD=$(LIBH5TEST) $(LIBHDF5)
+
+include $(top_srcdir)/config/conclude.am
diff --git a/tools/perform/Makefile.in b/tools/perform/Makefile.in
new file mode 100644
index 0000000..1244e27
--- /dev/null
+++ b/tools/perform/Makefile.in
@@ -0,0 +1,1544 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Copyright by The HDF Group.
+# Copyright by the Board of Trustees of the University of Illinois.
+# All rights reserved.
+#
+# This file is part of HDF5. The full HDF5 copyright notice, including
+# terms governing use, modification, and redistribution, is contained in
+# the files COPYING and Copyright.html. COPYING can be found at the root
+# of the source code distribution tree; Copyright.html can be found at the
+# root level of an installed copy of the electronic HDF5 document set and
+# is linked from the top-level documents page. It can also be found at
+# http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have
+# access to either file, you may request a copy from help@hdfgroup.org.
+#
+# HDF5 Library Performance Makefile(.in)
+#
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(top_srcdir)/config/commence.am \
+ $(top_srcdir)/config/conclude.am $(srcdir)/Makefile.in \
+ $(srcdir)/Makefile.am $(top_srcdir)/bin/mkinstalldirs \
+ $(top_srcdir)/bin/depcomp $(top_srcdir)/bin/test-driver \
+ COPYING
+@BUILD_PARALLEL_CONDITIONAL_FALSE@bin_PROGRAMS = \
+@BUILD_PARALLEL_CONDITIONAL_FALSE@ h5perf_serial$(EXEEXT)
+@BUILD_PARALLEL_CONDITIONAL_TRUE@bin_PROGRAMS = \
+@BUILD_PARALLEL_CONDITIONAL_TRUE@ h5perf_serial$(EXEEXT) \
+@BUILD_PARALLEL_CONDITIONAL_TRUE@ h5perf$(EXEEXT)
+check_PROGRAMS = iopipe$(EXEEXT) chunk$(EXEEXT) overhead$(EXEEXT) \
+ zip_perf$(EXEEXT) perf_meta$(EXEEXT) $(am__EXEEXT_2) \
+ perf$(EXEEXT)
+TESTS = $(am__EXEEXT_3)
+subdir = tools/perform
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/bin/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/src/H5config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+am__EXEEXT_1 =
+@BUILD_ALL_CONDITIONAL_TRUE@am__EXEEXT_2 = $(am__EXEEXT_1)
+PROGRAMS = $(bin_PROGRAMS)
+chunk_SOURCES = chunk.c
+chunk_OBJECTS = chunk.$(OBJEXT)
+chunk_LDADD = $(LDADD)
+chunk_DEPENDENCIES = $(LIBHDF5)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+am_h5perf_OBJECTS = pio_perf.$(OBJEXT) pio_engine.$(OBJEXT) \
+ pio_timer.$(OBJEXT)
+h5perf_OBJECTS = $(am_h5perf_OBJECTS)
+h5perf_DEPENDENCIES = $(LIBH5TOOLS) $(LIBH5TEST) $(LIBHDF5)
+h5perf_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(h5perf_LDFLAGS) $(LDFLAGS) -o $@
+am_h5perf_serial_OBJECTS = sio_perf.$(OBJEXT) sio_engine.$(OBJEXT) \
+ sio_timer.$(OBJEXT)
+h5perf_serial_OBJECTS = $(am_h5perf_serial_OBJECTS)
+h5perf_serial_DEPENDENCIES = $(LIBH5TOOLS) $(LIBH5TEST) $(LIBHDF5)
+h5perf_serial_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(h5perf_serial_LDFLAGS) $(LDFLAGS) -o $@
+iopipe_SOURCES = iopipe.c
+iopipe_OBJECTS = iopipe.$(OBJEXT)
+iopipe_DEPENDENCIES = $(LIBH5TEST) $(LIBHDF5)
+overhead_SOURCES = overhead.c
+overhead_OBJECTS = overhead.$(OBJEXT)
+overhead_LDADD = $(LDADD)
+overhead_DEPENDENCIES = $(LIBHDF5)
+perf_SOURCES = perf.c
+perf_OBJECTS = perf.$(OBJEXT)
+perf_DEPENDENCIES = $(LIBH5TEST) $(LIBHDF5)
+perf_meta_SOURCES = perf_meta.c
+perf_meta_OBJECTS = perf_meta.$(OBJEXT)
+perf_meta_DEPENDENCIES = $(LIBH5TEST) $(LIBHDF5)
+zip_perf_SOURCES = zip_perf.c
+zip_perf_OBJECTS = zip_perf.$(OBJEXT)
+zip_perf_DEPENDENCIES = $(LIBH5TOOLS) $(LIBH5TEST) $(LIBHDF5)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src
+depcomp = $(SHELL) $(top_srcdir)/bin/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = chunk.c $(h5perf_SOURCES) $(h5perf_serial_SOURCES) iopipe.c \
+ overhead.c perf.c perf_meta.c zip_perf.c
+DIST_SOURCES = chunk.c $(h5perf_SOURCES) $(h5perf_serial_SOURCES) \
+ iopipe.c overhead.c perf.c perf_meta.c zip_perf.c
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+am__EXEEXT_3 = iopipe$(EXEEXT) chunk$(EXEEXT) overhead$(EXEEXT) \
+ zip_perf$(EXEEXT) perf_meta$(EXEEXT) h5perf_serial$(EXEEXT) \
+ $(am__EXEEXT_2)
+TEST_SUITE_LOG = test-suite.log
+LOG_DRIVER = $(SHELL) $(top_srcdir)/bin/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.sh.log=.log)
+SH_LOG_DRIVER = $(SHELL) $(top_srcdir)/bin/test-driver
+SH_LOG_COMPILE = $(SH_LOG_COMPILER) $(AM_SH_LOG_FLAGS) $(SH_LOG_FLAGS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ADD_PARALLEL_FILES = @ADD_PARALLEL_FILES@
+AMTAR = @AMTAR@
+
+# H5_CFLAGS holds flags that should be used when building hdf5,
+# but which should not be exported to h5cc for building other programs.
+# AM_CFLAGS is an automake construct which should be used by Makefiles
+# instead of CFLAGS, as CFLAGS is reserved solely for the user to define.
+# This applies to FCFLAGS, CXXFLAGS, CPPFLAGS, and LDFLAGS as well.
+AM_CFLAGS = @AM_CFLAGS@ @H5_CFLAGS@
+AM_CPPFLAGS = @AM_CPPFLAGS@ @H5_CPPFLAGS@ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/test -I$(top_srcdir)/tools/lib
+AM_CXXFLAGS = @AM_CXXFLAGS@ @H5_CXXFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_FCFLAGS = @AM_FCFLAGS@ @H5_FCFLAGS@
+AM_LDFLAGS = @AM_LDFLAGS@ @H5_LDFLAGS@
+AM_MAKEFLAGS = @AM_MAKEFLAGS@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BYTESEX = @BYTESEX@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_VERSION = @CC_VERSION@
+CFLAGS = @CFLAGS@
+CLEARFILEBUF = @CLEARFILEBUF@
+CODESTACK = @CODESTACK@
+CONFIG_DATE = @CONFIG_DATE@
+CONFIG_MODE = @CONFIG_MODE@
+CONFIG_USER = @CONFIG_USER@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CXX_VERSION = @CXX_VERSION@
+CYGPATH_W = @CYGPATH_W@
+DEBUG_PKG = @DEBUG_PKG@
+DEFAULT_API_VERSION = @DEFAULT_API_VERSION@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEPRECATED_SYMBOLS = @DEPRECATED_SYMBOLS@
+DIRECT_VFD = @DIRECT_VFD@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNAMIC_DIRS = @DYNAMIC_DIRS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXTERNAL_FILTERS = @EXTERNAL_FILTERS@
+
+# Make sure that these variables are exported to the Makefiles
+F9XMODEXT = @F9XMODEXT@
+F9XMODFLAG = @F9XMODFLAG@
+F9XSUFFIXFLAG = @F9XSUFFIXFLAG@
+FC = @FC@
+FC2003 = @FC2003@
+FCFLAGS = @FCFLAGS@
+FCFLAGS_f90 = @FCFLAGS_f90@
+FCLIBS = @FCLIBS@
+FC_VERSION = @FC_VERSION@
+FGREP = @FGREP@
+FILTERS = @FILTERS@
+FSEARCH_DIRS = @FSEARCH_DIRS@
+GREP = @GREP@
+H5_CFLAGS = @H5_CFLAGS@
+H5_CPPFLAGS = @H5_CPPFLAGS@
+H5_CXXFLAGS = @H5_CXXFLAGS@
+H5_CXX_SHARED = @H5_CXX_SHARED@
+H5_FCFLAGS = @H5_FCFLAGS@
+H5_FORTRAN_SHARED = @H5_FORTRAN_SHARED@
+H5_LDFLAGS = @H5_LDFLAGS@
+H5_LONE_COLON = @H5_LONE_COLON@
+H5_VERSION = @H5_VERSION@
+HADDR_T = @HADDR_T@
+HAVE_DMALLOC = @HAVE_DMALLOC@
+HAVE_FORTRAN_2003 = @HAVE_FORTRAN_2003@
+HAVE_PTHREAD = @HAVE_PTHREAD@
+HDF5_HL = @HDF5_HL@
+HDF5_INTERFACES = @HDF5_INTERFACES@
+HDF_CXX = @HDF_CXX@
+HDF_FORTRAN = @HDF_FORTRAN@
+HDF_FORTRAN2003 = @HDF_FORTRAN2003@
+HID_T = @HID_T@
+HL = @HL@
+HL_FOR = @HL_FOR@
+HSIZE_T = @HSIZE_T@
+HSSIZE_T = @HSSIZE_T@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTRUMENT = @INSTRUMENT@
+INSTRUMENT_LIBRARY = @INSTRUMENT_LIBRARY@
+LARGEFILE = @LARGEFILE@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LL_PATH = @LL_PATH@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_STATIC_EXEC = @LT_STATIC_EXEC@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MPE = @MPE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJECT_NAMELEN_DEFAULT_F = @OBJECT_NAMELEN_DEFAULT_F@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARALLEL = @PARALLEL@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+ROOT = @ROOT@
+RUNPARALLEL = @RUNPARALLEL@
+RUNSERIAL = @RUNSERIAL@
+R_INTEGER = @R_INTEGER@
+R_LARGE = @R_LARGE@
+SEARCH = @SEARCH@
+SED = @SED@
+SETX = @SETX@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIZE_T = @SIZE_T@
+STATIC_EXEC = @STATIC_EXEC@
+STATIC_SHARED = @STATIC_SHARED@
+STRICT_FORMAT_CHECKS = @STRICT_FORMAT_CHECKS@
+STRIP = @STRIP@
+TESTPARALLEL = @TESTPARALLEL@
+THREADSAFE = @THREADSAFE@
+TIME = @TIME@
+TR = @TR@
+TRACE_API = @TRACE_API@
+UNAME_INFO = @UNAME_INFO@
+USE_FILTER_DEFLATE = @USE_FILTER_DEFLATE@
+USE_FILTER_FLETCHER32 = @USE_FILTER_FLETCHER32@
+USE_FILTER_NBIT = @USE_FILTER_NBIT@
+USE_FILTER_SCALEOFFSET = @USE_FILTER_SCALEOFFSET@
+USE_FILTER_SHUFFLE = @USE_FILTER_SHUFFLE@
+USE_FILTER_SZIP = @USE_FILTER_SZIP@
+USINGMEMCHECKER = @USINGMEMCHECKER@
+VERSION = @VERSION@
+WORDS_BIGENDIAN = @WORDS_BIGENDIAN@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_FC = @ac_ct_FC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+
+# Install directories that automake doesn't know about
+docdir = $(exec_prefix)/doc
+dvidir = @dvidir@
+enable_shared = @enable_shared@
+enable_static = @enable_static@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Shell commands used in Makefiles
+RM = rm -f
+CP = cp
+
+# Some machines need a command to run executables; this is that command
+# so that our tests will run.
+# We use RUNEXEC instead of RUNSERIAL directly because it may be that
+# some tests need to be run with a different command. Older versions
+# of the makefiles used the command
+# $(LIBTOOL) --mode=execute
+# in some directories, for instance.
+RUNEXEC = $(RUNSERIAL)
+
+# Libraries to link to while building
+LIBHDF5 = $(top_builddir)/src/libhdf5.la
+LIBH5TEST = $(top_builddir)/test/libh5test.la
+LIBH5F = $(top_builddir)/fortran/src/libhdf5_fortran.la
+LIBH5FTEST = $(top_builddir)/fortran/test/libh5test_fortran.la
+LIBH5CPP = $(top_builddir)/c++/src/libhdf5_cpp.la
+LIBH5TOOLS = $(top_builddir)/tools/lib/libh5tools.la
+LIBH5_HL = $(top_builddir)/hl/src/libhdf5_hl.la
+LIBH5F_HL = $(top_builddir)/hl/fortran/src/libhdf5hl_fortran.la
+LIBH5CPP_HL = $(top_builddir)/hl/c++/src/libhdf5_hl_cpp.la
+
+# Note that in svn revision 19400 the '/' after DESTDIR in H5* variables below
+# has been removed. According to the official description of DESTDIR by Gnu at
+# http://www.gnu.org/prep/standards/html_node/DESTDIR.html, DESTDIR is
+# prepended to the normal and complete install path that it precedes for the
+# purpose of installing in a temporary directory which is useful for building
+# rpms and other packages. The '/' after ${DESTDIR} will be followed by another
+# '/' at the beginning of the normal install path. When DESTDIR is empty the
+# path then begins with '//', which is incorrect and causes problems at least for
+# Cygwin.
+
+# Scripts used to build examples
+# If only shared libraries have been installed, have h5cc build examples with
+# shared libraries instead of static libraries
+H5CC = ${DESTDIR}$(bindir)/h5cc
+H5CC_PP = ${DESTDIR}$(bindir)/h5pcc
+H5FC = ${DESTDIR}$(bindir)/h5fc
+H5FC_PP = ${DESTDIR}$(bindir)/h5pfc
+H5CPP = ${DESTDIR}$(bindir)/h5c++
+ACLOCAL_AMFLAGS = "-I m4"
+
+# The trace script; this is used on source files from the C library to
+# insert tracing macros.
+TRACE = perl $(top_srcdir)/bin/trace
+
+# .chkexe files are used to mark tests that have run successfully.
+# .chklog files are output from those tests.
+# *.clog are from the MPE option.
+CHECK_CLEANFILES = *.chkexe *.chklog *.clog
+
+# Add h5perf and h5perf_serial specific linker flags here
+h5perf_LDFLAGS = $(LT_STATIC_EXEC) $(AM_LDFLAGS)
+h5perf_serial_LDFLAGS = $(LT_STATIC_EXEC) $(AM_LDFLAGS)
+
+# Some programs are not built or run by default, but can be built by hand or by
+# specifying --enable-build-all at configure time.
+# Also, some of these programs should only be built in parallel.
+# Currently there is no such program.
+@BUILD_PARALLEL_CONDITIONAL_TRUE@PARA_BUILD_ALL =
+@BUILD_ALL_CONDITIONAL_TRUE@BUILD_ALL_PROGS = $(PARA_BUILD_ALL)
+
+# Define programs that will be run in 'make check'
+# List them in the order they should be run.
+# Parallel test programs.
+@BUILD_PARALLEL_CONDITIONAL_TRUE@TEST_PROG_PARA = h5perf perf
+# Serial test programs.
+TEST_PROG = iopipe chunk overhead zip_perf perf_meta h5perf_serial $(BUILD_ALL_PROGS)
+h5perf_SOURCES = pio_perf.c pio_engine.c pio_timer.c
+h5perf_serial_SOURCES = sio_perf.c sio_engine.c sio_timer.c
+
+# These are the files that `make clean' (and derivatives) will remove from
+# this directory.
+CLEANFILES = *.h5 *.raw *.dat x-gnuplot perftest.out
+
+# All of the programs depend on the main hdf5 library, and some of them
+# depend on test or tools library.
+LDADD = $(LIBHDF5)
+h5perf_LDADD = $(LIBH5TOOLS) $(LIBH5TEST) $(LIBHDF5)
+h5perf_serial_LDADD = $(LIBH5TOOLS) $(LIBH5TEST) $(LIBHDF5)
+perf_LDADD = $(LIBH5TEST) $(LIBHDF5)
+iopipe_LDADD = $(LIBH5TEST) $(LIBHDF5)
+zip_perf_LDADD = $(LIBH5TOOLS) $(LIBH5TEST) $(LIBHDF5)
+perf_meta_LDADD = $(LIBH5TEST) $(LIBHDF5)
+
+# Automake needs to be taught how to build lib, progs, and tests targets.
+# These will be filled in automatically for the most part (e.g.,
+# lib_LIBRARIES are built for lib target), but EXTRA_LIB, EXTRA_PROG, and
+# EXTRA_TEST variables are supplied to allow the user to force targets to
+# be built at certain times.
+LIB = $(lib_LIBRARIES) $(lib_LTLIBRARIES) $(noinst_LIBRARIES) \
+ $(noinst_LTLIBRARIES) $(check_LIBRARIES) $(check_LTLIBRARIES) $(EXTRA_LIB)
+
+PROGS = $(bin_PROGRAMS) $(bin_SCRIPTS) $(noinst_PROGRAMS) $(noinst_SCRIPTS) \
+ $(EXTRA_PROG)
+
+chk_TESTS = $(check_PROGRAMS) $(check_SCRIPTS) $(EXTRA_TEST)
+TEST_EXTENSIONS = .sh
+SH_LOG_COMPILER = $(SHELL)
+AM_SH_LOG_FLAGS =
+TEST_PROG_CHKEXE = $(TEST_PROG:=.chkexe_)
+TEST_PROG_PARA_CHKEXE = $(TEST_PROG_PARA:=.chkexe_)
+TEST_SCRIPT_CHKSH = $(TEST_SCRIPT:=.chkexe_)
+TEST_SCRIPT_PARA_CHKSH = $(TEST_SCRIPT_PARA:=.chkexe_)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .sh .sh$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/config/commence.am $(top_srcdir)/config/conclude.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tools/perform/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign tools/perform/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+$(top_srcdir)/config/commence.am $(top_srcdir)/config/conclude.am:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+chunk$(EXEEXT): $(chunk_OBJECTS) $(chunk_DEPENDENCIES) $(EXTRA_chunk_DEPENDENCIES)
+ @rm -f chunk$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(chunk_OBJECTS) $(chunk_LDADD) $(LIBS)
+
+h5perf$(EXEEXT): $(h5perf_OBJECTS) $(h5perf_DEPENDENCIES) $(EXTRA_h5perf_DEPENDENCIES)
+ @rm -f h5perf$(EXEEXT)
+ $(AM_V_CCLD)$(h5perf_LINK) $(h5perf_OBJECTS) $(h5perf_LDADD) $(LIBS)
+
+h5perf_serial$(EXEEXT): $(h5perf_serial_OBJECTS) $(h5perf_serial_DEPENDENCIES) $(EXTRA_h5perf_serial_DEPENDENCIES)
+ @rm -f h5perf_serial$(EXEEXT)
+ $(AM_V_CCLD)$(h5perf_serial_LINK) $(h5perf_serial_OBJECTS) $(h5perf_serial_LDADD) $(LIBS)
+
+iopipe$(EXEEXT): $(iopipe_OBJECTS) $(iopipe_DEPENDENCIES) $(EXTRA_iopipe_DEPENDENCIES)
+ @rm -f iopipe$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(iopipe_OBJECTS) $(iopipe_LDADD) $(LIBS)
+
+overhead$(EXEEXT): $(overhead_OBJECTS) $(overhead_DEPENDENCIES) $(EXTRA_overhead_DEPENDENCIES)
+ @rm -f overhead$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(overhead_OBJECTS) $(overhead_LDADD) $(LIBS)
+
+perf$(EXEEXT): $(perf_OBJECTS) $(perf_DEPENDENCIES) $(EXTRA_perf_DEPENDENCIES)
+ @rm -f perf$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(perf_OBJECTS) $(perf_LDADD) $(LIBS)
+
+perf_meta$(EXEEXT): $(perf_meta_OBJECTS) $(perf_meta_DEPENDENCIES) $(EXTRA_perf_meta_DEPENDENCIES)
+ @rm -f perf_meta$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(perf_meta_OBJECTS) $(perf_meta_LDADD) $(LIBS)
+
+zip_perf$(EXEEXT): $(zip_perf_OBJECTS) $(zip_perf_DEPENDENCIES) $(EXTRA_zip_perf_DEPENDENCIES)
+ @rm -f zip_perf$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(zip_perf_OBJECTS) $(zip_perf_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chunk.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iopipe.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/overhead.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/perf_meta.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pio_engine.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pio_perf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pio_timer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sio_engine.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sio_perf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sio_timer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zip_perf.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ else \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+recheck: all $(check_PROGRAMS)
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+iopipe.log: iopipe$(EXEEXT)
+ @p='iopipe$(EXEEXT)'; \
+ b='iopipe'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+chunk.log: chunk$(EXEEXT)
+ @p='chunk$(EXEEXT)'; \
+ b='chunk'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+overhead.log: overhead$(EXEEXT)
+ @p='overhead$(EXEEXT)'; \
+ b='overhead'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+zip_perf.log: zip_perf$(EXEEXT)
+ @p='zip_perf$(EXEEXT)'; \
+ b='zip_perf'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+perf_meta.log: perf_meta$(EXEEXT)
+ @p='perf_meta$(EXEEXT)'; \
+ b='perf_meta'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+h5perf_serial.log: h5perf_serial$(EXEEXT)
+ @p='h5perf_serial$(EXEEXT)'; \
+ b='h5perf_serial'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.sh.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(SH_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_SH_LOG_DRIVER_FLAGS) $(SH_LOG_DRIVER_FLAGS) -- $(SH_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.sh$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(SH_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_SH_LOG_DRIVER_FLAGS) $(SH_LOG_DRIVER_FLAGS) -- $(SH_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(PROGRAMS) all-local
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool mostlyclean-local
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am all-local check check-TESTS \
+ check-am clean clean-binPROGRAMS clean-checkPROGRAMS \
+ clean-generic clean-libtool cscopelist-am ctags ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool mostlyclean-local pdf \
+ pdf-am ps ps-am recheck tags tags-am uninstall uninstall-am \
+ uninstall-binPROGRAMS
+
+
+# List all build rules defined by HDF5 Makefiles as "PHONY" targets here.
+# This tells the Makefiles that these targets are not files to be built but
+# commands that should be executed even if a file with the same name already
+# exists.
+.PHONY: build-check-clean build-check-p build-check-s build-lib build-progs \
+ build-tests check-clean check-install check-p check-s check-vfd \
+ install-doc lib progs tests uninstall-doc _exec_check-s _test help
+
+help:
+ @$(top_srcdir)/bin/makehelp
+
+# lib/progs/tests targets recurse into subdirectories. build-* targets
+# build files in this directory.
+build-lib: $(LIB)
+build-progs: $(LIB) $(PROGS)
+build-tests: $(LIB) $(PROGS) $(chk_TESTS)
+
+# General rule for recursive building targets.
+# BUILT_SOURCES contain targets that need to be built before anything else
+# in the directory (e.g., for Fortran type detection)
+lib progs tests check-s check-p :: $(BUILT_SOURCES)
+ @$(MAKE) $(AM_MAKEFLAGS) build-$@ || exit 1;
+ @for d in X $(SUBDIRS); do \
+ if test $$d != X && test $$d != .; then \
+ (set -x; cd $$d && $(MAKE) $(AM_MAKEFLAGS) $@) || exit 1; \
+ fi; \
+ done
+
+# General rule for recursive cleaning targets. Like the rule above,
+# but doesn't require building BUILT_SOURCES.
+check-clean ::
+ @$(MAKE) $(AM_MAKEFLAGS) build-$@ || exit 1;
+ @for d in X $(SUBDIRS); do \
+ if test $$d != X && test $$d != .; then \
+ (set -x; cd $$d && $(MAKE) $(AM_MAKEFLAGS) $@) || exit 1; \
+ fi; \
+ done
+
+# Tell Automake to build tests when the user types `make all' (this is
+# not its default behavior). Also build EXTRA_LIB and EXTRA_PROG since
+# Automake won't build them automatically, either.
+all-local: $(EXTRA_LIB) $(EXTRA_PROG) $(chk_TESTS)
+
+# make install-doc doesn't do anything outside of doc directory, but
+# Makefiles should recognize it.
+# UPDATE: docs no longer reside in this build tree, so this target
+# is depreciated.
+install-doc uninstall-doc:
+ @echo "Nothing to be done."
+
+# clean up files generated by tests so they can be re-run.
+build-check-clean:
+ $(RM) -rf $(CHECK_CLEANFILES)
+
+# run check-clean whenever mostlyclean is run
+mostlyclean-local: build-check-clean
+
+# check-install is just a synonym for installcheck
+check-install: installcheck
+
+# Run each test in order, passing $(TEST_FLAGS) to the program.
+# Since tests are done in a shell loop, "make -i" does apply inside it.
+# Set HDF5_Make_Ignore to a non-blank string to ignore errors inside the loop.
+# The timestamps give a rough idea how much time the tests use.
+#
+# Note that targets in chk_TESTS (defined above) will be built when the user
+# types 'make tests' or 'make check', but only programs in TEST_PROG,
+# TEST_PROG_PARA, or TEST_SCRIPT will actually be executed.
+check-TESTS: test
+
+test _test:
+ @$(MAKE) build-check-s
+ @$(MAKE) build-check-p
+
+# Actual execution of check-s.
+build-check-s: $(LIB) $(PROGS) $(chk_TESTS)
+ @if test -n "$(TEST_PROG)$(TEST_SCRIPT)"; then \
+ echo "===Serial tests in `echo ${PWD} | sed -e s:.*/::` begin `date`==="; \
+ fi
+ @$(MAKE) $(AM_MAKEFLAGS) _exec_check-s
+ @if test -n "$(TEST_PROG)$(TEST_SCRIPT)"; then \
+ echo "===Serial tests in `echo ${PWD} | sed -e s:.*/::` ended `date`===";\
+ fi
+
+_exec_check-s: $(TEST_PROG_CHKEXE) $(TEST_SCRIPT_CHKSH)
+
+# The dummy.chkexe here prevents the target from being
+# empty if there are no tests in the current directory.
+# $${log} is the log file.
+# $${tname} is the name of test.
+$(TEST_PROG_CHKEXE) $(TEST_PROG_PARA_CHKEXE) dummy.chkexe_:
+ @if test "X$@" != "X.chkexe_" && test "X$@" != "Xdummy.chkexe_"; then \
+ tname=$(@:.chkexe_=)$(EXEEXT);\
+ log=$(@:.chkexe_=.chklog); \
+ echo "============================"; \
+ if $(top_srcdir)/bin/newer $(@:.chkexe_=.chkexe) $${tname}; then \
+ echo "No need to test $${tname} again."; \
+ else \
+ echo "============================" > $${log}; \
+ if test "X$(FORTRAN_API)" = "Xyes"; then \
+ echo "Fortran API: Testing $(HDF5_DRIVER) $${tname} $(TEST_FLAGS)"; \
+ echo "Fortran API: $(HDF5_DRIVER) $${tname} $(TEST_FLAGS) Test Log" >> $${log}; \
+ elif test "X$(CXX_API)" = "Xyes"; then \
+ echo "C++ API: Testing $(HDF5_DRIVER) $${tname} $(TEST_FLAGS)"; \
+ echo "C++ API: $(HDF5_DRIVER) $${tname} $(TEST_FLAGS) Test Log" >> $${log};\
+ else \
+ echo "Testing $(HDF5_DRIVER) $${tname} $(TEST_FLAGS)"; \
+ echo "$(HDF5_DRIVER) $${tname} $(TEST_FLAGS) Test Log" >> $${log}; \
+ fi; \
+ echo "============================" >> $${log}; \
+ srcdir="$(srcdir)" \
+ $(TIME) $(RUNEXEC) ./$${tname} $(TEST_FLAGS) >> $${log} 2>&1 \
+ && touch $(@:.chkexe_=.chkexe) || \
+ (test $$HDF5_Make_Ignore && echo "*** Error ignored") || \
+ (cat $${log} && false) || exit 1; \
+ echo "" >> $${log}; \
+ echo "Finished testing $${tname} $(TEST_FLAGS)" >> $${log}; \
+ echo "============================" >> $${log}; \
+ echo "Finished testing $${tname} $(TEST_FLAGS)"; \
+ cat $${log}; \
+ fi; \
+ fi
+
+# The dummysh.chkexe here prevents the target from being
+# empty if there are no tests in the current directory.
+# $${log} is the log file.
+# $${tname} is the name of test.
+$(TEST_SCRIPT_CHKSH) $(TEST_SCRIPT_PARA_CHKSH) dummysh.chkexe_:
+ @if test "X$@" != "X.chkexe_" && test "X$@" != "Xdummysh.chkexe_"; then \
+ cmd=$(@:.chkexe_=);\
+ tname=`basename $$cmd`;\
+ chkname=`basename $(@:.chkexe_=.chkexe)`;\
+ log=`basename $(@:.chkexe_=.chklog)`; \
+ echo "============================"; \
+ if $(top_srcdir)/bin/newer $${chkname} $$cmd $(SCRIPT_DEPEND); then \
+ echo "No need to test $${tname} again."; \
+ else \
+ echo "============================" > $${log}; \
+ if test "X$(FORTRAN_API)" = "Xyes"; then \
+ echo "Fortran API: Testing $${tname} $(TEST_FLAGS)"; \
+ echo "Fortran API: $${tname} $(TEST_FLAGS) Test Log" >> $${log}; \
+ elif test "X$(CXX_API)" = "Xyes"; then \
+ echo "C++ API: Testing $${tname} $(TEST_FLAGS)"; \
+ echo "C++ API: $${tname} $(TEST_FLAGS) Test Log" >> $${log}; \
+ else \
+ echo "Testing $${tname} $(TEST_FLAGS)"; \
+ echo "$${tname} $(TEST_FLAGS) Test Log" >> $${log}; \
+ fi; \
+ echo "============================" >> $${log}; \
+ RUNSERIAL="$(RUNSERIAL)" RUNPARALLEL="$(RUNPARALLEL)" \
+ srcdir="$(srcdir)" \
+ $(TIME) $(SHELL) $$cmd $(TEST_FLAGS) >> $${log} 2>&1 \
+ && touch $${chkname} || \
+ (test $$HDF5_Make_Ignore && echo "*** Error ignored") || \
+ (cat $${log} && false) || exit 1; \
+ echo "" >> $${log}; \
+ echo "Finished testing $${tname} $(TEST_FLAGS)" >> $${log}; \
+ echo "============================" >> $${log}; \
+ echo "Finished testing $${tname} $(TEST_FLAGS)"; \
+ cat $${log}; \
+ fi; \
+ echo "============================"; \
+ fi
+
+# Actual execution of check-p.
+build-check-p: $(LIB) $(PROGS) $(chk_TESTS)
+ @if test -n "$(TEST_PROG_PARA)$(TEST_SCRIPT_PARA)"; then \
+ echo "===Parallel tests in `echo ${PWD} | sed -e s:.*/::` begin `date`==="; \
+ fi
+ @if test -n "$(TEST_PROG_PARA)"; then \
+ echo "**** Hint ****"; \
+ echo "Parallel test files reside in the current directory" \
+ "by default."; \
+ echo "Set HDF5_PARAPREFIX to use another directory. E.g.,"; \
+ echo " HDF5_PARAPREFIX=/PFS/user/me"; \
+ echo " export HDF5_PARAPREFIX"; \
+ echo " make check"; \
+ echo "**** end of Hint ****"; \
+ fi
+ @for test in $(TEST_PROG_PARA) dummy; do \
+ if test $$test != dummy; then \
+ $(MAKE) $(AM_MAKEFLAGS) $$test.chkexe_ \
+ RUNEXEC="$(RUNPARALLEL)" || exit 1; \
+ fi; \
+ done
+ @for test in $(TEST_SCRIPT_PARA) dummy; do \
+ if test $$test != dummy; then \
+ $(MAKE) $(AM_MAKEFLAGS) $$test.chkexe_ || exit 1; \
+ fi; \
+ done
+ @if test -n "$(TEST_PROG_PARA)$(TEST_SCRIPT_PARA)"; then \
+ echo "===Parallel tests in `echo ${PWD} | sed -e s:.*/::` ended `date`===";\
+ fi
+
+# Run test with different Virtual File Driver
+check-vfd: $(LIB) $(PROGS) $(chk_TESTS)
+ @for vfd in $(VFD_LIST) dummy; do \
+ if test $$vfd != dummy; then \
+ echo "============================"; \
+ echo "Testing Virtual File Driver $$vfd"; \
+ echo "============================"; \
+ $(MAKE) $(AM_MAKEFLAGS) check-clean || exit 1; \
+ HDF5_DRIVER=$$vfd $(MAKE) $(AM_MAKEFLAGS) check || exit 1; \
+ fi; \
+ done
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tools/perform/benchpar.c b/tools/perform/benchpar.c
new file mode 100644
index 0000000..b75006a
--- /dev/null
+++ b/tools/perform/benchpar.c
@@ -0,0 +1,488 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifdef H5_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h>
+#include <float.h>
+#include <string.h>
+
+#include "hdf5.h"
+
+/* Local macros */
+#ifdef H5_HAVE_VISUAL_STUDIO
+#define HDgetlogin() Wgetlogin()
+#else /* H5_HAVE_VISUAL_STUDIO */
+#define HDgetlogin() getlogin()
+#endif /* H5_HAVE_VISUAL_STUDIO */
+
+/*
+ * HDF Boolean type.
+ */
+#ifndef FALSE
+# define FALSE 0
+#endif
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+/* defines for type of VFL driver to use */
+#define FACC_DEFAULT 0
+#define FACC_MPIO 1
+
+/* Defines for computing performance information */
+#define ONE_KB 1024
+#define ONE_MB (ONE_KB * ONE_KB)
+#define ONE_GB (ONE_MB * ONE_KB)
+
+/* report 0.0 in case t is zero too */
+#define MB_PER_SEC(bytes,t) ((fabs(t)<0.0000000001) ? 0.0 : ((((double)bytes) / ONE_MB) / (t)))
+
+/* Control default behavior (with no command line arguments) */
+#define DEFAULT_RANK 3
+#define DEFAULT_DIM 1024
+#define DEFAULT_PREFIX "/tmp"
+#define DEFAULT_USERNAME "koziol"
+#define DEFAULT_FILENAME "benchpar.h5"
+#define DEFAULT_SLICE 0
+#define DEFAULT_C_TYPE int
+#define DEFAULT_HDF5_DATATYPE H5T_NATIVE_INT /* Keep this in sync with the DEFAULT_C_TYPE */
+#define DEFAULT_DATASET_NAME "Dataset"
+#define DEFAULT_VFL_DRIVER FACC_MPIO
+#define DEFAULT_PAR_MODE H5FD_MPIO_COLLECTIVE
+#define DEFAULT_CHUNK_STORAGE 0
+#define DEFAULT_ITER 3
+
+/* MPI info */
+int mpi_rank, mpi_size;
+int mpi_namelen;
+char mpi_name[MPI_MAX_PROCESSOR_NAME];
+
+/* Usage information */
+static void usage(void)
+{
+ printf("usage: benchpar [-d <# of dims>] [-s <dim_size>] [-f <file name>] [-h]\n");
+ printf(" [-S <slice dim>] [-I] [-c] [-i <# of iterations>\n");
+ printf(" -c - Use chunked storage for dataset with 1-1 exact\n");
+ printf(" mapping of chunks to hyperslabs\n");
+ printf(" Default: off (i.e. contiguous storage)\n");
+ printf(" -d <# of dims> - Number of dimensions of the dataset\n");
+ printf(" Default: 3\n");
+ printf(" -f <file name> - Set the name of the test file\n");
+ printf(" Default: /tmp/<login>/benchpar.h5\n");
+ printf(" -h - Prints usage information\n");
+ printf(" -i <# of iters> - Set the number of test iterations to perform\n");
+ printf(" Default: 3\n");
+ printf(" -I - Use independent parallel I/O\n");
+ printf(" Default: use collective parallel I/O\n");
+ printf(" -s <dim_size> - Set the size of each of the dataset's dimensions\n");
+ printf(" Default: 1024\n");
+ printf(" -S <slice dim> - Set the dimension to slice the dataset along\n");
+ printf(" Default: 0\n");
+} /* end usage() */
+
+/* Create & initialize file creation property list with appropriate properties */
+static hid_t create_fcpl(void)
+{
+ hid_t fcpl; /* File creation property list */
+
+ fcpl=H5Pcreate(H5P_FILE_CREATE);
+ assert(fcpl>0);
+
+ return(fcpl);
+} /* end create_fcpl() */
+
+/* Create & initialize file access property list with appropriate properties */
+static hid_t create_fapl(MPI_Comm comm, MPI_Info info, int acc_type )
+{
+ hid_t fapl; /* File access property list */
+ herr_t ret; /* Generic return value */
+
+ fapl = H5Pcreate (H5P_FILE_ACCESS);
+ assert(fapl>0);
+
+ /* set parallel access with communicator, using MPI-I/O driver */
+ if (acc_type == FACC_MPIO) {
+ ret = H5Pset_fapl_mpio(fapl, comm, info);
+ assert(ret>=0);
+ } /* end if */
+
+ return (fapl);
+} /* end create_fapl() */
+
+/* Create & initialize dataset creation property list with appropriate properties */
+static hid_t create_dcpl(unsigned use_chunks, int rank, hsize_t *dims)
+{
+ hid_t dcpl; /* Dataset creation property list */
+ herr_t ret; /* Generic return value */
+
+ dcpl=H5Pcreate(H5P_DATASET_CREATE);
+ assert(dcpl>0);
+
+ /* Check if the dataset should be chunked */
+ if(use_chunks) {
+ ret = H5Pset_chunk(dcpl, rank, dims);
+ assert(ret>=0);
+ } /* end if */
+
+ return(dcpl);
+} /* end create_dcpl() */
+
+/* Create & initialize dataset transfer property list with appropriate properties */
+static hid_t create_dxpl(H5FD_mpio_xfer_t par_mode)
+{
+ hid_t dxpl; /* Dataset creation property list */
+ herr_t ret; /* Generic return value */
+
+ dxpl=H5Pcreate(H5P_DATASET_XFER);
+ assert(dxpl>0);
+
+ /* Set collective I/O on this transfer */
+ ret=H5Pset_dxpl_mpio(dxpl, par_mode);
+ assert(ret>=0);
+
+ return(dxpl);
+} /* end create_dcpl() */
+
+int main(int argc, char *argv[])
+{
+ int curr_arg; /* Current command line argument being processed */
+ int rank; /* Number of dimensions of the dataset */
+ hsize_t dim_size; /* Dimension size of each dimension */
+ hsize_t dims[H5S_MAX_RANK]; /* Pointer to array of dimensions */
+ hsize_t start[H5S_MAX_RANK]; /* Pointer to array of starting locations for hyperslab selection */
+ hsize_t count[H5S_MAX_RANK]; /* Pointer to array of counts for hyperslab selection */
+ unsigned slice_dim; /* Dimension to slice up */
+ char *file_name=NULL; /* Name of file to put data into */
+ hid_t fcpl; /* HDF5 File creation property list ID */
+ hid_t fapl; /* HDF5 File access property list ID */
+ hid_t dcpl; /* HDF5 Dataset creation property list ID */
+ hid_t dxpl; /* HDF5 Dataset transfer property list ID */
+ hid_t fid; /* HDF5 file ID */
+ hid_t dsid; /* HDF5 dataset ID */
+ hid_t file_sid; /* HDF5 dataspace ID for dataset on disk */
+ hid_t mem_sid; /* HDF5 dataspace ID for dataset in memory */
+ DEFAULT_C_TYPE *buf; /* Buffer to write out */
+ hsize_t buf_size; /* Size of buffer to write */
+ int i; /* Local index variable */
+ herr_t ret; /* Generic return value */
+ double start_write_time, end_write_time, elap_write_time; /* Start, end and elapsed time to write raw data */
+ double tmp_max_write_time; /* Temporary holders for maximum time for all nodes to perform raw data I/O */
+ double max_write_time=-DBL_MAX, min_write_time=DBL_MAX; /* Minimum & maximum time for all nodes to perform raw data I/O */
+ double start_file_time, end_file_time, elap_file_time; /* Start, end and elapsed time from file open to file close */
+ double tmp_max_file_time; /* Temporary holders for maximum time for all nodes from file open to file close */
+ double max_file_time=-DBL_MAX, min_file_time=DBL_MAX; /* Minimum & maximum time for all nodes from file open to file close */
+ int vfl_type; /* Type of VFL driver to use */
+ H5FD_mpio_xfer_t par_mode; /* Type of parallel I/O to perform */
+ unsigned use_chunks; /* Whether to use chunks for dataset or not */
+ unsigned num_iter; /* Number of iterations to perform */
+ unsigned u; /* Local index variable */
+
+ /* Un-buffer the stdout and stderr */
+ setbuf(stderr, NULL);
+ setbuf(stdout, NULL);
+
+ /* MPI initialization */
+ MPI_Init(&argc,&argv);
+ MPI_Comm_size(MPI_COMM_WORLD,&mpi_size);
+ MPI_Comm_rank(MPI_COMM_WORLD,&mpi_rank);
+ MPI_Get_processor_name(mpi_name,&mpi_namelen);
+
+ /* Set some defaults */
+ rank=DEFAULT_RANK;
+ dim_size=DEFAULT_DIM;
+ slice_dim=DEFAULT_SLICE;
+ vfl_type=DEFAULT_VFL_DRIVER;
+ par_mode=DEFAULT_PAR_MODE;
+ use_chunks=DEFAULT_CHUNK_STORAGE;
+ num_iter=DEFAULT_ITER;
+
+ /* Parse command line arguments */
+ if(argc>1) {
+ curr_arg=1;
+ while(curr_arg<argc) {
+ /* Trap any unknown command line parameters */
+ if(argv[curr_arg][0]!='-') {
+ printf("unknown command line parameter: %s\n",argv[curr_arg]);
+ goto done;
+ } /* end if */
+
+ /* Skip over command line flag */
+ curr_arg++;
+
+ switch(argv[curr_arg-1][1]) {
+ case 'c': /* Use chunked storage for dataset */
+ use_chunks=1;
+ break;
+
+ case 'd': /* Change number of dimensions */
+ /* Get new number of dimensions */
+ rank=atoi(argv[curr_arg]);
+ curr_arg++; /* Skip over number of dimensions */
+
+ /* Sanity check */
+ if(rank<=0) {
+ printf("rank=%d, invalid number of dimensions: %d\n",mpi_rank,rank);
+ goto done;
+ } /* end if */
+ break;
+
+ case 'f': /* Change test file name */
+ /* Get new file name */
+ file_name=strdup(argv[curr_arg]);
+ curr_arg++; /* Skip over file name from command line */
+ break;
+
+ case 'h': /* Print usage information */
+ usage();
+ goto done;
+ break;
+
+ case 'i': /* Change number of iterations */
+ /* Get new number of dimensions */
+ num_iter=atoi(argv[curr_arg]);
+ curr_arg++; /* Skip over number of iterations */
+
+ /* Sanity check */
+ if(num_iter<1) {
+ printf("rank=%d, invalid number of iterations: %u\n",mpi_rank,num_iter);
+ goto done;
+ } /* end if */
+ break;
+
+ case 'I': /* Use independent I/O for parallel I/O */
+ par_mode=H5FD_MPIO_INDEPENDENT;
+ break;
+
+ case 's': /* Change dimension size */
+ /* Get new dimension size */
+ dim_size=atoi(argv[curr_arg]);
+ curr_arg++; /* Skip over dimension size from command line */
+
+ /* Sanity check */
+ if(dim_size<=0) {
+ printf("rank=%d, invalid dimension size: %ld\n",mpi_rank,(long)dim_size);
+ goto done;
+ } /* end if */
+ break;
+
+ case 'S': /* Change dimension to slice */
+ /* Get new dimension to slice */
+ slice_dim=atoi(argv[curr_arg]);
+ curr_arg++; /* Skip over slice dimension from command line */
+ break;
+
+ default:
+ printf("rank=%d, unknown command line parameter: %s\n",mpi_rank,argv[curr_arg-1]);
+ goto done;
+ } /* end switch */
+ } /* end while */
+ } /* end if */
+
+ /* Sanity check */
+ if(slice_dim>=rank) {
+ printf("rank=%d, error, slice dim larger than rank: slice_dim=%d, rank=%d\n",mpi_rank,slice_dim,rank);
+ goto done;
+ } /* end if */
+
+ /* Set rest of defaults */
+ if(file_name==NULL) {
+ char *login; /* Pointer to login name */
+
+ /* Get the login name for this user */
+ login=HDgetlogin();
+ if(login==NULL)
+ login=DEFAULT_USERNAME;
+
+ /* Allocate enough room for the prefix, the login name, two '/'s, the filename and the string terminator */
+ file_name=malloc(strlen(DEFAULT_PREFIX)+1+strlen(login)+1+strlen(DEFAULT_FILENAME)+1);
+ strcpy(file_name,DEFAULT_PREFIX);
+ strcat(file_name,"/");
+ strcat(file_name,login);
+ strcat(file_name,"/");
+ strcat(file_name,DEFAULT_FILENAME);
+ } /* end if */
+
+ /* Allocate memory for this process's portion of dataset */
+ buf_size=sizeof(DEFAULT_C_TYPE);
+ for(i=0; i<rank; i++)
+ buf_size *= dim_size;
+ buf_size /= mpi_size;
+
+ /* Sanity check for overflow */
+ assert((hsize_t)((size_t)buf_size)==buf_size);
+
+ buf=malloc((size_t)buf_size);
+ assert(buf);
+
+ /* Initialize dataset portion to something unique for each process */
+ memset(buf,mpi_rank,(size_t)buf_size);
+
+ for(u=0; u<num_iter; u++) {
+ /* Create file creation property list */
+ fcpl=create_fcpl();
+ assert(fcpl>0);
+
+ /* Create file access property list */
+ fapl=create_fapl(MPI_COMM_WORLD,MPI_INFO_NULL,vfl_type);
+ assert(fapl>0);
+
+ /* Get file start time */
+ start_file_time = MPI_Wtime();
+
+ /* Create file */
+ fid=H5Fcreate(file_name,H5F_ACC_TRUNC,fcpl,fapl);
+ assert(fid>0);
+
+ /* Close file creation property list */
+ ret=H5Pclose(fcpl);
+ assert(ret>=0);
+
+ /* Close file access property list */
+ ret=H5Pclose(fapl);
+ assert(ret>=0);
+
+ /* Create dataspace for dataset on disk */
+ for(i=0; i<rank; i++)
+ dims[i]=dim_size;
+
+ file_sid=H5Screate_simple(rank,dims,NULL);
+ assert(file_sid>0);
+
+ /* Create dataspace for buffer in memory */
+ for(i=0; i<rank; i++)
+ dims[i]=dim_size;
+ dims[slice_dim] /= mpi_size;
+
+ mem_sid=H5Screate_simple(rank,dims,NULL);
+ assert(mem_sid>0);
+
+ /* Create dataset creation property list */
+ dcpl=create_dcpl(use_chunks,rank,dims);
+ assert(dcpl>0);
+
+ /* Create dataset */
+ dsid = H5Dcreate2(fid, DEFAULT_DATASET_NAME, DEFAULT_HDF5_DATATYPE, file_sid, H5P_DEFAULT, dcpl, H5P_DEFAULT);
+ assert(dsid > 0);
+
+ /* Close dataset creation property list */
+ ret=H5Pclose(dcpl);
+ assert(ret>=0);
+
+ /* Select hyperslab for file dataspace */
+ for(i=0; i<rank; i++) {
+ start[i]=0;
+ count[i]=dim_size;
+ } /* end for */
+ start[slice_dim]=mpi_rank*(dim_size/mpi_size);
+ count[slice_dim]=dim_size/mpi_size;
+
+ ret = H5Sselect_hyperslab(file_sid,H5S_SELECT_SET,start,NULL,count,NULL);
+ assert(ret>=0);
+
+ /* Create dataset transfer property list */
+ dxpl=create_dxpl(par_mode);
+ assert(dxpl>0);
+
+ /* Get raw data start time */
+ start_write_time = MPI_Wtime();
+
+ /* Write hyperslab to dataset */
+ ret = H5Dwrite(dsid, DEFAULT_HDF5_DATATYPE, mem_sid,
+ file_sid, dxpl, buf);
+ assert(ret>=0);
+
+ /* Get stop time for raw data timer */
+ end_write_time = MPI_Wtime();
+
+ /* Close dataset transfer property list */
+ ret=H5Pclose(dxpl);
+ assert(ret>=0);
+
+ /* Close memory dataspace */
+ ret=H5Sclose(mem_sid);
+ assert(ret>=0);
+
+ /* Close file dataspace */
+ ret=H5Sclose(file_sid);
+ assert(ret>=0);
+
+ /* Close dataset */
+ ret=H5Dclose(dsid);
+ assert(ret>=0);
+
+ /* Close file */
+ ret=H5Fclose(fid);
+ assert(ret>=0);
+
+ /* Get stop time for file timer */
+ end_file_time = MPI_Wtime();
+
+ /* Compute timing results */
+ elap_write_time=end_write_time-start_write_time;
+ elap_file_time=end_file_time-start_file_time;
+
+ /* Collect the minimum and maximum times by MPI reduces */
+ MPI_Allreduce(&elap_write_time, &tmp_max_write_time, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
+ MPI_Allreduce(&elap_file_time, &tmp_max_file_time, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
+
+ /* Track the fastest & slowest total runs */
+ if(tmp_max_write_time>max_write_time)
+ max_write_time=tmp_max_write_time;
+ if(tmp_max_write_time<min_write_time)
+ min_write_time=tmp_max_write_time;
+ if(tmp_max_file_time>max_file_time)
+ max_file_time=tmp_max_file_time;
+ if(tmp_max_file_time<min_file_time)
+ min_file_time=tmp_max_file_time;
+ } /* end for */
+
+ /* Only print information from one node */
+ if(mpi_rank==0) {
+ /* Print information about test */
+ printf("File driver used: %s\n",vfl_type==FACC_MPIO ? "MPI-I/O" : "Unknown");
+ printf("Type of parallel access: %s\n",par_mode==H5FD_MPIO_COLLECTIVE ? "Collective" : "Independent");
+ printf("Type of dataset storage: %s\n",use_chunks ? "Chunked" : "Contiguous");
+ printf("Number of processes: %d\n",mpi_size);
+ printf("Element size: %u\n",(unsigned)sizeof(DEFAULT_C_TYPE));
+ printf("# of dimensions: %d\n",rank);
+ printf("Dimension size: %ld\n",(long)dim_size);
+ printf("Dimension sliced: %u\n",slice_dim);
+ printf("Number of elements: %lu\n",(unsigned long)((buf_size/sizeof(DEFAULT_C_TYPE))*mpi_size));
+ printf("Total dataset size (bytes): %lu\n",(unsigned long)(buf_size*mpi_size));
+ printf("Dataset size per process (bytes): %lu\n",(unsigned long)buf_size);
+
+ /* Print timing results */
+ printf("# of iterations: %u\n",num_iter);
+ printf("Maximum raw data write throughput=%6.2f MB/s (%7.3f s)\n",MB_PER_SEC((buf_size*mpi_size),min_write_time),min_write_time);
+ printf("Minimum raw data write throughput=%6.2f MB/s (%7.3f s)\n",MB_PER_SEC((buf_size*mpi_size),max_write_time),max_write_time);
+ printf("Maximum file throughput=%6.2f MB/s (%7.3f s)\n",MB_PER_SEC((buf_size*mpi_size),min_file_time),min_file_time);
+ printf("Minimum file throughput=%6.2f MB/s (%7.3f s)\n",MB_PER_SEC((buf_size*mpi_size),max_file_time),max_file_time);
+ } /* end if */
+
+done:
+ /* Free buffers allocated */
+ if(file_name)
+ free(file_name);
+ if(buf)
+ free(buf);
+
+ /* MPI termination */
+ MPI_Finalize();
+ return(0);
+} /* end main() */
diff --git a/tools/perform/build_h5perf_alone.sh b/tools/perform/build_h5perf_alone.sh
new file mode 100755
index 0000000..b65e863
--- /dev/null
+++ b/tools/perform/build_h5perf_alone.sh
@@ -0,0 +1,28 @@
+#! /bin/sh -x
+#
+# Copyright by The HDF Group.
+# Copyright by the Board of Trustees of the University of Illinois.
+# All rights reserved.
+#
+# This file is part of HDF5. The full HDF5 copyright notice, including
+# terms governing use, modification, and redistribution, is contained in
+# the files COPYING and Copyright.html. COPYING can be found at the root
+# of the source code distribution tree; Copyright.html can be found at the
+# root level of an installed copy of the electronic HDF5 document set and
+# is linked from the top-level documents page. It can also be found at
+# http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have
+# access to either file, you may request a copy from help@hdfgroup.org.
+#
+# Name: build_h5perf_alone.sh
+#
+# Puporse: Build the h5perf tool by standalone mode.
+#
+# Created: Albert Cheng, 2005/09/18
+#
+# Modification:
+#
+
+# Default to use h5pcc to build h5perf unless $H5CC is defined.
+#
+h5pcc=${H5CC:-h5pcc}
+$h5pcc -DSTANDALONE pio_perf.c pio_engine.c pio_timer.c -o h5perf
diff --git a/tools/perform/build_h5perf_serial_alone.sh b/tools/perform/build_h5perf_serial_alone.sh
new file mode 100755
index 0000000..2566609
--- /dev/null
+++ b/tools/perform/build_h5perf_serial_alone.sh
@@ -0,0 +1,28 @@
+#! /bin/sh -x
+#
+# Copyright by The HDF Group.
+# Copyright by the Board of Trustees of the University of Illinois.
+# All rights reserved.
+#
+# This file is part of HDF5. The full HDF5 copyright notice, including
+# terms governing use, modification, and redistribution, is contained in
+# the files COPYING and Copyright.html. COPYING can be found at the root
+# of the source code distribution tree; Copyright.html can be found at the
+# root level of an installed copy of the electronic HDF5 document set and
+# is linked from the top-level documents page. It can also be found at
+# http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have
+# access to either file, you may request a copy from help@hdfgroup.org.
+#
+# Name: build_h5perf_serial_alone.sh
+#
+# Puporse: Build the h5perf_serial tool by standalone mode.
+#
+# Created: Christian Chilan, 2008/09/02
+#
+# Modification:
+#
+
+# Default to use h5cc to build h5perf_serial unless $H5CC is defined.
+#
+h5cc=${H5CC:-h5cc}
+$h5cc -DSTANDALONE sio_perf.c sio_engine.c sio_timer.c -o h5perf_serial
diff --git a/tools/perform/chunk.c b/tools/perform/chunk.c
new file mode 100644
index 0000000..a3c11c1
--- /dev/null
+++ b/tools/perform/chunk.c
@@ -0,0 +1,552 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <robb@arborea.spizella.com>
+ * Thursday, May 14, 1998
+ *
+ * Purpose: Checks the effect of various I/O request sizes and raw data
+ * cache sizes. Performance depends on the amount of data read
+ * from disk and we use a filter to get that number.
+ */
+
+/* See H5private.h for how to include headers */
+#undef NDEBUG
+#include "hdf5.h"
+
+#ifdef H5_STDC_HEADERS
+# include <assert.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+
+#if !defined(H5_HAVE_ATTRIBUTE) || defined __cplusplus
+# undef __attribute__
+# define __attribute__(X) /*void*/
+# define UNUSED /*void*/
+#else
+# define UNUSED __attribute__((unused))
+#endif
+
+#define FILE_NAME "chunk.h5"
+#define LINESPOINTS "lines"
+#define CH_SIZE 100 /*squared in terms of bytes */
+#define DS_SIZE 20 /*squared in terms of chunks */
+#define FILTER_COUNTER 305
+#define READ 0
+#define WRITE 1
+#define MIN(X,Y) ((X)<(Y)?(X):(Y))
+#define MAX(X,Y) ((X)>(Y)?(X):(Y))
+#define SQUARE(X) ((X)*(X))
+
+/* The row-major test */
+#define RM_CACHE_STRT 25
+#define RM_CACHE_END 25
+#define RM_CACHE_DELT 5
+#define RM_START 0.50
+#define RM_END 5.00
+#define RM_DELTA 0.50
+#define RM_W0 0.0
+#define RM_NRDCC 521
+
+/* Diagonal test */
+#define DIAG_CACHE_STRT 25
+#define DIAG_CACHE_END 25
+#define DIAG_CACHE_DELT 5
+#define DIAG_START 0.50
+#define DIAG_END 5.00
+#define DIAG_DELTA 0.50
+/* #define DIAG_W0 0.65 */
+/* #define DIAG_NRDCC 521 */
+
+static size_t nio_g;
+static hid_t fapl_g = -1;
+
+/* Local function prototypes */
+static size_t
+counter (unsigned UNUSED flags, size_t cd_nelmts,
+ const unsigned *cd_values, size_t nbytes,
+ size_t *buf_size, void **buf);
+
+/* This message derives from H5Z */
+const H5Z_class2_t H5Z_COUNTER[1] = {{
+ H5Z_CLASS_T_VERS, /* H5Z_class_t version */
+ FILTER_COUNTER, /* Filter id number */
+ 1, 1, /* Encoding and decoding enabled */
+ "counter", /* Filter name for debugging */
+ NULL, /* The "can apply" callback */
+ NULL, /* The "set local" callback */
+ counter, /* The actual filter function */
+}};
+
+
+/*-------------------------------------------------------------------------
+ * Function: counter
+ *
+ * Purpose: Count number of bytes but don't do anything.
+ *
+ * Return: Success: src_nbytes-1
+ *
+ * Failure: never fails
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 14, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static size_t
+counter (unsigned UNUSED flags, size_t UNUSED cd_nelmts,
+ const unsigned UNUSED *cd_values, size_t nbytes,
+ size_t UNUSED *buf_size, void UNUSED **buf)
+{
+ nio_g += nbytes;
+ return nbytes;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: create_dataset
+ *
+ * Purpose: Creates a square dataset with square chunks, registers a
+ * stupid compress/uncompress pair for counting I/O, and
+ * initializes the dataset. The chunk size is in bytes, the
+ * dataset size is in terms of chunks.
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 14, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+create_dataset (void)
+{
+ hid_t file, space, dcpl, dset;
+ hsize_t size[2];
+ signed char *buf;
+
+ /* The file */
+ file = H5Fcreate (FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_g);
+
+ /* The data space */
+ size[0] = size[1] = DS_SIZE * CH_SIZE;
+ space = H5Screate_simple(2, size, size);
+
+ /* The storage layout and compression */
+ dcpl = H5Pcreate(H5P_DATASET_CREATE);
+ size[0] = size[1] = CH_SIZE;
+ H5Pset_chunk(dcpl, 2, size);
+ H5Zregister(H5Z_COUNTER);
+ H5Pset_filter(dcpl, FILTER_COUNTER, 0, 0, NULL);
+
+ /* The dataset */
+ dset = H5Dcreate2(file, "dset", H5T_NATIVE_SCHAR, space, H5P_DEFAULT, dcpl, H5P_DEFAULT);
+ assert(dset>=0);
+
+ /* The data */
+ buf = calloc(1, SQUARE (DS_SIZE*CH_SIZE));
+ H5Dwrite(dset, H5T_NATIVE_SCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf);
+ free(buf);
+
+ /* Close */
+ H5Dclose(dset);
+ H5Sclose(space);
+ H5Pclose(dcpl);
+ H5Fclose(file);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_rowmaj
+ *
+ * Purpose: Reads the entire dataset using the specified size-squared
+ * I/O requests in row major order.
+ *
+ * Return: Efficiency: data requested divided by data actually read.
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 14, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static double
+test_rowmaj (int op, size_t cache_size, size_t io_size)
+{
+ hid_t file, dset, mem_space, file_space;
+ signed char *buf = calloc (1, (size_t)(SQUARE(io_size)));
+ hsize_t i, j, hs_size[2];
+ hsize_t hs_offset[2];
+ int mdc_nelmts;
+ size_t rdcc_nelmts;
+ double w0;
+
+ H5Pget_cache (fapl_g, &mdc_nelmts, &rdcc_nelmts, NULL, &w0);
+#ifdef RM_W0
+ w0 = RM_W0;
+#endif
+#ifdef RM_NRDCC
+ rdcc_nelmts = RM_NRDCC;
+#endif
+ H5Pset_cache (fapl_g, mdc_nelmts, rdcc_nelmts,
+ cache_size*SQUARE (CH_SIZE), w0);
+ file = H5Fopen(FILE_NAME, H5F_ACC_RDWR, fapl_g);
+ dset = H5Dopen2(file, "dset", H5P_DEFAULT);
+ file_space = H5Dget_space(dset);
+ nio_g = 0;
+
+ for (i=0; i<CH_SIZE*DS_SIZE; i+=io_size) {
+#if 0
+ fprintf (stderr, "%5d\b\b\b\b\b", (int)i);
+ fflush (stderr);
+#endif
+ for (j=0; j<CH_SIZE*DS_SIZE; j+=io_size) {
+ hs_offset[0] = i;
+ hs_size[0] = MIN (io_size, CH_SIZE*DS_SIZE-i);
+ hs_offset[1] = j;
+ hs_size[1] = MIN (io_size, CH_SIZE*DS_SIZE-j);
+ mem_space = H5Screate_simple (2, hs_size, hs_size);
+ H5Sselect_hyperslab (file_space, H5S_SELECT_SET, hs_offset,
+ NULL, hs_size, NULL);
+
+ if (READ==op) {
+ H5Dread (dset, H5T_NATIVE_SCHAR, mem_space, file_space,
+ H5P_DEFAULT, buf);
+ } else {
+ H5Dwrite (dset, H5T_NATIVE_SCHAR, mem_space, file_space,
+ H5P_DEFAULT, buf);
+ }
+ H5Sclose (mem_space);
+ }
+ }
+
+ free (buf);
+ H5Sclose (file_space);
+ H5Dclose (dset);
+ H5Fclose (file);
+
+ return (double)SQUARE(CH_SIZE*DS_SIZE)/(double)nio_g;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test_diag
+ *
+ * Purpose: Reads windows diagonally across the dataset. Each window is
+ * offset from the previous window by OFFSET in the x and y
+ * directions. The reading ends after the (k,k) value is read
+ * where k is the maximum index in the dataset.
+ *
+ * Return: Efficiency.
+ *
+ * Programmer: Robb Matzke
+ * Friday, May 15, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static double
+test_diag (int op, size_t cache_size, size_t io_size, size_t offset)
+{
+ hid_t file, dset, mem_space, file_space;
+ hsize_t i, hs_size[2];
+ hsize_t nio = 0;
+ hsize_t hs_offset[2];
+ signed char *buf = calloc (1, (size_t)(SQUARE (io_size)));
+ int mdc_nelmts;
+ size_t rdcc_nelmts;
+ double w0;
+
+ H5Pget_cache (fapl_g, &mdc_nelmts, &rdcc_nelmts, NULL, &w0);
+#ifdef DIAG_W0
+ w0 = DIAG_W0;
+#endif
+#ifdef DIAG_NRDCC
+ rdcc_nelmts = DIAG_NRDCC;
+#endif
+ H5Pset_cache (fapl_g, mdc_nelmts, rdcc_nelmts,
+ cache_size*SQUARE (CH_SIZE), w0);
+ file = H5Fopen(FILE_NAME, H5F_ACC_RDWR, fapl_g);
+ dset = H5Dopen2(file, "dset", H5P_DEFAULT);
+ file_space = H5Dget_space(dset);
+ nio_g = 0;
+
+ for (i=0, hs_size[0]=io_size; hs_size[0]==io_size; i+=offset) {
+ hs_offset[0] = hs_offset[1] = i;
+ hs_size[0] = hs_size[1] = MIN (io_size, CH_SIZE*DS_SIZE-i);
+ mem_space = H5Screate_simple (2, hs_size, hs_size);
+ H5Sselect_hyperslab (file_space, H5S_SELECT_SET, hs_offset, NULL,
+ hs_size, NULL);
+ if (READ==op) {
+ H5Dread (dset, H5T_NATIVE_SCHAR, mem_space, file_space,
+ H5P_DEFAULT, buf);
+ } else {
+ H5Dwrite (dset, H5T_NATIVE_SCHAR, mem_space, file_space,
+ H5P_DEFAULT, buf);
+ }
+ H5Sclose (mem_space);
+ nio += hs_size[0]*hs_size[1];
+ if (i>0) nio -= SQUARE (io_size-offset);
+ }
+
+ free (buf);
+ H5Sclose (file_space);
+ H5Dclose (dset);
+ H5Fclose (file);
+
+ /*
+ * The extra cast in the following statement is a bug workaround for the
+ * Win32 version 5.0 compiler.
+ * 1998-11-06 ptl
+ */
+ return (double)(hssize_t)nio/(hssize_t)nio_g;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: See file prologue.
+ *
+ * Return: Success:
+ *
+ * Failure:
+ *
+ * Programmer: Robb Matzke
+ * Thursday, May 14, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+main (void)
+{
+ size_t io_size;
+ double effic, io_percent;
+ FILE *f, *d;
+ size_t cache_size;
+ double w0;
+
+ /*
+ * Create a global file access property list.
+ */
+ fapl_g = H5Pcreate (H5P_FILE_ACCESS);
+ H5Pget_cache (fapl_g, NULL, NULL, NULL, &w0);
+
+ /* Create the file */
+ create_dataset ();
+ f = fopen ("x-gnuplot", "w");
+
+ printf("Test %8s %8s %8s\n", "CacheSz", "ChunkSz", "Effic");
+ printf("--------- -------- -------- --------\n");
+
+#if 1
+ /*
+ * Test row-major reading of the dataset with various sizes of request
+ * windows.
+ */
+ if (RM_CACHE_STRT==RM_CACHE_END) {
+ fprintf (f, "set yrange [0:1.2]\n");
+ fprintf (f, "set ytics 0, 0.1, 1\n");
+ fprintf (f, "set xlabel \"%s\"\n",
+ "Request size as a fraction of chunk size");
+ fprintf (f, "set ylabel \"Efficiency\"\n");
+ fprintf (f, "set title \"Cache %d chunks, w0=%g, "
+ "Size=(total=%d, chunk=%d)\"\n",
+ RM_CACHE_STRT, w0, DS_SIZE*CH_SIZE, CH_SIZE);
+ } else {
+ fprintf (f, "set autoscale\n");
+ fprintf (f, "set hidden3d\n");
+ }
+
+ fprintf (f, "set terminal postscript\nset output \"x-rowmaj-rd.ps\"\n");
+ fprintf (f, "%s \"x-rowmaj-rd.dat\" title \"RowMaj-Read\" with %s\n",
+ RM_CACHE_STRT==RM_CACHE_END?"plot":"splot",
+ LINESPOINTS);
+ fprintf (f, "set terminal x11\nreplot\n");
+ d = fopen ("x-rowmaj-rd.dat", "w");
+ for (cache_size=RM_CACHE_STRT;
+ cache_size<=RM_CACHE_END;
+ cache_size+=RM_CACHE_DELT) {
+ for (io_percent=RM_START; io_percent<=RM_END; io_percent+=RM_DELTA) {
+ io_size = MAX (1, (size_t)(CH_SIZE*io_percent));
+ printf ("Rowmaj-rd %8d %8.2f", (int)cache_size, io_percent);
+ fflush (stdout);
+ effic = test_rowmaj (READ, cache_size, io_size);
+ printf (" %8.2f\n", effic);
+ if (RM_CACHE_STRT==RM_CACHE_END) {
+ fprintf (d, "%g %g\n", io_percent, effic);
+ } else {
+ fprintf (d, "%g\n", effic);
+ }
+ }
+ fprintf (d, "\n");
+ }
+ fclose (d);
+ fprintf (f, "pause -1\n");
+#endif
+
+#if 1
+ /*
+ * Test row-major writing of the dataset with various sizes of request
+ * windows.
+ */
+ if (RM_CACHE_STRT==RM_CACHE_END) {
+ fprintf (f, "set yrange [0:1.2]\n");
+ fprintf (f, "set ytics 0, 0.1, 1\n");
+ fprintf (f, "set xlabel \"%s\"\n",
+ "Request size as a fraction of chunk size");
+ fprintf (f, "set ylabel \"Efficiency\"\n");
+ fprintf (f, "set title \"Cache %d chunks,w0=%g, "
+ "Size=(total=%d, chunk=%d)\"\n",
+ RM_CACHE_STRT, w0, DS_SIZE*CH_SIZE, CH_SIZE);
+ } else {
+ fprintf (f, "set autoscale\n");
+ fprintf (f, "set hidden3d\n");
+ }
+
+ fprintf (f, "set terminal postscript\nset output \"x-rowmaj-wr.ps\"\n");
+ fprintf (f, "%s \"x-rowmaj-wr.dat\" title \"RowMaj-Write\" with %s\n",
+ RM_CACHE_STRT==RM_CACHE_END?"plot":"splot",
+ LINESPOINTS);
+ fprintf (f, "set terminal x11\nreplot\n");
+ d = fopen ("x-rowmaj-wr.dat", "w");
+ for (cache_size=RM_CACHE_STRT;
+ cache_size<=RM_CACHE_END;
+ cache_size+=RM_CACHE_DELT) {
+ for (io_percent=RM_START; io_percent<=RM_END; io_percent+=RM_DELTA) {
+ io_size = MAX (1, (size_t)(CH_SIZE*io_percent));
+ printf ("Rowmaj-wr %8d %8.2f", (int)cache_size, io_percent);
+ fflush (stdout);
+ effic = test_rowmaj (WRITE, cache_size, io_size);
+ printf (" %8.2f\n", effic);
+ if (RM_CACHE_STRT==RM_CACHE_END) {
+ fprintf (d, "%g %g\n", io_percent, effic);
+ } else {
+ fprintf (d, "%g\n", effic);
+ }
+ }
+ fprintf (d, "\n");
+ }
+ fclose (d);
+ fprintf (f, "pause -1\n");
+#endif
+
+#if 1
+ /*
+ * Test diagonal read
+ */
+ if (DIAG_CACHE_STRT==DIAG_CACHE_END) {
+ fprintf (f, "set yrange [0:1.2]\n");
+ fprintf (f, "set ytics 0, 0.1, 1\n");
+ fprintf (f, "set xlabel \"%s\"\n",
+ "Request size as a fraction of chunk size");
+ fprintf (f, "set ylabel \"Efficiency\"\n");
+ fprintf (f, "set title \"Cache %d chunks,w0=%g, "
+ "Size=(total=%d, chunk=%d)\"\n",
+ DIAG_CACHE_STRT, w0, DS_SIZE*CH_SIZE, CH_SIZE);
+ } else {
+ fprintf (f, "set autoscale\n");
+ fprintf (f, "set hidden3d\n");
+ }
+ fprintf (f, "set terminal postscript\nset output \"x-diag-rd.ps\"\n");
+ fprintf (f, "%s \"x-diag-rd.dat\" title \"Diag-Read\" with %s\n",
+ DIAG_CACHE_STRT==DIAG_CACHE_END?"plot":"splot", LINESPOINTS);
+ fprintf (f, "set terminal x11\nreplot\n");
+ d = fopen ("x-diag-rd.dat", "w");
+ for (cache_size=DIAG_CACHE_STRT;
+ cache_size<=DIAG_CACHE_END;
+ cache_size+=DIAG_CACHE_DELT) {
+ for (io_percent=DIAG_START;
+ io_percent<=DIAG_END;
+ io_percent+=DIAG_DELTA) {
+ io_size = MAX (1, (size_t)(CH_SIZE*io_percent));
+ printf ("Diag-rd %8d %8.2f", (int)cache_size, io_percent);
+ fflush (stdout);
+ effic = test_diag (READ, cache_size, io_size, MAX (1, io_size/2));
+ printf (" %8.2f\n", effic);
+ if (DIAG_CACHE_STRT==DIAG_CACHE_END) {
+ fprintf (d, "%g %g\n", io_percent, effic);
+ } else {
+ fprintf (d, "%g\n", effic);
+ }
+ }
+ fprintf (d, "\n");
+ }
+ fclose (d);
+ fprintf (f, "pause -1\n");
+#endif
+
+#if 1
+ /*
+ * Test diagonal write
+ */
+ if (DIAG_CACHE_STRT==DIAG_CACHE_END) {
+ fprintf (f, "set yrange [0:1.2]\n");
+ fprintf (f, "set ytics 0, 0.1, 1\n");
+ fprintf (f, "set xlabel \"%s\"\n",
+ "Request size as a fraction of chunk size");
+ fprintf (f, "set ylabel \"Efficiency\"\n");
+ fprintf (f, "set title \"Cache %d chunks, w0=%g, "
+ "Size=(total=%d, chunk=%d)\"\n",
+ DIAG_CACHE_STRT, w0, DS_SIZE*CH_SIZE, CH_SIZE);
+ } else {
+ fprintf (f, "set autoscale\n");
+ fprintf (f, "set hidden3d\n");
+ }
+ fprintf (f, "set terminal postscript\nset output \"x-diag-wr.ps\"\n");
+ fprintf (f, "%s \"x-diag-wr.dat\" title \"Diag-Write\" with %s\n",
+ DIAG_CACHE_STRT==DIAG_CACHE_END?"plot":"splot", LINESPOINTS);
+ fprintf (f, "set terminal x11\nreplot\n");
+ d = fopen ("x-diag-wr.dat", "w");
+ for (cache_size=DIAG_CACHE_STRT;
+ cache_size<=DIAG_CACHE_END;
+ cache_size+=DIAG_CACHE_DELT) {
+ for (io_percent=DIAG_START;
+ io_percent<=DIAG_END;
+ io_percent+=DIAG_DELTA) {
+ io_size = MAX (1, (size_t)(CH_SIZE*io_percent));
+ printf ("Diag-wr %8d %8.2f", (int)cache_size, io_percent);
+ fflush (stdout);
+ effic = test_diag (WRITE, cache_size, io_size, MAX (1, io_size/2));
+ printf (" %8.2f\n", effic);
+ if (DIAG_CACHE_STRT==DIAG_CACHE_END) {
+ fprintf (d, "%g %g\n", io_percent, effic);
+ } else {
+ fprintf (d, "%g\n", effic);
+ }
+ }
+ fprintf (d, "\n");
+ }
+ fclose (d);
+ fprintf (f, "pause -1\n");
+#endif
+
+
+ H5Pclose (fapl_g);
+ fclose (f);
+ return 0;
+}
+
diff --git a/tools/perform/gen_report.pl b/tools/perform/gen_report.pl
new file mode 100755
index 0000000..285f5d7
--- /dev/null
+++ b/tools/perform/gen_report.pl
@@ -0,0 +1,527 @@
+#!/usr/bin/perl
+#
+# Copyright by The HDF Group.
+# Copyright by the Board of Trustees of the University of Illinois.
+# All rights reserved.
+#
+# This file is part of HDF5. The full HDF5 copyright notice, including
+# terms governing use, modification, and redistribution, is contained in
+# the files COPYING and Copyright.html. COPYING can be found at the root
+# of the source code distribution tree; Copyright.html can be found at the
+# root level of an installed copy of the electronic HDF5 document set and
+# is linked from the top-level documents page. It can also be found at
+# http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have
+# access to either file, you may request a copy from help@hdfgroup.org.
+#
+
+#
+# Generates an ASCII and Excel-importable file of tables representing
+# the output of running the "pio_perf" command. The name of the input
+# file is important. The name should reflect the command-line options
+# used in the performance test. It needs to be of the form:
+#
+# f#[GMK].i#.d#.X#[GMK].x#[GMK]..*
+#
+# For example:
+#
+# PIO_output_f1G.i2.d1.X2M.x128K.frost
+#
+# for a 1GB sized file ran for 2 iterations with 1 dataset from xfer
+# buffer size of 128KB to 2MB on the frost machine.
+#
+# The output file will have the same name as the input, but will append
+# ".ascii" for the ASCII file and ".excel" for the Excel-importable
+# file.
+#
+# The data structure used in this program looks like:
+#
+# %results = {
+# num_proc => (
+# %xfer_size => (
+# %posix = {
+# 'write-only' => ##,
+# 'write-close' => ##,
+# 'read-only' => ##,
+# 'read-close' => ##
+# },
+# %mpio = {
+# 'write-only' => ##,
+# 'write-close' => ##,
+# 'read-only' => ##,
+# 'read-close' => ##
+# },
+# %phdf = {
+# 'write-only' => ##,
+# 'write-close' => ##,
+# 'read-only' => ##,
+# 'read-close' => ##
+# }
+# )
+# )
+# }
+
+use IO::Handle;
+use Getopt::Long;
+use List::Util qw[max];
+
+if ($#ARGV == -1) {
+ usage();
+}
+
+my ($ascii_output, $excel_output);
+
+GetOptions("data_type=s"=>\$data_type,
+ "buffer_size=i"=>\$transfer_buffer_size,
+ "procs=i"=>\$num_procs_graph,
+ "help!"=>\$help,
+ "throughput=s"=>\$throughput_type,
+ "io_type=i"=>\$io_type,
+ "3d!"=>\$plot_3d);
+
+usage() if $help or !@ARGV;
+
+$throughput_type = "average" if !$throughput_type;
+$io_type = 7 if !$io_type;
+
+foreach my $arg (@ARGV) {
+
+ if ($arg !~ /^-/) {
+ $arg =~ /f([0-9]+.)\.i([0-9]+)\.d([0-9]+)\.X([0-9]+.)\.x([0-9]+.)\.(.*)/;
+
+ my $output = $arg . $1 . ".X" . $4 . ".x" . $5 . "." . $6;
+
+ $ascii_output = $output . ".ascii";
+ $excel_output = $output . ".excel";
+
+ open(INPUT, "<$arg") or die "error: cannot open file $arg: $!\n";
+ open(ASCII_OUTPUT, ">$ascii_output") or
+ die "error: cannot open file $ascii_output: $!\n";
+ open(EXCEL_OUTPUT, ">$excel_output") or
+ die "error: cannot open file $excel_output: $!\n";
+ }
+ else
+ {
+ die "error: unrecognized option: $arg\n";
+ }
+}
+
+my %results;
+my $num_procs = 0;
+my ($xfer_size, $avg_type, $type);
+
+my $posix = 0, $mpio = 1, $phdf5 = 2;
+
+##"==== End of Parameters ===="
+
+while (<INPUT>) {
+ if (/Number of processors = ([0-9]+)/) {
+ $num_procs = $1;
+ }
+
+ if (/Transfer Buffer Size: ([0-9]+)/) {
+ $xfer_size = $1;
+ }
+
+ $type = $posix if /POSIX/;
+ $type = $mpio if /MPIO/;
+ $type = $phdf5 if /PHDF5/;
+
+ if (/Write Open/) {
+ $avg_type = "write-close";
+ } elsif (/Write/) {
+ $avg_type = "write-only";
+ } elsif (/Read Open/) {
+ $avg_type = "read-close";
+ } elsif (/Read/) {
+ $avg_type = "read-only";
+ }
+
+ if($throughput_type eq "max")
+ {
+ if (/Maximum Throughput: ( {0,2}[0-9]+\.[0-9]{2}) MB\/s/) {
+ $results{$num_procs}{$xfer_size}[$type]{$avg_type} = $1;
+ }
+ }
+ elsif($throughput_type eq "min")
+ {
+ if (/Minimum Throughput: ( {0,2}[0-9]+\.[0-9]{2}) MB\/s/) {
+ $results{$num_procs}{$xfer_size}[$type]{$avg_type} = $1;
+ }
+ }
+ elsif($throughput_type eq "average")
+ {
+ if (/Average Throughput: ( {0,2}[0-9]+\.[0-9]{2}) MB\/s/) {
+ $results{$num_procs}{$xfer_size}[$type]{$avg_type} = $1;
+ }
+ }
+}
+
+sub usage {
+ print "Usage: gen_reporl.pl [options] FILE
+ options are:\n
+ -data_type \"data_type\" plots the results for \"write-only\",\"read-only\", \"write-close\", or \"read-close\" (default is write-only)\n
+ -buffer_size \"buffer_size\" plots data from this buffer size (in kilobytes, default is 128)\n
+ -procs \"num_procs\" plots data from the run with num_procs processors (default is the highest number of processors for which there is data).\n
+ -throughput \"throughput_type\" plots either the \"max\", \"min\", or \"average\" throughput (default is average)\n
+ -io_type \"io_type\" where \"io_type\" is the bitwise or of the io_type for which plotting is desired (1 for POSIX, 2 for MPIO, 4 for PHDF5 (default is 7 (all))\n
+ -3d if present, does a 3d plot in addition to the normal ones\n";
+
+ exit 1;
+}
+
+sub create_excel_output_header {
+ my $output_header;
+ my $kb = 1024;
+ my $mb = $kb * $kb;
+
+ foreach my $key (sort { $a <=> $b } keys(%{$results{$num_procs}})) {
+ if ($key < $mb) {
+ $key /= $kb;
+ $output_header .= "\t". $key . "K";
+ } else {
+ $key /= $mb;
+ $output_header .= "\t". $key . "M";
+ }
+ }
+
+ $output_header;
+}
+
+sub create_excel_output_string {
+ my ($t) = @_;
+ my $output_content = "";
+
+ foreach my $procs (sort { $b <=> $a } keys(%results)) {
+ $output_content .= "\n$procs Procs";
+ $output_content .= "\n" . create_excel_output_header;
+ $output_content .= "\n POSIX";
+
+ foreach my $xfer (sort { $a <=> $b } keys(%{$results{$procs}})) {
+ $output_content .= "\t$results{$procs}{$xfer}[0]{$t}";
+ }
+
+ $output_content .= "\n MPIO";
+
+ foreach my $xfer (sort { $a <=> $b } keys(%{$results{$procs}})) {
+ $output_content .= "\t$results{$procs}{$xfer}[1]{$t}";
+ }
+
+ $output_content .= "\n PHDF5";
+
+ foreach my $xfer (sort { $a <=> $b } keys(%{$results{$procs}})) {
+ $output_content .= "\t$results{$procs}{$xfer}[2]{$t}";
+ }
+
+ $output_content .= "\n";
+ }
+
+ $output_content;
+}
+
+sub is_defined {
+ my ($t) = @_;
+ my $def = 1;
+
+ foreach my $procs (sort { $b <=> $a } keys(%results)) {
+ foreach my $xfer (sort { $a <=> $b } keys(%{$results{$procs}})) {
+ if (!defined($results{$procs}{$xfer}[0]{$t})) {
+ $def = 0;
+ }
+ }
+
+ foreach my $xfer (sort { $a <=> $b } keys(%{$results{$procs}})) {
+ if (!defined($results{$procs}{$xfer}[0]{$t})) {
+ $def = 0;
+ }
+ }
+
+ foreach my $xfer (sort { $a <=> $b } keys(%{$results{$procs}})) {
+ if (!defined($results{$procs}{$xfer}[0]{$t})) {
+ $def = 0;
+ }
+ }
+ }
+
+ $def;
+}
+
+sub write_excel_file {
+ print EXCEL_OUTPUT "\nWrite-Only\n";
+ print EXCEL_OUTPUT create_excel_output_string("write-only");
+ print EXCEL_OUTPUT "\nWrite-Close\n";
+ print EXCEL_OUTPUT create_excel_output_string("write-close");
+
+ if (is_defined("read-only")) {
+ print EXCEL_OUTPUT "\nRead-Only\n";
+ print EXCEL_OUTPUT create_excel_output_string("read-only");
+ print EXCEL_OUTPUT "\nRead-Close\n";
+ print EXCEL_OUTPUT create_excel_output_string("read-close");
+ }
+}
+
+sub create_ascii_output_header {
+ my $output_header = " " x 12 . "|";
+ my $kb = 1024;
+ my $mb = $kb * $kb;
+
+ foreach my $key (sort { $a <=> $b } keys(%{$results{$num_procs}})) {
+ if ($key < $mb) {
+ $key /= $kb;
+ $output_header = sprintf("$output_header %-4s |", $key . "K");
+ } else {
+ $key /= $mb;
+ $output_header = sprintf("$output_header %-4s |", $key . "M");
+ }
+ }
+
+ $output_header;
+}
+
+sub create_ascii_output_string {
+ my ($t) = @_;
+ my $output_content = "";
+ my $output_header = create_ascii_output_header;
+
+ foreach my $procs (sort { $b <=> $a } keys(%results)) {
+ $output_content .= "\n$procs Procs";
+ $output_content .= "\n$output_header\n";
+ $output_content .= "-" x length($output_header);
+ $output_content .= "\n POSIX |";
+
+ foreach my $xfer (sort { $a <=> $b } keys(%{$results{$procs}})) {
+ $output_content = sprintf("$output_content %-6s |",
+ $results{$procs}{$xfer}[0]{$t});
+ }
+
+ $output_content .= "\n ";
+ $output_content .= "-" x (length($output_header) - 4);
+ $output_content .= "\n MPI/IO |";
+
+ foreach my $xfer (sort { $a <=> $b } keys(%{$results{$procs}})) {
+ $output_content = sprintf("$output_content %-6s |",
+ $results{$procs}{$xfer}[1]{$t});
+ }
+
+ $output_content .= "\n ";
+ $output_content .= "-" x (length($output_header) - 4);
+ $output_content .= "\n PHDF5 |";
+
+ foreach my $xfer (sort { $a <=> $b } keys(%{$results{$procs}})) {
+ $output_content = sprintf("$output_content %-6s |",
+ $results{$procs}{$xfer}[2]{$t});
+ }
+
+ $output_content .= "\n";
+ $output_content .= "=" x length($output_header);
+ $output_content .= "\n";
+ }
+
+ $output_content;
+}
+
+sub write_ascii_file {
+ print ASCII_OUTPUT "\nWrite-Only";
+ print ASCII_OUTPUT "\n----------\n";
+ print ASCII_OUTPUT create_ascii_output_string("write-only");
+ print ASCII_OUTPUT "\n\nWrite-Close";
+ print ASCII_OUTPUT "\n-----------\n";
+ print ASCII_OUTPUT create_ascii_output_string("write-close");
+
+ if (is_defined("read-only")) {
+ print ASCII_OUTPUT "\n\nRead-Only";
+ print ASCII_OUTPUT "\n---------\n";
+ print ASCII_OUTPUT create_ascii_output_string("read-only");
+ print ASCII_OUTPUT "\n\nRead-Close";
+ print ASCII_OUTPUT "\n----------\n";
+ print ASCII_OUTPUT create_ascii_output_string("read-close");
+ }
+}
+
+sub draw_plot
+{
+ my($p_3d) = @_;
+
+ if($p_3d)
+ {
+ $counter = 3;
+ print GNUPLOT_PIPE "splot ";
+ }
+ else
+ {
+ $counter = 2;
+ print GNUPLOT_PIPE "plot ";
+ }
+
+ if($io_type & 1) {
+ print GNUPLOT_PIPE " \"gnuplot.data\" using 1:";
+
+ if($p_3d) { print GNUPLOT_PIPE "2:"; }
+
+ print GNUPLOT_PIPE $counter . " title 'POSIX' with linespoints";
+ $counter = $counter + 1;
+ }
+ if($io_type & 2) {
+ if($io_type & 1) { print GNUPLOT_PIPE ", "; }
+ print GNUPLOT_PIPE "\"gnuplot.data\" using 1:";
+
+ if($p_3d) { print GNUPLOT_PIPE "2:"; }
+
+ print GNUPLOT_PIPE $counter . " title 'MPIO' with linespoints";
+ $counter = $counter + 1;
+ if($io_type & 4) { print GNUPLOT_PIPE ", ";}
+ }
+ if($io_type & 4) {
+ print GNUPLOT_PIPE " \"gnuplot.data\" using 1:";
+
+ if($p_3d) { print GNUPLOT_PIPE "2:"; }
+
+ print GNUPLOT_PIPE $counter . " title 'PHDF5' with linespoints";
+
+ }
+ print GNUPLOT_PIPE "\n";
+}
+
+
+sub plot_default_graph1 {
+ open(GNUPLOT_DATA_OUTPUT, ">gnuplot.data") or
+ die "error: cannot open file gnuplot.data: $!\n";
+
+ $transfer_buffer_size = 128 if !$transfer_buffer_size;
+ $data_type = "write-only" if !$data_type;
+
+ #set up the plot
+ print GNUPLOT_PIPE "set term x11 1\n";
+ print GNUPLOT_PIPE "set xlabel \"Number of Processors\"\n";
+ print GNUPLOT_PIPE "set title \"" . $data_type . " Performance (Speed vs. Num. Procs)\"\n";
+ print GNUPLOT_PIPE "set ylabel \"Bandwdith (MB/s)\"\n";
+ print GNUPLOT_PIPE "set label 1 \"Transfer buffer size: " . $transfer_buffer_size . "K\" at graph 0.7, graph 0.7 left \n";
+
+#the next line attempts to hack gnuplot to get around it's inability to linearly scale, but logarithmically label an axis
+ print GNUPLOT_PIPE "set xtics (\"1\" 1, \"2\" 2, \"4\" 4, \"8\" 8, \"16\" 16, \"32\" 32, \"64\" 64, \"128\" 128, \"256\" 256, \"512\" 512, \"1024\" 1024)\n";
+
+
+ foreach $proc (sort { $a <=> $b }( keys %results ))
+ {
+ print GNUPLOT_DATA_OUTPUT $proc . "\t";
+ if($io_type & 1) {
+ print GNUPLOT_DATA_OUTPUT $results{$proc}{$transfer_buffer_size*1024}[0]{$data_type} . "\t";
+ }
+ if($io_type & 2) {
+ print GNUPLOT_DATA_OUTPUT $results{$proc}{$transfer_buffer_size*1024}[1]{$data_type}. "\t";
+ }
+ if($io_type & 4) {
+ print GNUPLOT_DATA_OUTPUT $results{$proc}{$transfer_buffer_size*1024}[2]{$data_type};
+ }
+ print GNUPLOT_DATA_OUTPUT "\n";
+
+ }
+
+ close(GNUPLOT_DATA_OUTPUT);
+
+ draw_plot(0);
+
+ unlink(GNUPLOT_DATA_OUTPUT);
+
+}
+
+
+sub plot_default_graph2 {
+ open(GNUPLOT_DATA_OUTPUT, ">gnuplot.data") or
+ die "error: cannot open file gnuplot.data: $!\n";
+
+ $num_procs_graph = max(sort { $a <=> $b }( keys %results )) if !$num_procs_graph;
+ print "min-rpocs: " . $num_procs_graph;
+ $data_type = "write-only" if !$data_type;
+
+ #set up the plot
+ print GNUPLOT_PIPE "set term x11 2\n";
+ print GNUPLOT_PIPE "set xlabel \"Transfer Buffer Size (in bytes)\"\n";
+ print GNUPLOT_PIPE "set title \"" . $data_type . " Performance (Speed vs. Transfer Buffer Size)\"\n";
+ print GNUPLOT_PIPE "set ylabel \"Bandwdith (MB/s)\"\n";
+ print GNUPLOT_PIPE "set label 1 \"Procs: " . $num_procs_graph . "\" at graph 0.7, graph 0.7 left \n";
+
+#the next line attempts to hack gnuplot to get around it's inability to linearly scale, but logarithmically label an axis
+ print GNUPLOT_PIPE "set xtics (\"4K\" 4*1024, \"8K\" 8*1024, \"16K\" 16*1024, \"32K\" 32*1024, \"64K\" 64*1024, \"128K\" 128*1024, \"256K\" 256*1024, \"512K\" 512*1024, \"1M\" 1024*1024, \"2M\" 2048*1024, \"4M\" 4096*1024, \"8M\" 8192*1024, \"16M\" 16384*1024)\n";
+
+ foreach $xfer (sort {$a <=> $b} ( keys %{$results{$num_procs_graph}} ))
+ {
+ print GNUPLOT_DATA_OUTPUT $xfer . "\t";
+ if($io_type & 1) {
+ print GNUPLOT_DATA_OUTPUT $results{$num_procs_graph}{$xfer}[0]{$data_type} . "\t";
+ }
+ if($io_type & 2) {
+ print GNUPLOT_DATA_OUTPUT $results{$num_procs_graph}{$xfer}[1]{$data_type}. "\t";
+ }
+ if($io_type & 4) {
+ print GNUPLOT_DATA_OUTPUT $results{$num_procs_graph}{$xfer}[2]{$data_type};
+ }
+ print GNUPLOT_DATA_OUTPUT "\n";
+
+ }
+
+ close(GNUPLOT_DATA_OUTPUT);
+
+ draw_plot(0);
+
+ unlink(GNUPLOT_DATA_OUTPUT);
+}
+
+sub plot_3d_graph3 {
+ open(GNUPLOT_DATA_OUTPUT, ">gnuplot.data") or
+ die "error: cannot open file gnuplot.data: $!\n";
+
+ #set up the plot
+ print GNUPLOT_PIPE "set term x11 3\n";
+ print GNUPLOT_PIPE "set xlabel \"Num. Processors\"\n";
+ print GNUPLOT_PIPE "set title \"Write Speed v. No. Procs v. Buffer Size\"\n";
+ print GNUPLOT_PIPE "set ylabel \"Buffer Size (bytes)\"\n";
+ print GNUPLOT_PIPE "set zlabel \"Bandwidth (in MB/s)\"\n";
+ print GNUPLOT_PIPE "set nolabel\n";
+ print GNUPLOT_PIPE "set dgrid3d 30,30\n";
+ print GNUPLOT_PIPE "set hidden3d\n";
+
+#the next lines attempts to hack gnuplot to get around it's inability to linearly scale, but logarithmically label an axis
+ print GNUPLOT_PIPE "set xtics (\"1\" 1, \"2\" 2, \"4\" 4, \"8\" 8, \"16\" 16, \"32\" 32, \"64\" 64, \"128\" 128, \"256\" 256, \"512\" 512, \"1024\" 1024)\n";
+ print GNUPLOT_PIPE "set ytics (\"4K\" 4*1024, \"8K\" 8*1024, \"16K\" 16*1024, \"32K\" 32*1024, \"64K\" 64*1024, \"128K\" 128*1024, \"256K\" 256*1024, \"512K\" 512*1024, \"1M\" 1024*1024, \"2M\" 2048*1024, \"4M\" 4096*1024, \"8M\" 8192*1024, \"16M\" 16384*1024)\n";
+
+
+#Read speed on z-axis, processors on x, buffer size on y.
+
+ foreach $proc (sort { $a <=> $b }( keys %results ))
+ {
+ foreach $xfer (sort {$a <=> $b} ( keys %{$results{$proc}} ))
+ {
+ print GNUPLOT_DATA_OUTPUT $proc . "\t" . $xfer . "\t";
+ if($io_type & 1) {
+ print GNUPLOT_DATA_OUTPUT $results{$proc}{$xfer}[0]{"write-only"} . "\t";
+ }
+ if($io_type & 2) {
+ print GNUPLOT_DATA_OUTPUT $results{$proc}{$xfer}[1]{"write-only"}. "\t";
+ }
+ if($io_type & 4) {
+ print GNUPLOT_DATA_OUTPUT $results{$proc}{$xfer}[2]{"write-only"};
+ }
+ print GNUPLOT_DATA_OUTPUT "\n";
+
+ }
+ }
+
+ close(GNUPLOT_DATA_OUTPUT);
+
+ draw_plot(1);
+
+ unlink(GNUPLOT_DATA_OUTPUT);
+}
+
+open(GNUPLOT_PIPE, "| tee gnuplot.script | gnuplot -persist") || die "Couldn't run gnuplot: $!\n";
+GNUPLOT_PIPE->autoflush(1);
+
+write_excel_file;
+write_ascii_file;
+plot_default_graph1;
+sleep 1;
+plot_default_graph2;
+sleep 1;
+
+plot_3d_graph3 if $plot_3d;
+close(GNUPLOT_PIPE);
diff --git a/tools/perform/iopipe.c b/tools/perform/iopipe.c
new file mode 100644
index 0000000..85063fa
--- /dev/null
+++ b/tools/perform/iopipe.c
@@ -0,0 +1,503 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Thursday, March 12, 1998
+ */
+
+/* See H5private.h for how to include headers */
+#include "hdf5.h"
+
+#include "H5private.h"
+
+#ifdef H5_HAVE_SYS_TIMEB
+#include <sys/timeb.h>
+#endif
+
+
+#define RAW_FILE_NAME "iopipe.raw"
+#define HDF5_FILE_NAME "iopipe.h5"
+#define HEADING "%-16s"
+#define PROGRESS '='
+
+#if 0
+/* Normal testing */
+#define REQUEST_SIZE_X 4579
+#define REQUEST_SIZE_Y 4579
+#define NREAD_REQUESTS 45
+#define NWRITE_REQUESTS 45
+#else
+/* Speedy testing */
+#define REQUEST_SIZE_X 1000
+#define REQUEST_SIZE_Y 1000
+#define NREAD_REQUESTS 45
+#define NWRITE_REQUESTS 45
+#endif
+
+
+/*-------------------------------------------------------------------------
+ * Function: print_stats
+ *
+ * Purpose: Prints statistics
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Thursday, March 12, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifdef H5_HAVE_GETRUSAGE
+static void
+print_stats (const char *prefix,
+ struct rusage *r_start, struct rusage *r_stop,
+ struct timeval *t_start, struct timeval *t_stop,
+ size_t nbytes)
+#else /* H5_HAVE_GETRUSAGE */
+static void
+print_stats (const char *prefix,
+ struct timeval *r_start, struct timeval *r_stop,
+ struct timeval *t_start, struct timeval *t_stop,
+ size_t nbytes)
+#endif /* H5_HAVE_GETRUSAGE */
+{
+ double e_time, bw;
+#ifdef H5_HAVE_GETRUSAGE
+ double u_time, s_time;
+
+ u_time = ((double)(r_stop->ru_utime.tv_sec)+
+ (double)(r_stop->ru_utime.tv_usec)/1000000.0) -
+ ((double)(r_start->ru_utime.tv_sec)+
+ (double)(r_start->ru_utime.tv_usec)/1000000.0);
+
+ s_time = ((double)(r_stop->ru_stime.tv_sec)+
+ (double)(r_stop->ru_stime.tv_usec)/1000000.0) -
+ ((double)(r_start->ru_stime.tv_sec)+
+ (double)(r_start->ru_stime.tv_usec)/1000000.0);
+#endif
+#ifndef H5_HAVE_SYS_TIMEB
+ e_time = ((double)(t_stop->tv_sec)+
+ (double)(t_stop->tv_usec)/1000000.0) -
+ ((double)(t_start->tv_sec)+
+ (double)(t_start->tv_usec)/1000000.0);
+#else
+ e_time = ((double)(t_stop->tv_sec)+
+ (double)(t_stop->tv_usec)/1000.0) -
+ ((double)(t_start->tv_sec)+
+ (double)(t_start->tv_usec)/1000.0);
+#endif
+ bw = (double)nbytes / e_time;
+
+#ifdef H5_HAVE_GETRUSAGE
+ printf (HEADING "%1.2fuser %1.2fsystem %1.2felapsed %1.2fMB/s\n",
+ prefix, u_time, s_time, e_time, bw/(1024*1024));
+#else
+ printf (HEADING "%1.2felapsed %1.2fMB/s\n",
+ prefix, e_time, bw/(1024*1024));
+#endif
+
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: synchronize
+ *
+ * Purpose:
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Thursday, March 12, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+synchronize (void)
+{
+#ifdef H5_HAVE_SYSTEM
+#if defined(H5_HAVE_WIN32_API) && ! defined(__CYGWIN__)
+ _flushall();
+#else
+ HDsystem("sync");
+ HDsystem("df >/dev/null");
+#endif
+#endif
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose:
+ *
+ * Return: Success:
+ *
+ * Failure:
+ *
+ * Programmer: Robb Matzke
+ * Thursday, March 12, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+main (void)
+{
+ static hsize_t size[2] = {REQUEST_SIZE_X, REQUEST_SIZE_Y};
+ static unsigned nread = NREAD_REQUESTS, nwrite = NWRITE_REQUESTS;
+
+ unsigned char *the_data = NULL;
+ hid_t file, dset, file_space = -1;
+ herr_t status;
+#ifdef H5_HAVE_GETRUSAGE
+ struct rusage r_start, r_stop;
+#else
+ struct timeval r_start, r_stop;
+#endif
+ struct timeval t_start, t_stop;
+ int fd;
+ unsigned u;
+ hssize_t n;
+ off_t offset;
+ hsize_t start[2];
+ hsize_t count[2];
+
+
+#ifdef H5_HAVE_SYS_TIMEB
+ struct _timeb *tbstart = malloc(sizeof(struct _timeb));
+ struct _timeb *tbstop = malloc(sizeof(struct _timeb));
+#endif
+ /*
+ * The extra cast in the following statement is a bug workaround for the
+ * Win32 version 5.0 compiler.
+ * 1998-11-06 ptl
+ */
+ printf ("I/O request size is %1.1fMB\n",
+ (double)(hssize_t)(size[0]*size[1])/1024.0*1024);
+
+ /* Open the files */
+ file = H5Fcreate (HDF5_FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
+ assert (file>=0);
+ fd = HDopen (RAW_FILE_NAME, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ assert (fd>=0);
+
+ /* Create the dataset */
+ file_space = H5Screate_simple (2, size, size);
+ assert(file_space >= 0);
+ dset = H5Dcreate2(file, "dset", H5T_NATIVE_UCHAR, file_space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ assert(dset >= 0);
+ the_data = (unsigned char *)malloc((size_t)(size[0] * size[1]));
+
+ /* initial fill for lazy malloc */
+ HDmemset(the_data, 0xAA, (size_t)(size[0] * size[1]));
+
+ /* Fill raw */
+ synchronize ();
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_start);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_start, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstart);
+#endif
+#endif
+ fprintf (stderr, HEADING, "fill raw");
+ for(u = 0; u < nwrite; u++) {
+ putc (PROGRESS, stderr);
+ HDfflush(stderr);
+ HDmemset(the_data, 0xAA, (size_t)(size[0]*size[1]));
+ }
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_stop);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_stop, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstop);
+ t_start.tv_sec = tbstart->time;
+ t_start.tv_usec = tbstart->millitm;
+ t_stop.tv_sec = tbstop->time;
+ t_stop.tv_usec = tbstop->millitm;
+#endif
+#endif
+ putc ('\n', stderr);
+ print_stats ("fill raw",
+ &r_start, &r_stop, &t_start, &t_stop,
+ (size_t)(nread*size[0]*size[1]));
+
+
+ /* Fill hdf5 */
+ synchronize ();
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_start);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_start, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstart);
+#endif
+#endif
+ fprintf (stderr, HEADING, "fill hdf5");
+ for(u = 0; u < nread; u++) {
+ putc (PROGRESS, stderr);
+ HDfflush(stderr);
+ status = H5Dread (dset, H5T_NATIVE_UCHAR, file_space, file_space,
+ H5P_DEFAULT, the_data);
+ assert (status>=0);
+ }
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_stop);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_stop, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstop);
+ t_start.tv_sec = tbstart->time;
+ t_start.tv_usec = tbstart->millitm;
+ t_stop.tv_sec = tbstop->time;
+ t_stop.tv_usec = tbstop->millitm;
+#endif
+#endif
+ putc ('\n', stderr);
+ print_stats ("fill hdf5",
+ &r_start, &r_stop, &t_start, &t_stop,
+ (size_t)(nread*size[0]*size[1]));
+
+ /* Write the raw dataset */
+ synchronize ();
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_start);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_start, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstart);
+#endif
+#endif
+ fprintf (stderr, HEADING, "out raw");
+ for(u = 0; u < nwrite; u++) {
+ putc (PROGRESS, stderr);
+ HDfflush(stderr);
+ offset = HDlseek (fd, (off_t)0, SEEK_SET);
+ assert (0==offset);
+ n = HDwrite (fd, the_data, (size_t)(size[0]*size[1]));
+ assert (n>=0 && (size_t)n==size[0]*size[1]);
+ }
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_stop);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_stop, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstop);
+ t_start.tv_sec = tbstart->time;
+ t_start.tv_usec = tbstart->millitm;
+ t_stop.tv_sec = tbstop->time;
+ t_stop.tv_usec = tbstop->millitm;
+#endif
+#endif
+ putc ('\n', stderr);
+ print_stats ("out raw",
+ &r_start, &r_stop, &t_start, &t_stop,
+ (size_t)(nread*size[0]*size[1]));
+
+ /* Write the hdf5 dataset */
+ synchronize ();
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_start);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_start, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstart);
+#endif
+#endif
+ fprintf (stderr, HEADING, "out hdf5");
+ for(u = 0; u < nwrite; u++) {
+ putc (PROGRESS, stderr);
+ HDfflush(stderr);
+ status = H5Dwrite (dset, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL,
+ H5P_DEFAULT, the_data);
+ assert (status>=0);
+ }
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_stop);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_stop, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstop);
+ t_start.tv_sec = tbstart->time;
+ t_start.tv_usec = tbstart->millitm;
+ t_stop.tv_sec = tbstop->time;
+ t_stop.tv_usec = tbstop->millitm;
+#endif
+#endif
+ putc ('\n', stderr);
+ print_stats ("out hdf5",
+ &r_start, &r_stop, &t_start, &t_stop,
+ (size_t)(nread*size[0]*size[1]));
+
+ /* Read the raw dataset */
+ synchronize ();
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_start);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_start, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstart);
+#endif
+#endif
+ fprintf (stderr, HEADING, "in raw");
+ for(u = 0; u < nread; u++) {
+ putc (PROGRESS, stderr);
+ HDfflush(stderr);
+ offset = HDlseek (fd, (off_t)0, SEEK_SET);
+ assert (0==offset);
+ n = HDread (fd, the_data, (size_t)(size[0]*size[1]));
+ assert (n>=0 && (size_t)n==size[0]*size[1]);
+ }
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_stop);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_stop, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstop);
+ t_start.tv_sec = tbstart->time;
+ t_start.tv_usec = tbstart->millitm;
+ t_stop.tv_sec = tbstop->time;
+ t_stop.tv_usec = tbstop->millitm;
+#endif
+#endif
+ putc ('\n', stderr);
+ print_stats ("in raw",
+ &r_start, &r_stop, &t_start, &t_stop,
+ (size_t)(nread*size[0]*size[1]));
+
+
+ /* Read the hdf5 dataset */
+ synchronize ();
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_start);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_start, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstart);
+#endif
+#endif
+ fprintf (stderr, HEADING, "in hdf5");
+ for(u = 0; u < nread; u++) {
+ putc (PROGRESS, stderr);
+ HDfflush(stderr);
+ status = H5Dread (dset, H5T_NATIVE_UCHAR, file_space, file_space,
+ H5P_DEFAULT, the_data);
+ assert (status>=0);
+ }
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_stop);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_stop, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstop);
+ t_start.tv_sec = tbstart->time;
+ t_start.tv_usec = tbstart->millitm;
+ t_stop.tv_sec = tbstop->time;
+ t_stop.tv_usec = tbstop->millitm;
+#endif
+#endif
+ putc ('\n', stderr);
+ print_stats ("in hdf5",
+ &r_start, &r_stop, &t_start, &t_stop,
+ (size_t)(nread*size[0]*size[1]));
+
+ /* Read hyperslab */
+ assert (size[0]>20 && size[1]>20);
+ start[0] = start[1] = 10;
+ count[0] = count[1] = size[0]-20;
+ status = H5Sselect_hyperslab (file_space, H5S_SELECT_SET, start, NULL, count, NULL);
+ assert (status>=0);
+ synchronize ();
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_start);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_start, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstart);
+#endif
+#endif
+ fprintf (stderr, HEADING, "in hdf5 partial");
+ for(u = 0; u < nread; u++) {
+ putc (PROGRESS, stderr);
+ HDfflush(stderr);
+ status = H5Dread (dset, H5T_NATIVE_UCHAR, file_space, file_space,
+ H5P_DEFAULT, the_data);
+ assert (status>=0);
+ }
+#ifdef H5_HAVE_GETRUSAGE
+ HDgetrusage(RUSAGE_SELF, &r_stop);
+#endif
+#ifdef H5_HAVE_GETTIMEOFDAY
+ HDgettimeofday(&t_stop, NULL);
+#else
+#ifdef H5_HAVE_SYS_TIMEB
+ _ftime(tbstop);
+ t_start.tv_sec = tbstart->time;
+ t_start.tv_usec = tbstart->millitm;
+ t_stop.tv_sec = tbstop->time;
+ t_stop.tv_usec = tbstop->millitm;
+#endif
+#endif
+ putc('\n', stderr);
+ print_stats("in hdf5 partial",
+ &r_start, &r_stop, &t_start, &t_stop,
+ (size_t)(nread*count[0]*count[1]));
+
+
+
+ /* Close everything */
+ HDclose(fd);
+ H5Dclose(dset);
+ H5Sclose(file_space);
+ H5Fclose(file);
+ free(the_data);
+
+ return 0;
+}
+
diff --git a/tools/perform/overhead.c b/tools/perform/overhead.c
new file mode 100644
index 0000000..9341e64
--- /dev/null
+++ b/tools/perform/overhead.c
@@ -0,0 +1,416 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Robb Matzke <matzke@llnl.gov>
+ * Monday, September 28, 1998
+ *
+ * Purpose: Creates a chunked dataset and measures the storage overhead.
+ */
+
+/* See H5private.h for how to include headers */
+#undef NDEBUG
+#include "hdf5.h"
+#include "H5private.h"
+
+#ifdef H5_STDC_HEADERS
+# include <ctype.h>
+# include <fcntl.h>
+# include <stdlib.h>
+# include <sys/stat.h>
+# include <string.h>
+#endif
+
+#ifdef H5_HAVE_IO_H
+# include <io.h>
+#endif
+
+#ifdef H5_HAVE_UNISTD_H
+# include <sys/types.h>
+# include <unistd.h>
+#endif
+
+#ifdef H5_HAVE_IO_H
+# include <io.h>
+#endif
+
+#ifndef H5_HAVE_ATTRIBUTE
+# undef __attribute__
+# define __attribute__(X) /*void*/
+# define UNUSED /*void*/
+#else
+# define UNUSED __attribute__((unused))
+#endif
+
+#define FILE_NAME_1 "overhead.h5"
+#ifndef FALSE
+#define FALSE 0
+#endif /* FALSE */
+#ifndef TRUE
+#define TRUE 1
+#endif /* TRUE */
+
+typedef enum fill_t {
+ FILL_ALL,
+ FILL_FORWARD,
+ FILL_REVERSE,
+ FILL_INWARD,
+ FILL_OUTWARD,
+ FILL_RANDOM
+} fill_t;
+
+
+/*-------------------------------------------------------------------------
+ * Function: usage
+ *
+ * Purpose: Prints a usage message and exits.
+ *
+ * Return: never returns
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, September 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+usage(const char *prog)
+{
+ fprintf(stderr, "usage: %s [STYLE|cache] [LEFT [MIDDLE [RIGHT]]]\n",
+ prog);
+ fprintf(stderr, "\
+ STYLE is the order that the dataset is filled and should be one of:\n\
+ forward -- Fill the dataset from lowest address to highest\n\
+ address. This style tests the right split ratio.\n\
+ reverse -- Fill the dataset from highest address to lowest\n\
+ address. This is the reverse order of `forward' and\n\
+ tests the left split ratio.\n\
+ inward -- Fill beginning at both the lowest and highest\n\
+ addresses and work in toward the center of the\n\
+ dataset. This tests the middle split ratio.\n\
+ outward -- Start at the center of the dataset and work outward\n\
+ toward the lowest and highest addresses. This tests\n\
+ both left and right split ratios.\n\
+ random -- Write the chunks of the dataset in random order. This\n\
+ tests all split ratios.\n\
+ If no fill style is specified then all fill styles are tried and a\n\
+ single value is printed for each one.\n\
+\n\
+ If the word `cache' is used instead of a fill style then the raw data\n\
+ cache is enabled. It is not possible to enable the raw data cache when\n\
+ a specific fill style is used because H5Fflush() is called after each\n\
+ chunk is written in order to calculate overhead during the test. If\n\
+ the cache is enabled then chunks are written to disk in different orders\n\
+ than the actual H5Dwrite() calls in the test due to collisions and the\n\
+ resulting B-tree will be split differently.\n\
+\n\
+ LEFT, MIDDLE, and RIGHT are the ratios to use for splitting and should\n\
+ be values between zero and one, inclusive.\n");
+ exit(1);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: cleanup
+ *
+ * Purpose: Removes test files
+ *
+ * Return: void
+ *
+ * Programmer: Robb Matzke
+ * Thursday, June 4, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+cleanup (void)
+{
+ if (!getenv ("HDF5_NOCLEANUP")) {
+ remove (FILE_NAME_1);
+ }
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: display_error_cb
+ *
+ * Purpose: Displays the error stack after printing "*FAILED*".
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, March 4, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+display_error_cb (hid_t estack, void UNUSED *client_data)
+{
+ puts ("*FAILED*");
+ H5Eprint2(estack, stdout);
+
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: test
+ *
+ * Purpose: The guts of the test
+ *
+ * Return: Success: 0
+ *
+ * Failure: number of errors
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, September 30, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+test(fill_t fill_style, const double splits[],
+ hbool_t verbose, hbool_t use_rdcc)
+{
+ hid_t file = (-1), fapl = (-1), dcpl = (-1), xfer = (-1), mspace = (-1), fspace = (-1), dset = (-1);
+ hsize_t ch_size[1] = {1}; /*chunk size */
+ hsize_t cur_size[1] = {1000}; /*current dataset size */
+ hsize_t max_size[1] = {H5S_UNLIMITED}; /*maximum dataset size */
+ hsize_t hs_start[1]; /*hyperslab start offset*/
+ hsize_t hs_count[1] = {1}; /*hyperslab nelmts */
+ int fd = (-1); /*h5 file direct */
+ int *had = NULL; /*for random filling */
+ const char *sname=NULL; /*fill style nam */
+ int mdc_nelmts; /*num meta objs to cache*/
+ hsize_t i;
+ int j;
+ h5_stat_t sb;
+
+ if((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0) goto error;
+ if(!use_rdcc) {
+ if(H5Pget_cache(fapl, &mdc_nelmts, NULL, NULL, NULL) < 0) goto error;
+ if(H5Pset_cache(fapl, mdc_nelmts, 0, 0, 0.0) < 0) goto error;
+ }
+ if((file = H5Fcreate(FILE_NAME_1, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0) goto error;
+ if((dcpl = H5Pcreate(H5P_DATASET_CREATE)) < 0) goto error;
+ if(H5Pset_chunk(dcpl, 1, ch_size) < 0) goto error;
+ if((xfer = H5Pcreate(H5P_DATASET_XFER)) < 0) goto error;
+ if(H5Pset_btree_ratios(xfer, splits[0], splits[1], splits[2]) < 0) goto error;
+ if((fspace = H5Screate_simple(1, cur_size, max_size)) < 0) goto error;
+ if((mspace = H5Screate_simple(1, ch_size, ch_size)) < 0) goto error;
+ if((dset = H5Dcreate2(file, "chunked", H5T_NATIVE_INT,
+ fspace, H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0) goto error;
+ if ((fd=HDopen(FILE_NAME_1, O_RDONLY, 0666)) < 0) goto error;
+
+ if(FILL_RANDOM==fill_style)
+ had = calloc((size_t)cur_size[0], sizeof(int));
+
+ for (i=1; i<=cur_size[0]; i++) {
+
+ /* Decide which chunk to write to */
+ switch (fill_style) {
+ case FILL_FORWARD:
+ hs_start[0] = i-1;
+ break;
+ case FILL_REVERSE:
+ hs_start[0] = cur_size[0]-i;
+ break;
+ case FILL_INWARD:
+ hs_start[0] = i%2 ? i/2 : cur_size[0]-i/2;
+ break;
+ case FILL_OUTWARD:
+ j = (int)(cur_size[0]-i)+1;
+ hs_start[0] = j%2 ? j/2 : (hssize_t)cur_size[0]-j/2;
+ break;
+ case FILL_RANDOM:
+ for (j=HDrand()%(int)cur_size[0]; had[j]; j=(j+1)%(int)cur_size[0])
+ /*void*/;
+ hs_start[0] = j;
+ had[j] = 1;
+ break;
+ case FILL_ALL:
+ abort();
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown fill style\n");
+ goto error;
+ break;
+ }
+
+ /* Write the chunk */
+ if (H5Sselect_hyperslab(fspace, H5S_SELECT_SET, hs_start, NULL,
+ hs_count, NULL) < 0) goto error;
+ if (H5Dwrite(dset, H5T_NATIVE_INT, mspace, fspace, xfer, &i) < 0) {
+ goto error;
+ }
+
+ /* Determine overhead */
+ if (verbose) {
+ if (H5Fflush(file, H5F_SCOPE_LOCAL) < 0) goto error;
+ if (HDfstat(fd, &sb) < 0) goto error;
+ /*
+ * The extra cast in the following statement is a bug workaround
+ * for the Win32 version 5.0 compiler.
+ * 1998-11-06 ptl
+ */
+ printf("%4lu %8.3f ***\n",
+ (unsigned long)i,
+ (double)(hssize_t)(sb.st_size-i*sizeof(int))/(hssize_t)i);
+ }
+ }
+
+ if(had) {
+ free(had);
+ had = NULL;
+ } /* end if */
+
+ H5Dclose(dset);
+ H5Sclose(mspace);
+ H5Sclose(fspace);
+ H5Pclose(dcpl);
+ H5Pclose(xfer);
+ H5Fclose(file);
+
+ if (!verbose) {
+ switch (fill_style) {
+ case FILL_FORWARD:
+ sname = "forward";
+ break;
+ case FILL_REVERSE:
+ sname = "reverse";
+ break;
+ case FILL_INWARD:
+ sname = "inward";
+ break;
+ case FILL_OUTWARD:
+ sname = "outward";
+ break;
+ case FILL_RANDOM:
+ sname = "random";
+ break;
+ case FILL_ALL:
+ abort();
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown fill style\n");
+ goto error;
+ break;
+ }
+
+ if (HDfstat(fd, &sb) < 0) goto error;
+ printf("%-7s %8.3f\n", sname,
+ (double)(hssize_t)(sb.st_size-cur_size[0]*sizeof(int))/
+ (hssize_t)cur_size[0]);
+ }
+ HDclose(fd);
+
+ return 0;
+
+ error:
+ H5Dclose(dset);
+ H5Sclose(mspace);
+ H5Sclose(fspace);
+ H5Pclose(dcpl);
+ H5Pclose(xfer);
+ H5Fclose(file);
+ if(had)
+ free(had);
+ HDclose(fd);
+ return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose:
+ *
+ * Return: Success: zero
+ *
+ * Failure: non-zero
+ *
+ * Programmer: Robb Matzke
+ * Monday, September 28, 1998
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+main(int argc, char *argv[])
+{
+ hid_t xfer;
+ fill_t fill_style = FILL_ALL;
+ hbool_t use_cache = FALSE;
+ double splits[3];
+ int i, j, nerrors=0;
+
+ /* Default split ratios */
+ H5Eset_auto2(H5E_DEFAULT, display_error_cb, NULL);
+
+ if((xfer = H5Pcreate(H5P_DATASET_XFER)) < 0) goto error;
+ if(H5Pget_btree_ratios(xfer, splits+0, splits+1, splits+2) < 0) goto error;
+ if(H5Pclose(xfer) < 0) goto error;
+
+ /* Parse command-line options */
+ for(i = 1, j = 0; i < argc; i++) {
+ if (!strcmp(argv[i], "forward")) {
+ fill_style = FILL_FORWARD;
+ } else if (!strcmp(argv[i], "reverse")) {
+ fill_style = FILL_REVERSE;
+ } else if (!strcmp(argv[i], "inward")) {
+ fill_style = FILL_INWARD;
+ } else if (!strcmp(argv[i], "outward")) {
+ fill_style = FILL_OUTWARD;
+ } else if (!strcmp(argv[i], "random")) {
+ fill_style = FILL_RANDOM;
+ } else if (!strcmp(argv[i], "cache")) {
+ use_cache = TRUE;
+ } else if (j<3 && (isdigit(argv[i][0]) || '.'==argv[i][0])) {
+ splits[j++] = strtod(argv[i], NULL);
+ } else {
+ usage(argv[0]);
+ }
+ }
+
+ if (FILL_ALL==fill_style) {
+ printf("%-7s %8s\n", "Style", "Bytes/Chunk");
+ printf("%-7s %8s\n", "-----", "-----------");
+ nerrors += test(FILL_FORWARD, splits, FALSE, use_cache);
+ nerrors += test(FILL_REVERSE, splits, FALSE, use_cache);
+ nerrors += test(FILL_INWARD, splits, FALSE, use_cache);
+ nerrors += test(FILL_OUTWARD, splits, FALSE, use_cache);
+ nerrors += test(FILL_RANDOM, splits, FALSE, use_cache);
+ }
+ else {
+ if (use_cache) usage(argv[0]);
+ nerrors += test(fill_style, splits, TRUE, FALSE);
+ }
+ if (nerrors>0) goto error;
+ cleanup();
+ return 0;
+
+ error:
+ fprintf(stderr, "*** ERRORS DETECTED ***\n");
+ return 1;
+}
diff --git a/tools/perform/perf.c b/tools/perform/perf.c
new file mode 100644
index 0000000..7d329f0
--- /dev/null
+++ b/tools/perform/perf.c
@@ -0,0 +1,482 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Author: Albert Cheng of NCSA, May 1, 2001.
+ * This is derived from code given to me by Robert Ross.
+ *
+ * NOTE: This code assumes that all command line arguments make it out to all
+ * the processes that make up the parallel job, which isn't always the case.
+ * So if it doesn't work on some platform, that might be why.
+ */
+
+#include "hdf5.h"
+#include "H5private.h"
+#ifdef H5_HAVE_PARALLEL
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#ifdef H5_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <string.h>
+#if defined(H5_TIME_WITH_SYS_TIME)
+# include <sys/time.h>
+# include <time.h>
+#elif defined(H5_HAVE_SYS_TIME_H)
+# include <sys/time.h>
+#else
+# include <time.h>
+#endif
+#include <mpi.h>
+#ifndef MPI_FILE_NULL /*MPIO may be defined in mpi.h already */
+# include <mpio.h>
+#endif
+
+/* Macro definitions */
+/* Verify:
+ * if val is false (0), print mesg and if fatal is true (non-zero), die.
+ */
+#define H5FATAL 1
+#define VRFY(val, mesg, fatal) do { \
+ if (!val) { \
+ printf("Proc %d: ", mynod); \
+ printf("*** Assertion failed (%s) at line %4d in %s\n", \
+ mesg, (int)__LINE__, __FILE__); \
+ if (fatal){ \
+ fflush(stdout); \
+ goto die_jar_jar_die; \
+ } \
+ } \
+} while(0)
+#define RANK 1
+#define MAX_PATH 1024
+
+hsize_t dims[RANK]; /* dataset dim sizes */
+hsize_t block[RANK], stride[RANK], count[RANK];
+hssize_t start[RANK];
+hid_t fid; /* HDF5 file ID */
+hid_t acc_tpl; /* File access templates */
+hid_t sid; /* Dataspace ID */
+hid_t file_dataspace; /* File dataspace ID */
+hid_t mem_dataspace; /* memory dataspace ID */
+hid_t dataset; /* Dataset ID */
+hsize_t opt_alignment = 1;
+hsize_t opt_threshold = 1;
+int opt_split_vfd = 0;
+char *meta_ext, *raw_ext; /* holds the meta and raw file extension if */
+ /* opt_split_vfd is set */
+
+
+/* DEFAULT VALUES FOR OPTIONS */
+int64_t opt_block = 1048576*16;
+int opt_iter = 1;
+int opt_stripe = -1;
+int opt_correct = 0;
+int amode = O_RDWR | O_CREAT;
+char opt_file[256] = "perftest.out";
+char opt_pvfstab[256] = "notset";
+int opt_pvfstab_set = 0;
+
+const char *FILENAME[] = {
+ opt_file,
+ NULL
+};
+
+/* function prototypes */
+static int parse_args(int argc, char **argv);
+
+extern int errno;
+
+/* globals needed for getopt */
+extern char *optarg;
+
+int main(int argc, char **argv)
+{
+ char *buf, *tmp, *buf2, *tmp2, *check;
+ int i, j, mynod=0, nprocs=1, err, my_correct = 1, correct, myerrno;
+ double stim, etim;
+ double write_tim = 0;
+ double read_tim = 0;
+ double read_bw, write_bw;
+ double max_read_tim, max_write_tim;
+ double min_read_tim, min_write_tim;
+ double ave_read_tim, ave_write_tim;
+ int64_t iter_jump = 0;
+ int64_t seek_position = 0;
+ MPI_File fh;
+ MPI_Status status;
+ int nchars;
+ char filename[MAX_PATH];
+ herr_t ret; /* Generic return value */
+
+ /* startup MPI and determine the rank of this process */
+ MPI_Init(&argc,&argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+ MPI_Comm_rank(MPI_COMM_WORLD, &mynod);
+
+ /* parse the command line arguments */
+ parse_args(argc, argv);
+
+ if (mynod == 0) printf("# Using hdf5-io calls.\n");
+
+ /* kindof a weird hack- if the location of the pvfstab file was
+ * specified on the command line, then spit out this location into
+ * the appropriate environment variable: */
+
+#if H5_HAVE_SETENV
+/* no setenv or unsetenv */
+ if (opt_pvfstab_set) {
+ if((setenv("PVFSTAB_FILE", opt_pvfstab, 1)) < 0){
+ perror("setenv");
+ goto die_jar_jar_die;
+ }
+ }
+#endif
+
+ /* this is how much of the file data is covered on each iteration of
+ * the test. used to help determine the seek offset on each
+ * iteration */
+ iter_jump = nprocs * opt_block;
+
+ /* setup a buffer of data to write */
+ if (!(tmp = (char *) malloc(opt_block + 256))) {
+ perror("malloc");
+ goto die_jar_jar_die;
+ }
+ buf = tmp + 128 - (((long)tmp) % 128); /* align buffer */
+
+ if (opt_correct) {
+ /* do the same buffer setup for verifiable data */
+ if (!(tmp2 = (char *) malloc(opt_block + 256))) {
+ perror("malloc2");
+ goto die_jar_jar_die;
+ }
+ buf2 = tmp + 128 - (((long)tmp) % 128);
+ }
+
+ /* setup file access template with parallel IO access. */
+ if (opt_split_vfd){
+ hid_t mpio_pl;
+
+ mpio_pl = H5Pcreate (H5P_FILE_ACCESS);
+ VRFY((acc_tpl >= 0), "", H5FATAL);
+ ret = H5Pset_fapl_mpio(mpio_pl, MPI_COMM_WORLD, MPI_INFO_NULL);
+ VRFY((ret >= 0), "", H5FATAL);
+
+ /* set optional allocation alignment */
+ if (opt_alignment*opt_threshold != 1){
+ ret = H5Pset_alignment(acc_tpl, opt_threshold, opt_alignment );
+ VRFY((ret >= 0), "H5Pset_alignment succeeded", !H5FATAL);
+ }
+
+ /* setup file access template */
+ acc_tpl = H5Pcreate (H5P_FILE_ACCESS);
+ VRFY((acc_tpl >= 0), "", H5FATAL);
+ ret = H5Pset_fapl_split(acc_tpl, meta_ext, mpio_pl, raw_ext, mpio_pl);
+ VRFY((ret >= 0), "H5Pset_fapl_split succeeded", H5FATAL);
+ ret = H5Pclose(mpio_pl);
+ VRFY((ret >= 0), "H5Pclose mpio_pl succeeded", H5FATAL);
+ }else{
+ /* setup file access template */
+ acc_tpl = H5Pcreate (H5P_FILE_ACCESS);
+ VRFY((acc_tpl >= 0), "", H5FATAL);
+ ret = H5Pset_fapl_mpio(acc_tpl, MPI_COMM_WORLD, MPI_INFO_NULL);
+ VRFY((ret >= 0), "", H5FATAL);
+
+ /* set optional allocation alignment */
+ if (opt_alignment*opt_threshold != 1){
+ ret = H5Pset_alignment(acc_tpl, opt_threshold, opt_alignment );
+ VRFY((ret >= 0), "H5Pset_alignment succeeded", !H5FATAL);
+ }
+ }
+
+ h5_fixname_no_suffix(FILENAME[0], acc_tpl, filename, sizeof filename);
+
+ /* create the parallel file */
+ fid = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl);
+ VRFY((fid >= 0), "H5Fcreate succeeded", H5FATAL);
+
+ /* define a contiquous dataset of opt_iter*nprocs*opt_block chars */
+ dims[0] = opt_iter * nprocs * opt_block;
+ sid = H5Screate_simple(RANK, dims, NULL);
+ VRFY((sid >= 0), "H5Screate_simple succeeded", H5FATAL);
+ dataset = H5Dcreate2(fid, "Dataset1", H5T_NATIVE_CHAR, sid,
+ H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
+ VRFY((dataset >= 0), "H5Dcreate2 succeeded", H5FATAL);
+
+ /* create the memory dataspace and the file dataspace */
+ dims[0] = opt_block;
+ mem_dataspace = H5Screate_simple(RANK, dims, NULL);
+ VRFY((mem_dataspace >= 0), "", H5FATAL);
+ file_dataspace = H5Dget_space(dataset);
+ VRFY((file_dataspace >= 0), "H5Dget_space succeeded", H5FATAL);
+
+ /* now each process writes a block of opt_block chars in round robbin
+ * fashion until the whole dataset is covered.
+ */
+ for(j=0; j < opt_iter; j++) {
+ /* setup a file dataspace selection */
+ start[0] = (j*iter_jump)+(mynod*opt_block);
+ stride[0] = block[0] = opt_block;
+ count[0]= 1;
+ ret=H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block);
+ VRFY((ret >= 0), "H5Sset_hyperslab succeeded", H5FATAL);
+
+ if (opt_correct) /* fill in buffer for iteration */ {
+ for (i=mynod+j, check=buf; i<opt_block; i++,check++) *check=(char)i;
+ }
+
+ /* discover the starting time of the operation */
+ MPI_Barrier(MPI_COMM_WORLD);
+ stim = MPI_Wtime();
+
+ /* write data */
+ ret = H5Dwrite(dataset, H5T_NATIVE_CHAR, mem_dataspace, file_dataspace,
+ H5P_DEFAULT, buf);
+ VRFY((ret >= 0), "H5Dwrite dataset1 succeeded", !H5FATAL);
+
+ /* discover the ending time of the operation */
+ etim = MPI_Wtime();
+
+ write_tim += (etim - stim);
+
+ /* we are done with this "write" iteration */
+ }
+
+ /* close dataset and file */
+ ret=H5Dclose(dataset);
+ VRFY((ret >= 0), "H5Dclose succeeded", H5FATAL);
+ ret=H5Fclose(fid);
+ VRFY((ret >= 0), "H5Fclose succeeded", H5FATAL);
+
+
+
+ /* wait for everyone to synchronize at this point */
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ /* reopen the file for reading */
+ fid=H5Fopen(filename,H5F_ACC_RDONLY,acc_tpl);
+ VRFY((fid >= 0), "", H5FATAL);
+
+ /* open the dataset */
+ dataset = H5Dopen2(fid, "Dataset1", H5P_DEFAULT);
+ VRFY((dataset >= 0), "H5Dopen succeeded", H5FATAL);
+
+ /* we can re-use the same mem_dataspace and file_dataspace
+ * the H5Dwrite used since the dimension size is the same.
+ */
+
+ /* we are going to repeat the read the same pattern the write used */
+ for (j=0; j < opt_iter; j++) {
+ /* setup a file dataspace selection */
+ start[0] = (j*iter_jump)+(mynod*opt_block);
+ stride[0] = block[0] = opt_block;
+ count[0]= 1;
+ ret=H5Sselect_hyperslab(file_dataspace, H5S_SELECT_SET, start, stride, count, block);
+ VRFY((ret >= 0), "H5Sset_hyperslab succeeded", H5FATAL);
+ /* seek to the appropriate spot give the current iteration and
+ * rank within the MPI processes */
+
+ /* discover the start time */
+ MPI_Barrier(MPI_COMM_WORLD);
+ stim = MPI_Wtime();
+
+ /* read in the file data */
+ if (!opt_correct){
+ ret = H5Dread(dataset, H5T_NATIVE_CHAR, mem_dataspace, file_dataspace, H5P_DEFAULT, buf);
+ }
+ else{
+ ret = H5Dread(dataset, H5T_NATIVE_CHAR, mem_dataspace, file_dataspace, H5P_DEFAULT, buf2);
+ }
+ myerrno = errno;
+
+ /* discover the end time */
+ etim = MPI_Wtime();
+ read_tim += (etim - stim);
+ VRFY((ret >= 0), "H5Dwrite dataset1 succeeded", !H5FATAL);
+
+
+ if (ret < 0) fprintf(stderr, "node %d, read error, loc = %Ld: %s\n",
+ mynod, mynod*opt_block, strerror(myerrno));
+
+ /* if the user wanted to check correctness, compare the write
+ * buffer to the read buffer */
+ if (opt_correct && memcmp(buf, buf2, opt_block)) {
+ fprintf(stderr, "node %d, correctness test failed\n", mynod);
+ my_correct = 0;
+ MPI_Allreduce(&my_correct, &correct, 1, MPI_INT, MPI_MIN,
+ MPI_COMM_WORLD);
+ }
+
+ /* we are done with this read iteration */
+ }
+
+ /* close dataset and file */
+ ret=H5Dclose(dataset);
+ VRFY((ret >= 0), "H5Dclose succeeded", H5FATAL);
+ ret=H5Fclose(fid);
+ VRFY((ret >= 0), "H5Fclose succeeded", H5FATAL);
+ ret=H5Pclose(acc_tpl);
+ VRFY((ret >= 0), "H5Pclose succeeded", H5FATAL);
+
+ /* compute the read and write times */
+ MPI_Allreduce(&read_tim, &max_read_tim, 1, MPI_DOUBLE, MPI_MAX,
+ MPI_COMM_WORLD);
+ MPI_Allreduce(&read_tim, &min_read_tim, 1, MPI_DOUBLE, MPI_MIN,
+ MPI_COMM_WORLD);
+ MPI_Allreduce(&read_tim, &ave_read_tim, 1, MPI_DOUBLE, MPI_SUM,
+ MPI_COMM_WORLD);
+
+ /* calculate the average from the sum */
+ ave_read_tim = ave_read_tim / nprocs;
+
+ MPI_Allreduce(&write_tim, &max_write_tim, 1, MPI_DOUBLE, MPI_MAX,
+ MPI_COMM_WORLD);
+ MPI_Allreduce(&write_tim, &min_write_tim, 1, MPI_DOUBLE, MPI_MIN,
+ MPI_COMM_WORLD);
+ MPI_Allreduce(&write_tim, &ave_write_tim, 1, MPI_DOUBLE, MPI_SUM,
+ MPI_COMM_WORLD);
+
+ /* calculate the average from the sum */
+ ave_write_tim = ave_write_tim / nprocs;
+
+ /* print out the results on one node */
+ if (mynod == 0) {
+ read_bw = ((int64_t)(opt_block*nprocs*opt_iter))/(max_read_tim*1000000.0);
+ write_bw = ((int64_t)(opt_block*nprocs*opt_iter))/(max_write_tim*1000000.0);
+
+ printf("nr_procs = %d, nr_iter = %d, blk_sz = %ld\n", nprocs,
+ opt_iter, (long)opt_block);
+
+ printf("# total_size = %ld\n", (long)(opt_block*nprocs*opt_iter));
+
+ printf("# Write: min_time = %f, max_time = %f, mean_time = %f\n",
+ min_write_tim, max_write_tim, ave_write_tim);
+ printf("# Read: min_time = %f, max_time = %f, mean_time = %f\n",
+ min_read_tim, max_read_tim, ave_read_tim);
+
+ printf("Write bandwidth = %f Mbytes/sec\n", write_bw);
+ printf("Read bandwidth = %f Mbytes/sec\n", read_bw);
+
+ if (opt_correct) {
+ printf("Correctness test %s.\n", correct ? "passed" : "failed");
+ }
+ }
+
+
+die_jar_jar_die:
+
+#if H5_HAVE_SETENV
+/* no setenv or unsetenv */
+ /* clear the environment variable if it was set earlier */
+ if (opt_pvfstab_set){
+ unsetenv("PVFSTAB_FILE");
+ }
+#endif
+
+ free(tmp);
+ if (opt_correct) free(tmp2);
+
+ MPI_Finalize();
+
+ return(0);
+}
+
+static int
+parse_args(int argc, char **argv)
+{
+ int c;
+
+ while ((c = getopt(argc, argv, "s:b:i:f:p:a:2:c")) != EOF) {
+ switch (c) {
+ case 's': /* stripe */
+ opt_stripe = atoi(optarg);
+ break;
+ case 'b': /* block size */
+ opt_block = atoi(optarg);
+ break;
+ case 'i': /* iterations */
+ opt_iter = atoi(optarg);
+ break;
+ case 'f': /* filename */
+ strncpy(opt_file, optarg, 255);
+ FILENAME[0] = opt_file;
+ break;
+ case 'p': /* pvfstab file */
+ strncpy(opt_pvfstab, optarg, 255);
+ opt_pvfstab_set = 1;
+ break;
+ case 'a': /* aligned allocation.
+ * syntax: -a<alignment>/<threshold>
+ * e.g., -a4096/512 allocate at 4096 bytes
+ * boundary if request size >= 512.
+ */
+ {char *p;
+ opt_alignment = atoi(optarg);
+ if (p=(char*)strchr(optarg, '/'))
+ opt_threshold = atoi(p+1);
+ }
+ HDfprintf(stdout,
+ "alignment/threshold=%Hu/%Hu\n",
+ opt_alignment, opt_threshold);
+ break;
+ case '2': /* use 2-files, i.e., split file driver */
+ opt_split_vfd=1;
+ /* get meta and raw file extension. */
+ /* syntax is <raw_ext>,<meta_ext> */
+ meta_ext = raw_ext = optarg;
+ while (*raw_ext != '\0'){
+ if (*raw_ext == ','){
+ *raw_ext = '\0';
+ raw_ext++;
+ break;
+ }
+ raw_ext++;
+ }
+ printf("split-file-vfd used: %s,%s\n",
+ meta_ext, raw_ext);
+ break;
+ case 'c': /* correctness */
+ opt_correct = 1;
+ break;
+ case '?': /* unknown */
+ default:
+ break;
+ }
+ }
+
+ return(0);
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 3
+ * c-basic-offset: 3
+ * tab-width: 3
+ * End:
+ */
+
+#else /* H5_HAVE_PARALLEL */
+/* dummy program since H5_HAVE_PARALLEL is not configured in */
+int
+main(int UNUSED argc, char UNUSED **argv)
+{
+ printf("No parallel performance because parallel is not configured in\n");
+ return(0);
+}
+#endif /* H5_HAVE_PARALLEL */
+
diff --git a/tools/perform/perf_meta.c b/tools/perform/perf_meta.c
new file mode 100644
index 0000000..b52871e
--- /dev/null
+++ b/tools/perform/perf_meta.c
@@ -0,0 +1,850 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Programmer: Raymond Lu <slu@ncsa.uiuc.edu>
+ * Friday, Oct 3, 2004
+ *
+ * Purpose: Tests performance of metadata
+ */
+
+#include "h5test.h"
+
+#ifdef H5_HAVE_PARALLEL
+#define MAINPROCESS (!mpi_rank) /* define process 0 as main process */
+#endif /*H5_HAVE_PARALLEL*/
+
+/* File_Access_type bits */
+#define FACC_DEFAULT 0x0 /* serial as default */
+#define FACC_MPIO 0x1 /* MPIO */
+
+/* Which test to run */
+int RUN_TEST = 0x0; /* all tests as default */
+int TEST_1 = 0x1; /* Test 1 */
+int TEST_2 = 0x2; /* Test 2 */
+int TEST_3 = 0x4; /* Test 3 */
+
+
+const char *FILENAME[] = {
+ "meta_perf_1",
+ "meta_perf_2",
+ "meta_perf_3",
+ NULL
+};
+
+/* Default values for performance. Can be changed through command line options */
+int NUM_DSETS = 16;
+int NUM_ATTRS = 8;
+int BATCH_ATTRS = 2;
+hbool_t flush_dset = FALSE;
+hbool_t flush_attr = FALSE;
+int nerrors = 0; /* errors count */
+hid_t fapl;
+
+/* Data space IDs */
+hid_t space;
+hid_t small_space;
+
+/* Performance data */
+typedef struct p_time {
+ double total;
+ double avg;
+ double max;
+ double min;
+ double start;
+ char func[32];
+} p_time;
+
+/*Test file access type for parallel. MPIO as default */
+int facc_type = FACC_DEFAULT;
+
+double retrieve_time(void);
+void perf(p_time *perf_t, double start_t, double end_t);
+void print_perf(p_time, p_time, p_time);
+
+
+/*-------------------------------------------------------------------------
+ * Function: parse_options
+ *
+ Purpose: Parse command line options
+ *
+ * Programmer: Raymond Lu
+ * Friday, Oct 3, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+parse_options(int argc, char **argv)
+{
+ int t;
+
+ /* Use default values */
+ if(argc==1)
+ return(0);
+
+ while (--argc){
+ if (**(++argv) != '-'){
+ break;
+ }else{
+ switch(*(*argv+1)){
+ case 'h': /* Help page */
+ return(1);
+
+ case 'd': /* Number of datasets */
+ NUM_DSETS = atoi((*argv+1)+1);
+ if (NUM_DSETS < 0){
+ nerrors++;
+ return(1);
+ }
+ break;
+
+ case 'a': /* Number of attributes per dataset */
+ NUM_ATTRS = atoi((*argv+1)+1);
+ if (NUM_ATTRS < 0){
+ nerrors++;
+ return(1);
+ }
+ break;
+
+ case 'n': /* Number of attributes to be created in batch */
+ BATCH_ATTRS = atoi((*argv+1)+1);
+ if (BATCH_ATTRS < 0){
+ nerrors++;
+ return(1);
+ }
+ break;
+
+ case 'm': /* Use the MPI-IO driver */
+ facc_type = FACC_MPIO;
+ break;
+
+ case 'f': /* Call H5Fflush for each dataset or attribute */
+ if(!strcmp("a", (*argv+2)))
+ flush_attr = TRUE;
+ else if(!strcmp("d", (*argv+2)))
+ flush_dset = TRUE;
+ else {
+ nerrors++;
+ return(1);
+ }
+ break;
+
+ case 't': /* Which test to run */
+ t = atoi((*argv+1)+1);
+ if (t < 1 || t > 3){
+ nerrors++;
+ return(1);
+ }
+ if(t == 1)
+ RUN_TEST |= TEST_1;
+ else if(t == 2)
+ RUN_TEST |= TEST_2;
+ else
+ RUN_TEST |= TEST_3;
+
+ break;
+
+ default: nerrors++;
+ return(1);
+ }
+ }
+ } /*while*/
+
+ /* Check valid values */
+#ifndef H5_HAVE_PARALLEL
+ if(facc_type == FACC_MPIO)
+ {
+ nerrors++;
+ return(1);
+ }
+#endif /*H5_HAVE_PARALLEL*/
+
+ if(NUM_ATTRS && !BATCH_ATTRS)
+ NUM_ATTRS = 0;
+
+ if(!NUM_ATTRS && BATCH_ATTRS)
+ BATCH_ATTRS = 0;
+
+ if(!NUM_DSETS) {
+ nerrors++;
+ return(1);
+ }
+
+ if(NUM_ATTRS && BATCH_ATTRS) {
+ if(BATCH_ATTRS > NUM_ATTRS || NUM_ATTRS % BATCH_ATTRS) {
+ nerrors++;
+ return(1);
+ }
+ }
+
+ return(0);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: usage
+ *
+ Purpose: Prints help page
+ *
+ * Programmer: Raymond Lu
+ * Friday, Oct 3, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static void
+usage(void)
+{
+ printf("Usage: perf_meta [-h] [-m] [-d<num_datasets>]"
+ "[-a<num_attributes>]\n"
+ "\t[-n<batch_attributes>] [-f<option>] [-t<test>]\n");
+ printf("\t-h"
+ "\t\t\thelp page.\n");
+ printf("\t-m"
+ "\t\t\tset MPIO as the file driver when parallel HDF5\n"
+ "\t\t\t\tis enabled. -m must be specified\n"
+ "\t\t\t\twhen running parallel program.\n");
+ printf("\t-d<num_datasets>"
+ "\tset number of datasets for meta data \n"
+ "\t\t\t\tperformance test\n");
+ printf("\t-a<num_attributes>"
+ "\tset number of attributes per dataset for meta \n"
+ "\t\t\t\tdata performance test.\n");
+ printf("\t-n<batch_attributes>"
+ "\tset batch number of attributes for dataset \n"
+ "\t\t\t\tfor meta data performance test.\n");
+ printf("\t-f<option>"
+ "\t\tflush data to disk after closing a dataset \n"
+ "\t\t\t\tor attribute. Valid options are \"d\" for \n"
+ "\t\t\t\tdataset, \"a\" for attribute. Disabled is \n"
+ "\t\t\t\tthe default.\n");
+ printf("\t-t<tests>"
+ "\t\trun specific test. Give only one number each \n"
+ "\t\t\t\ttime. i.e. \"-t1 -t3\" will run test 1 and 3. \n"
+ "\t\t\t\tDefault is all three tests. The 3 tests are: \n\n"
+ "\t\t\t\t1. Create <num_attributes> attributes for each \n"
+ "\t\t\t\t of <num_datasets> existing datasets.\n"
+ "\t\t\t\t2. Create <num_attributes> attributes for each \n"
+ "\t\t\t\t of <num_datasets> new datasets.\n"
+ "\t\t\t\t3. Create <batch_attributes> attributes for \n"
+ "\t\t\t\t each of <num_dataset> new datasets for \n"
+ "\t\t\t\t <num_attributes>/<batch_attributes> times.\n");
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: create_dspace
+ *
+ * Purpose: Attempts to create data space.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Raymond Lu
+ * Friday, Oct 3, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+create_dspace(void)
+{
+ hsize_t dims[2];
+ hsize_t small_dims[2];
+
+ /* Create the data space */
+ dims[0] = 256;
+ dims[1] = 512;
+ if((space = H5Screate_simple(2, dims, NULL)) < 0)
+ goto error;
+
+ /* Create a small data space for attributes */
+ small_dims[0] = 16;
+ small_dims[1] = 8;
+ if((small_space = H5Screate_simple(2, small_dims, NULL)) < 0)
+ goto error;
+
+ return 0;
+
+error:
+ return -1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: create_dsets
+ *
+ * Purpose: Attempts to create some datasets.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Raymond Lu
+ * Friday, Oct 3, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+create_dsets(hid_t file)
+{
+ hid_t dataset;
+ char dset_name[32];
+ int i;
+
+ /*
+ * Create a dataset using the default dataset creation properties.
+ */
+ for(i = 0; i < NUM_DSETS; i++) {
+ sprintf(dset_name, "dataset %d", i);
+ if((dataset = H5Dcreate2(file, dset_name, H5T_NATIVE_DOUBLE, space,
+ H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
+ goto error;
+
+ if(H5Dclose(dataset) < 0)
+ goto error;
+ } /* end for */
+
+ return 0;
+
+error:
+ return -1;
+
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: create_attrs_1
+ *
+ * Purpose: Attempts to create all attributes for each existing dataset.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Raymond Lu
+ * Friday, Oct 3, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+create_attrs_1(void)
+{
+ hid_t file, dataset, attr;
+ char filename[128];
+ char dset_name[64];
+ char attr_name[128];
+ int i, j;
+ p_time attr_t = {0, 0, 0, 1000000, 0, ""};
+ p_time open_t = {0, 0, 0, 1000000, 0, "H5Dopen2"};
+ p_time close_t = {0, 0, 0, 1000000, 0, ""};
+
+#ifdef H5_HAVE_PARALLEL
+ /* need the rank for printing data */
+ int mpi_rank;
+ if(facc_type == FACC_MPIO)
+ MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
+#endif /*H5_HAVE_PARALLEL*/
+
+ h5_fixname(FILENAME[0], fapl, filename, sizeof filename);
+
+ if ((file=H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT,
+ fapl)) < 0)
+ goto error;
+
+ if(create_dsets(file) < 0)
+ goto error;
+
+ /*
+ * Create all(user specifies the number) attributes for each dataset
+ */
+ for(i = 0; i < NUM_DSETS; i++) {
+ sprintf(dset_name, "dataset %d", i);
+ open_t.start = retrieve_time();
+ if((dataset = H5Dopen2(file, dset_name, H5P_DEFAULT)) < 0)
+ goto error;
+ perf(&open_t, open_t.start, retrieve_time());
+
+ for(j = 0; j < NUM_ATTRS; j++) {
+ sprintf(attr_name, "all attrs for each dset %d", j);
+ attr_t.start = retrieve_time();
+ if((attr = H5Acreate2(dataset, attr_name, H5T_NATIVE_DOUBLE,
+ small_space, H5P_DEFAULT, H5P_DEFAULT)) < 0)
+ goto error;
+ if(H5Aclose(attr) < 0)
+ goto error;
+ perf(&attr_t, attr_t.start, retrieve_time());
+ if(flush_attr && H5Fflush(file, H5F_SCOPE_LOCAL) < 0)
+ goto error;
+ } /* end for */
+
+ close_t.start = retrieve_time();
+ if(H5Dclose(dataset) < 0)
+ goto error;
+ perf(&close_t, close_t.start, retrieve_time());
+ if(flush_dset && H5Fflush(file, H5F_SCOPE_LOCAL) < 0)
+ goto error;
+ } /* end for */
+
+ if(facc_type == FACC_MPIO) {
+#ifdef H5_HAVE_PARALLEL
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif /*H5_HAVE_PARALLEL*/
+ }
+
+#ifdef H5_HAVE_PARALLEL
+ if (facc_type == FACC_DEFAULT || (facc_type != FACC_DEFAULT && MAINPROCESS)) /* only process 0 reports */
+#endif /*H5_HAVE_PARALLEL*/
+ {
+ /* Calculate the average time */
+ open_t.avg = open_t.total / NUM_DSETS;
+ close_t.avg = close_t.total / NUM_DSETS;
+ if(NUM_ATTRS)
+ attr_t.avg = attr_t.total / (NUM_ATTRS*NUM_DSETS);
+
+ /* Print out the performance result */
+ fprintf(stderr, "1. Create %d attributes for each of %d existing datasets\n",
+ NUM_ATTRS, NUM_DSETS);
+ print_perf(open_t, close_t, attr_t);
+ }
+
+ if (H5Fclose(file) < 0) goto error;
+
+ return 0;
+
+error:
+ return -1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: create_attrs_2
+ *
+ * Purpose: Attempts to create all attributes for each new dataset.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Raymond Lu
+ * Friday, Oct 3, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+create_attrs_2(void)
+{
+ hid_t file, dataset, attr;
+ char filename[128];
+ char dset_name[64];
+ char attr_name[128];
+ int i, j;
+ p_time attr_t = {0, 0, 0, 1000000, 0, ""};
+ p_time create_t = {0, 0, 0, 1000000, 0, "H5Dcreate2"};
+ p_time close_t = {0, 0, 0, 1000000, 0, ""};
+
+#ifdef H5_HAVE_PARALLEL
+ /* need the rank for printing data */
+ int mpi_rank;
+ if(facc_type == FACC_MPIO)
+ MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
+#endif /*H5_HAVE_PARALLEL*/
+
+ h5_fixname(FILENAME[1], fapl, filename, sizeof filename);
+
+ if ((file=H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl)) < 0)
+ goto error;
+
+ /*
+ * Create all(user specifies the number) attributes for each new dataset
+ */
+ for(i = 0; i < NUM_DSETS; i++) {
+ sprintf(dset_name, "dataset %d", i);
+ create_t.start = retrieve_time();
+ if((dataset = H5Dcreate2(file, dset_name, H5T_NATIVE_DOUBLE,
+ space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0)
+ goto error;
+ perf(&create_t, create_t.start, retrieve_time());
+
+ for(j = 0; j < NUM_ATTRS; j++) {
+ sprintf(attr_name, "all attrs for each dset %d", j);
+ attr_t.start = retrieve_time();
+ if((attr = H5Acreate2(dataset, attr_name, H5T_NATIVE_DOUBLE,
+ small_space, H5P_DEFAULT, H5P_DEFAULT)) < 0)
+ goto error;
+ if(H5Aclose(attr) < 0)
+ goto error;
+ perf(&attr_t, attr_t.start, retrieve_time());
+ if(flush_attr && H5Fflush(file, H5F_SCOPE_LOCAL) < 0)
+ goto error;
+ } /* end for */
+
+ close_t.start = retrieve_time();
+ if(H5Dclose(dataset) < 0)
+ goto error;
+ perf(&close_t, close_t.start, retrieve_time());
+ if(flush_dset && H5Fflush(file, H5F_SCOPE_LOCAL) < 0)
+ goto error;
+ } /* end for */
+
+#ifdef H5_HAVE_PARALLEL
+ if(facc_type == FACC_MPIO)
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif /*H5_HAVE_PARALLEL*/
+
+#ifdef H5_HAVE_PARALLEL
+ /* only process 0 reports if parallel */
+ if (facc_type == FACC_DEFAULT || (facc_type != FACC_DEFAULT && MAINPROCESS))
+#endif /*H5_HAVE_PARALLEL*/
+ {
+ /* Calculate the average time */
+ create_t.avg = create_t.total / NUM_DSETS;
+ close_t.avg = close_t.total / NUM_DSETS;
+ if(NUM_ATTRS)
+ attr_t.avg = attr_t.total / (NUM_ATTRS*NUM_DSETS);
+
+ /* Print out the performance result */
+ fprintf(stderr, "2. Create %d attributes for each of %d new datasets\n",
+ NUM_ATTRS, NUM_DSETS);
+ print_perf(create_t, close_t, attr_t);
+ }
+
+ if (H5Fclose(file) < 0) goto error;
+
+ return 0;
+
+error:
+ return -1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: create_attrs_3
+ *
+ * Purpose: Attempts to create some attributes for each dataset in a
+ * loop.
+ *
+ * Return: Success: 0
+ *
+ * Failure: -1
+ *
+ * Programmer: Raymond Lu
+ * Friday, Oct 3, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+create_attrs_3(void)
+{
+ hid_t file, dataset, attr;
+ char filename[128];
+ char dset_name[64];
+ char attr_name[128];
+ int loop_num;
+ int i, j, k;
+ p_time attr_t = {0, 0, 0, 1000000, 0, ""};
+ p_time open_t = {0, 0, 0, 1000000, 0, "H5Dopen2"};
+ p_time close_t = {0, 0, 0, 1000000, 0, ""};
+
+#ifdef H5_HAVE_PARALLEL
+ /* need the rank for printing data */
+ int mpi_rank;
+ if(facc_type == FACC_MPIO)
+ MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
+#endif /*H5_HAVE_PARALLEL*/
+
+ h5_fixname(FILENAME[2], fapl, filename, sizeof filename);
+
+ if ((file=H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT,
+ fapl)) < 0)
+ goto error;
+
+ if(create_dsets(file) < 0)
+ goto error;
+
+ /*
+ * Create some(user specifies the number) attributes for each dataset
+ * in a loop
+ */
+ loop_num = NUM_ATTRS/BATCH_ATTRS;
+
+ for(i = 0; i < loop_num; i++) {
+ for(j = 0; j < NUM_DSETS; j++) {
+ sprintf(dset_name, "dataset %d", j);
+ open_t.start = retrieve_time();
+ if((dataset = H5Dopen2(file, dset_name, H5P_DEFAULT)) < 0)
+ goto error;
+ perf(&open_t, open_t.start, retrieve_time());
+
+ for(k = 0; k < BATCH_ATTRS; k++) {
+ sprintf(attr_name, "some attrs for each dset %d %d", i, k);
+ attr_t.start = retrieve_time();
+ if((attr = H5Acreate2(dataset, attr_name, H5T_NATIVE_DOUBLE,
+ small_space, H5P_DEFAULT, H5P_DEFAULT)) < 0)
+ goto error;
+ if(H5Aclose(attr) < 0)
+ goto error;
+ perf(&attr_t, attr_t.start, retrieve_time());
+ if(flush_attr && H5Fflush(file, H5F_SCOPE_LOCAL) < 0)
+ goto error;
+ } /* end for */
+
+ close_t.start = retrieve_time();
+ if(H5Dclose(dataset) < 0)
+ goto error;
+ perf(&close_t, close_t.start, retrieve_time());
+ if(flush_dset && H5Fflush(file, H5F_SCOPE_LOCAL) < 0)
+ goto error;
+ } /* end for */
+ } /* end for */
+
+#ifdef H5_HAVE_PARALLEL
+ if(facc_type == FACC_MPIO)
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif /*H5_HAVE_PARALLEL*/
+
+#ifdef H5_HAVE_PARALLEL
+ /* only process 0 reports if parallel */
+ if (facc_type == FACC_DEFAULT || (facc_type != FACC_DEFAULT && MAINPROCESS))
+#endif /*H5_HAVE_PARALLEL*/
+ {
+ /* Calculate the average time */
+ open_t.avg = open_t.total / (loop_num*NUM_DSETS);
+ close_t.avg = close_t.total / (loop_num*NUM_DSETS);
+ attr_t.avg = attr_t.total / (NUM_ATTRS*NUM_DSETS);
+
+ /* Print out the performance result */
+ fprintf(stderr, "3. Create %d attributes for each of %d existing datasets for %d times\n",
+ BATCH_ATTRS, NUM_DSETS, loop_num);
+ print_perf(open_t, close_t, attr_t);
+ }
+
+ if (H5Fclose(file) < 0) goto error;
+
+ return 0;
+
+error:
+ return -1;
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: retrieve_time
+ *
+ * Purpose: Returns time in seconds, in a double number.
+ *
+ * Programmer: Raymond Lu
+ * Friday, Oct 3, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+double retrieve_time(void)
+{
+#ifdef H5_HAVE_PARALLEL
+ if(facc_type == FACC_DEFAULT) {
+#endif /*H5_HAVE_PARALLEL*/
+ struct timeval t;
+ HDgettimeofday(&t, NULL);
+ return ((double)t.tv_sec + (double)t.tv_usec / 1000000);
+#ifdef H5_HAVE_PARALLEL
+ } else {
+ return MPI_Wtime();
+ }
+#endif /*H5_HAVE_PARALLEL*/
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: perf
+ *
+ * Purpose: Calculate total time, maximal and minimal time of
+ * performance.
+ *
+ * Programmer: Raymond Lu
+ * Friday, Oct 3, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void perf(p_time *perf_t, double start_t, double end_t)
+{
+ double t = end_t - start_t;
+
+#ifdef H5_HAVE_PARALLEL
+ if(facc_type == FACC_MPIO) {
+ double reduced_t;
+ double t_max, t_min;
+ int mpi_size, mpi_rank;
+
+ MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
+ MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
+ MPI_Barrier(MPI_COMM_WORLD);
+
+ MPI_Reduce(&t, &reduced_t, 1, MPI_DOUBLE, MPI_SUM, 0,
+ MPI_COMM_WORLD);
+ reduced_t /= mpi_size;
+
+ MPI_Reduce(&t, &t_max, 1, MPI_DOUBLE, MPI_MAX, 0,
+ MPI_COMM_WORLD);
+ MPI_Reduce(&t, &t_min, 1, MPI_DOUBLE, MPI_MIN, 0,
+ MPI_COMM_WORLD);
+
+ if (MAINPROCESS) {
+ perf_t->total += reduced_t;
+
+ if(t_max > perf_t->max)
+ perf_t->max = t_max;
+ if(t_min < perf_t->min)
+ perf_t->min = t_min;
+ }
+ } else
+#endif /*H5_HAVE_PARALLEL*/
+ {
+ perf_t->total += t;
+
+ if(t > perf_t->max)
+ perf_t->max = t;
+ if(t < perf_t->min)
+ perf_t->min = t;
+ }
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: print_perf
+ *
+ * Purpose: Print out performance data.
+ *
+ * Programmer: Raymond Lu
+ * Friday, Oct 3, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+void print_perf(p_time open_t, p_time close_t, p_time attr_t)
+{
+ fprintf(stderr, "\t%s:\t\tavg=%.6fs;\tmax=%.6fs;\tmin=%.6fs\n",
+ open_t.func, open_t.avg, open_t.max, open_t.min);
+ fprintf(stderr, "\tH5Dclose:\t\tavg=%.6fs;\tmax=%.6fs;\tmin=%.6fs\n",
+ close_t.avg, close_t.max, close_t.min);
+ if(NUM_ATTRS)
+ fprintf(stderr, "\tH5A(create & close):\tavg=%.6fs;\tmax=%.6fs;\tmin=%.6fs\n",
+ attr_t.avg, attr_t.max, attr_t.min);
+}
+
+
+/*-------------------------------------------------------------------------
+ * Function: main
+ *
+ * Purpose: Tests
+ *
+ * Return: Success: exit(0)
+ *
+ * Failure: exit(1)
+ *
+ * Programmer: Raymond Lu
+ * Friday, Oct 3, 2003
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+main(int argc, char **argv)
+{
+#ifdef H5_HAVE_PARALLEL
+ int mpi_size, mpi_rank; /* mpi variables */
+#endif /*H5_HAVE_PARALLEL*/
+
+ if(parse_options(argc, argv) != 0) {
+ usage();
+ return 0;
+ }
+
+#ifdef H5_HAVE_PARALLEL
+ if(facc_type == FACC_MPIO) {
+ MPI_Init(&argc, &argv);
+ MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
+ MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
+ }
+#endif /*H5_HAVE_PARALLEL*/
+
+#ifdef H5_HAVE_PARALLEL
+ if (facc_type == FACC_DEFAULT || (facc_type != FACC_DEFAULT && MAINPROCESS))
+#endif /*H5_HAVE_PARALLEL*/
+ fprintf(stderr, "\t\tPerformance result of metadata for datasets and attributes\n\n");
+
+ fapl = H5Pcreate (H5P_FILE_ACCESS);
+#ifdef H5_HAVE_PARALLEL
+ if(facc_type == FACC_MPIO)
+ H5Pset_fapl_mpio(fapl, MPI_COMM_WORLD, MPI_INFO_NULL);
+#endif /*H5_HAVE_PARALLEL*/
+
+ nerrors += create_dspace() < 0 ?1:0;
+
+ if((RUN_TEST & TEST_1) || !RUN_TEST)
+ nerrors += create_attrs_1() < 0 ?1:0;
+ if((RUN_TEST & TEST_2) || !RUN_TEST)
+ nerrors += create_attrs_2() < 0 ?1:0;
+ if(((RUN_TEST & TEST_3) || !RUN_TEST) && BATCH_ATTRS && NUM_ATTRS)
+ nerrors += create_attrs_3() < 0 ?1:0;
+
+ if (H5Sclose(space) < 0) goto error;
+ if (H5Sclose(small_space) < 0) goto error;
+
+ h5_cleanup(FILENAME, fapl);
+
+#ifdef H5_HAVE_PARALLEL
+ if(facc_type == FACC_MPIO)
+ /* MPI_Finalize must be called AFTER H5close which may use MPI calls */
+ MPI_Finalize();
+#endif /*H5_HAVE_PARALLEL*/
+
+ if (nerrors) goto error;
+#ifdef H5_HAVE_PARALLEL
+ if (facc_type != FACC_DEFAULT && MAINPROCESS)
+#endif /*H5_HAVE_PARALLEL*/
+ printf("All metadata performance tests passed.\n");
+
+ return 0;
+
+ error:
+ nerrors = MAX(1, nerrors);
+#ifdef H5_HAVE_PARALLEL
+ if (facc_type != FACC_DEFAULT && MAINPROCESS)
+#endif /*H5_HAVE_PARALLEL*/
+ printf("***** %d PERFORMANCE TEST%s FAILED! *****\n",
+ nerrors, 1 == nerrors ? "" : "S");
+
+ return 1;
+}
+
diff --git a/tools/perform/pio_engine.c b/tools/perform/pio_engine.c
new file mode 100644
index 0000000..3535fb4
--- /dev/null
+++ b/tools/perform/pio_engine.c
@@ -0,0 +1,2678 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Author: Albert Cheng of NCSA, Oct 24, 2001.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#ifdef H5_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include "hdf5.h"
+
+#ifdef H5_HAVE_PARALLEL
+
+#include <mpi.h>
+
+#ifndef MPI_FILE_NULL /*MPIO may be defined in mpi.h already */
+# include <mpio.h>
+#endif /* !MPI_FILE_NULL */
+
+#include "pio_perf.h"
+#include "pio_timer.h"
+
+/* Macro definitions */
+
+#if H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 6
+# define H5DCREATE(fd, name, type, space, dcpl) H5Dcreate(fd, name, type, space, dcpl)
+# define H5DOPEN(fd, name) H5Dopen(fd, name)
+#else
+# define H5DCREATE(fd, name, type, space, dcpl) H5Dcreate2(fd, name, type, space, H5P_DEFAULT, dcpl, H5P_DEFAULT)
+# define H5DOPEN(fd, name) H5Dopen2(fd, name, H5P_DEFAULT)
+#endif
+
+/* sizes of various items. these sizes won't change during program execution */
+/* The following three must have the same type */
+#define ELMT_SIZE (sizeof(unsigned char)) /* we're doing bytes */
+#define ELMT_MPI_TYPE MPI_BYTE
+#define ELMT_H5_TYPE H5T_NATIVE_UCHAR
+
+#define GOTOERROR(errcode) { ret_code = errcode; goto done; }
+#define GOTODONE { goto done; }
+#define ERRMSG(mesg) { \
+ fprintf(stderr, "Proc %d: ", pio_mpi_rank_g); \
+ fprintf(stderr, "*** Assertion failed (%s) at line %4d in %s\n", \
+ mesg, (int)__LINE__, __FILE__); \
+}
+
+#define MSG(mesg) { \
+ fprintf(stderr, "Proc %d: ", pio_mpi_rank_g); \
+ fprintf(stderr, "(%s) at line %4d in %s\n", \
+ mesg, (int)__LINE__, __FILE__); \
+}
+
+/* verify: if val is false (0), print mesg. */
+#define VRFY(val, mesg) do { \
+ if (!val) { \
+ ERRMSG(mesg); \
+ GOTOERROR(FAIL); \
+ } \
+} while(0)
+
+
+/* POSIX I/O macros */
+#define POSIXCREATE(fn) HDopen(fn, O_CREAT|O_TRUNC|O_RDWR, 0600)
+#define POSIXOPEN(fn, F) HDopen(fn, F, 0600)
+#define POSIXCLOSE(F) HDclose(F)
+#define POSIXSEEK(F,L) HDlseek(F, L, SEEK_SET)
+#define POSIXWRITE(F,B,S) HDwrite(F,B,S)
+#define POSIXREAD(F,B,S) HDread(F,B,S)
+
+enum {
+ PIO_CREATE = 1,
+ PIO_WRITE = 2,
+ PIO_READ = 4
+};
+
+/* Global variables */
+static int clean_file_g = -1; /*whether to cleanup temporary test */
+/*files. -1 is not defined; */
+/*0 is no cleanup; 1 is do cleanup */
+
+/*
+ * In a parallel machine, the filesystem suitable for compiling is
+ * unlikely a parallel file system that is suitable for parallel I/O.
+ * There is no standard pathname for the parallel file system. /tmp
+ * is about the best guess.
+ */
+#ifndef HDF5_PARAPREFIX
+# define HDF5_PARAPREFIX ""
+#endif /* !HDF5_PARAPREFIX */
+
+#ifndef MIN
+# define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif /* !MIN */
+
+/* the different types of file descriptors we can expect */
+typedef union _file_descr {
+ int posixfd; /* POSIX file handle*/
+ MPI_File mpifd; /* MPI file */
+ hid_t h5fd; /* HDF5 file */
+} file_descr;
+
+/* local functions */
+static char *pio_create_filename(iotype iot, const char *base_name,
+ char *fullname, size_t size);
+static herr_t do_write(results *res, file_descr *fd, parameters *parms,
+ long ndsets, off_t nelmts, size_t buf_size, void *buffer);
+static herr_t do_read(results *res, file_descr *fd, parameters *parms,
+ long ndsets, off_t nelmts, size_t buf_size, void *buffer /*out*/);
+static herr_t do_fopen(parameters *param, char *fname, file_descr *fd /*out*/,
+ int flags);
+static herr_t do_fclose(iotype iot, file_descr *fd);
+static void do_cleanupfile(iotype iot, char *fname);
+
+/*
+ * Function: do_pio
+ * Purpose: PIO Engine where Parallel IO are executed.
+ * Return: results
+ * Programmer: Albert Cheng, Bill Wendling 2001/12/12
+ * Modifications:
+ * Added 2D testing (Christian Chilan, 10. August 2005)
+ */
+ results
+do_pio(parameters param)
+{
+ /* return codes */
+ herr_t ret_code = 0; /*return code */
+ results res;
+
+ file_descr fd;
+ iotype iot;
+
+ char fname[FILENAME_MAX];
+ long nf;
+ long ndsets;
+ off_t nbytes; /*number of bytes per dataset */
+ off_t snbytes; /*general dataset size */
+ /*for 1D, it is the actual dataset size */
+ /*for 2D, it is the size of a side of the dataset square */
+ char *buffer = NULL; /*data buffer pointer */
+ size_t buf_size; /*general buffer size in bytes */
+ /*for 1D, it is the actual buffer size */
+ /*for 2D, it is the length of the buffer rectangle */
+ size_t blk_size; /*data block size in bytes */
+ size_t bsize; /*actual buffer size */
+
+ /* HDF5 variables */
+ herr_t hrc; /*HDF5 return code */
+
+ /* Sanity check parameters */
+
+ /* IO type */
+ iot = param.io_type;
+
+ switch (iot) {
+ case MPIO:
+ fd.mpifd = MPI_FILE_NULL;
+ res.timers = pio_time_new(MPI_TIMER);
+ break;
+ case POSIXIO:
+ fd.posixfd = -1;
+ res.timers = pio_time_new(MPI_TIMER);
+ break;
+ case PHDF5:
+ fd.h5fd = -1;
+ res.timers = pio_time_new(MPI_TIMER);
+ break;
+ default:
+ /* unknown request */
+ fprintf(stderr, "Unknown IO type request (%d)\n", iot);
+ GOTOERROR(FAIL);
+ }
+
+ ndsets = param.num_dsets; /* number of datasets per file */
+ nbytes = param.num_bytes; /* number of bytes per dataset */
+ buf_size = param.buf_size;
+ blk_size = param.blk_size;
+
+ if (!param.dim2d){
+ snbytes = nbytes; /* General dataset size */
+ bsize = buf_size; /* Actual buffer size */
+ }
+ else {
+ snbytes = (off_t)sqrt(nbytes); /* General dataset size */
+ bsize = buf_size * blk_size; /* Actual buffer size */
+ }
+
+ if (param.num_files < 0 ) {
+ fprintf(stderr,
+ "number of files must be >= 0 (%ld)\n",
+ param.num_files);
+ GOTOERROR(FAIL);
+ }
+
+ if (ndsets < 0 ) {
+ fprintf(stderr,
+ "number of datasets per file must be >= 0 (%ld)\n",
+ ndsets);
+ GOTOERROR(FAIL);
+ }
+
+ if (param.num_procs <= 0 ) {
+ fprintf(stderr,
+ "maximum number of process to use must be > 0 (%d)\n",
+ param.num_procs);
+ GOTOERROR(FAIL);
+ }
+
+ /* Validate transfer buffer size & block size*/
+ if(blk_size<=0) {
+ HDfprintf(stderr,
+ "Transfer block size (%zu) must be > 0\n", blk_size);
+ GOTOERROR(FAIL);
+ }
+ if(buf_size<=0) {
+ HDfprintf(stderr,
+ "Transfer buffer size (%zu) must be > 0\n", buf_size);
+ GOTOERROR(FAIL);
+ }
+ if ((buf_size % blk_size) != 0){
+ HDfprintf(stderr,
+ "Transfer buffer size (%zu) must be a multiple of the "
+ "interleaved I/O block size (%zu)\n",
+ buf_size, blk_size);
+ GOTOERROR(FAIL);
+ }
+ if((snbytes%pio_mpi_nprocs_g)!=0) {
+ HDfprintf(stderr,
+ "Dataset size (%" H5_PRINTF_LL_WIDTH "d) must be a multiple of the "
+ "number of processes (%d)\n",
+ (long long)snbytes, pio_mpi_nprocs_g);
+ GOTOERROR(FAIL);
+ }
+
+ if (!param.dim2d){
+ if(((snbytes/pio_mpi_nprocs_g)%buf_size)!=0) {
+ HDfprintf(stderr,
+ "Dataset size/process (%" H5_PRINTF_LL_WIDTH "d) must be a multiple of the "
+ "trasfer buffer size (%zu)\n",
+ (long long)(snbytes/pio_mpi_nprocs_g), buf_size);
+ GOTOERROR(FAIL);
+ }
+ }
+ else {
+ if((snbytes%buf_size)!=0) {
+ HDfprintf(stderr,
+ "Dataset side size (%" H5_PRINTF_LL_WIDTH "d) must be a multiple of the "
+ "trasfer buffer size (%zu)\n",
+ (long long)snbytes, buf_size);
+ GOTOERROR(FAIL);
+ }
+ }
+
+ /* Allocate transfer buffer */
+ if ((buffer = malloc(bsize)) == NULL){
+ HDfprintf(stderr, "malloc for transfer buffer size (%zu) failed\n",
+ bsize);
+ GOTOERROR(FAIL);
+ }
+
+ if (pio_debug_level >= 4) {
+ int myrank;
+
+ MPI_Comm_rank(pio_comm_g, &myrank);
+
+ /* output all of the times for all iterations */
+ if (myrank == 0)
+ fprintf(output, "Timer details:\n");
+ }
+
+ for (nf = 1; nf <= param.num_files; nf++) {
+ /*
+ * Write performance measurement
+ */
+ /* Open file for write */
+ char base_name[256];
+
+ sprintf(base_name, "#pio_tmp_%lu", nf);
+ pio_create_filename(iot, base_name, fname, sizeof(fname));
+ if (pio_debug_level > 0)
+ HDfprintf(output, "rank %d: data filename=%s\n",
+ pio_mpi_rank_g, fname);
+
+ /* Need barrier to make sure everyone starts at the same time */
+ MPI_Barrier(pio_comm_g);
+
+ set_time(res.timers, HDF5_GROSS_WRITE_FIXED_DIMS, TSTART);
+ hrc = do_fopen(&param, fname, &fd, PIO_CREATE | PIO_WRITE);
+
+ VRFY((hrc == SUCCESS), "do_fopen failed");
+
+ set_time(res.timers, HDF5_FINE_WRITE_FIXED_DIMS, TSTART);
+ hrc = do_write(&res, &fd, &param, ndsets, nbytes, buf_size, buffer);
+ hrc == SUCCESS;
+ set_time(res.timers, HDF5_FINE_WRITE_FIXED_DIMS, TSTOP);
+
+ VRFY((hrc == SUCCESS), "do_write failed");
+
+ /* Close file for write */
+ hrc = do_fclose(iot, &fd);
+
+ set_time(res.timers, HDF5_GROSS_WRITE_FIXED_DIMS, TSTOP);
+ VRFY((hrc == SUCCESS), "do_fclose failed");
+
+ if (!param.h5_write_only) {
+ /*
+ * Read performance measurement
+ */
+ /* Need barrier to make sure everyone is done writing and has
+ * closed the file. Also to make sure everyone starts reading
+ * at the same time.
+ */
+ MPI_Barrier(pio_comm_g);
+
+ /* Open file for read */
+ set_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS, TSTART);
+ hrc = do_fopen(&param, fname, &fd, PIO_READ);
+
+ VRFY((hrc == SUCCESS), "do_fopen failed");
+
+ set_time(res.timers, HDF5_FINE_READ_FIXED_DIMS, TSTART);
+ hrc = do_read(&res, &fd, &param, ndsets, nbytes, buf_size, buffer);
+ set_time(res.timers, HDF5_FINE_READ_FIXED_DIMS, TSTOP);
+ VRFY((hrc == SUCCESS), "do_read failed");
+
+ /* Close file for read */
+ hrc = do_fclose(iot, &fd);
+
+ set_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS, TSTOP);
+ VRFY((hrc == SUCCESS), "do_fclose failed");
+ }
+
+ /* Need barrier to make sure everyone is done with the file */
+ /* before it may be removed by do_cleanupfile */
+ MPI_Barrier(pio_comm_g);
+ do_cleanupfile(iot, fname);
+ }
+
+done:
+ /* clean up */
+ /* release HDF5 objects */
+
+ /* close any opened files */
+ /* no remove(fname) because that should have happened normally. */
+ switch (iot) {
+ case POSIXIO:
+ if (fd.posixfd != -1)
+ hrc = do_fclose(iot, &fd);
+ break;
+ case MPIO:
+ if (fd.mpifd != MPI_FILE_NULL)
+ hrc = do_fclose(iot, &fd);
+ break;
+ case PHDF5:
+ if (fd.h5fd != -1)
+ hrc = do_fclose(iot, &fd);
+ break;
+ }
+
+ /* release generic resources */
+ if(buffer)
+ free(buffer);
+ res.ret_code = ret_code;
+ return res;
+}
+
+/*
+ * Function: pio_create_filename
+ * Purpose: Create a new filename to write to. Determine the correct
+ * suffix to append to the filename by the type of I/O we're
+ * doing. Also, place in the /tmp/{$USER,$LOGIN} directory if
+ * USER or LOGIN are specified in the environment.
+ * Return: Pointer to filename or NULL
+ * Programmer: Bill Wendling, 21. November 2001
+ * Modifications:
+ */
+ static char *
+pio_create_filename(iotype iot, const char *base_name, char *fullname, size_t size)
+{
+ const char *prefix, *suffix = "";
+ char *ptr, last = '\0';
+ size_t i, j;
+
+ if (!base_name || !fullname || size < 1)
+ return NULL;
+
+ HDmemset(fullname, 0, size);
+
+ switch (iot) {
+ case POSIXIO:
+ suffix = ".posix";
+ break;
+ case MPIO:
+ suffix = ".mpio";
+ break;
+ case PHDF5:
+ suffix = ".h5";
+ break;
+ }
+
+ /* First use the environment variable and then try the constant */
+ prefix = HDgetenv("HDF5_PARAPREFIX");
+
+#ifdef HDF5_PARAPREFIX
+ if (!prefix)
+ prefix = HDF5_PARAPREFIX;
+#endif /* HDF5_PARAPREFIX */
+
+ /* Prepend the prefix value to the base name */
+ if (prefix && *prefix) {
+ /* If the prefix specifies the HDF5_PARAPREFIX directory, then
+ * default to using the "/tmp/$USER" or "/tmp/$LOGIN"
+ * directory instead. */
+ register char *user, *login, *subdir;
+
+ user = HDgetenv("USER");
+ login = HDgetenv("LOGIN");
+ subdir = (user ? user : login);
+
+ if (subdir) {
+ for (i = 0; i < size-1 && prefix[i]; i++)
+ fullname[i] = prefix[i];
+
+ fullname[i++] = '/';
+
+ for (j = 0; i < size && subdir[j]; i++, j++)
+ fullname[i] = subdir[j];
+ }
+ else {
+ /* We didn't append the prefix yet */
+ HDstrncpy(fullname, prefix, size);
+ fullname[size - 1] = '\0';
+ }
+
+ if ((HDstrlen(fullname) + HDstrlen(base_name) + 1) < size) {
+ /* Append the base_name with a slash first. Multiple slashes are
+ * handled below. */
+ h5_stat_t buf;
+
+ if (HDstat(fullname, &buf) < 0)
+ /* The directory doesn't exist just yet */
+ if (HDmkdir(fullname, (mode_t) 0755) < 0 && errno != EEXIST) {
+ /* We couldn't make the "/tmp/${USER,LOGIN}" subdirectory.
+ * Default to PREFIX's original prefix value. */
+ HDstrcpy(fullname, prefix);
+ }
+
+ HDstrcat(fullname, "/");
+ HDstrcat(fullname, base_name);
+ }
+ else {
+ /* Buffer is too small */
+ return NULL;
+ }
+ }
+ else if (HDstrlen(base_name) >= size) {
+ /* Buffer is too small */
+ return NULL;
+ }
+ else {
+ HDstrcpy(fullname, base_name);
+ }
+
+ /* Append a suffix */
+ if (suffix) {
+ if (HDstrlen(fullname) + HDstrlen(suffix) >= size)
+ return NULL;
+
+ HDstrcat(fullname, suffix);
+ }
+
+ /* Remove any double slashes in the filename */
+ for (ptr = fullname, i = j = 0; ptr && i < size; i++, ptr++) {
+ if (*ptr != '/' || last != '/')
+ fullname[j++] = *ptr;
+
+ last = *ptr;
+ }
+
+ return fullname;
+}
+
+/*
+ * Function: do_write
+ * Purpose: Write the required amount of data to the file.
+ * Return: SUCCESS or FAIL
+ * Programmer: Albert Cheng, Bill Wendling, 2001/12/13
+ * Modifications:
+ * Added 2D testing (Christian Chilan, 10. August 2005)
+ */
+ static herr_t
+do_write(results *res, file_descr *fd, parameters *parms, long ndsets,
+ off_t nbytes, size_t buf_size, void *buffer)
+{
+ int ret_code = SUCCESS;
+ int rc; /*routine return code */
+ long ndset;
+ size_t blk_size; /* The block size to subdivide the xfer buffer into */
+ off_t nbytes_xfer; /* Total number of bytes transferred so far */
+ size_t nbytes_xfer_advance; /* Number of bytes transferred in a single I/O operation */
+ size_t nbytes_toxfer; /* Number of bytes to transfer a particular time */
+ char dname[64];
+ off_t dset_offset=0; /*dataset offset in a file */
+ off_t bytes_begin[2]; /*first elmt this process transfer */
+ off_t bytes_count; /*number of elmts this process transfer */
+ off_t snbytes=0; /*size of a side of the dataset square */
+ unsigned char *buf_p; /* Current buffer pointer */
+
+ /* POSIX variables */
+ off_t file_offset; /* File offset of the next transfer */
+ off_t file_offset_advance; /* File offset advance after each I/O operation */
+ off_t posix_file_offset; /* Base file offset of the next transfer */
+
+ /* MPI variables */
+ MPI_Offset mpi_file_offset; /* Base file offset of the next transfer*/
+ MPI_Offset mpi_offset; /* Offset in MPI file */
+ MPI_Offset mpi_offset_advance; /* Offset advance after each I/O operation */
+ MPI_Datatype mpi_file_type; /* MPI derived type for 1D file */
+ MPI_Datatype mpi_blk_type; /* MPI derived type for 1D buffer */
+ MPI_Datatype mpi_cont_type; /* MPI derived type for 2D contiguous file */
+ MPI_Datatype mpi_partial_buffer_cont; /* MPI derived type for partial 2D contiguous buffer */
+ MPI_Datatype mpi_inter_type; /* MPI derived type for 2D interleaved file */
+ MPI_Datatype mpi_partial_buffer_inter; /* MPI derived type for partial 2D interleaved buffer */
+ MPI_Datatype mpi_full_buffer; /* MPI derived type for 2D full buffer */
+ MPI_Datatype mpi_full_chunk; /* MPI derived type for 2D full chunk */
+ MPI_Datatype mpi_chunk_inter_type; /* MPI derived type for 2D chunk interleaved file */
+ MPI_Datatype mpi_collective_type; /* Generic MPI derived type for 2D collective access */
+ MPI_Status mpi_status;
+ int mrc; /* MPI return code */
+
+ /* HDF5 variables */
+ herr_t hrc; /*HDF5 return code */
+ hsize_t h5dims[2]; /*dataset dim sizes */
+ hid_t h5dset_space_id = -1; /*dataset space ID */
+ hid_t h5mem_space_id = -1; /*memory dataspace ID */
+ hid_t h5ds_id = -1; /*dataset handle */
+ hsize_t h5block[2]; /*dataspace selection */
+ hsize_t h5stride[2];
+ hsize_t h5count[2];
+ hsize_t h5start[2];
+ hssize_t h5offset[2]; /* Selection offset within dataspace */
+ hid_t h5dcpl = -1; /* Dataset creation property list */
+ hid_t h5dxpl = -1; /* Dataset transfer property list */
+
+ /* Get the parameters from the parameter block */
+ blk_size=parms->blk_size;
+
+ /* There are two kinds of transfer patterns, contiguous and interleaved.
+ * Let 0,1,2,...,n be data accessed by process 0,1,2,...,n
+ * where n is rank of the last process.
+ * In contiguous pattern, data are accessed as
+ * 000...111...222...nnn...
+ * In interleaved pattern, data are accessed as
+ * 012...n012...n...
+ * These are all in the scope of one dataset.
+ */
+
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Contiguous Pattern: */
+ if (!parms->interleaved) {
+ bytes_begin[0] = (off_t)(((double)nbytes*pio_mpi_rank_g)/pio_mpi_nprocs_g);
+ } /* end if */
+ /* Interleaved Pattern: */
+ else {
+ bytes_begin[0] = (off_t)(blk_size*pio_mpi_rank_g);
+ } /* end else */
+
+ /* Prepare buffer for verifying data */
+ if (parms->verify)
+ memset(buffer,pio_mpi_rank_g+1,buf_size);
+ }/* end if */
+ /* 2D dataspace */
+ else {
+ /* nbytes is always the number of bytes per dataset (1D or 2D). If the
+ dataspace is 2D, snbytes is the size of a side of the dataset square.
+ */
+ snbytes = (off_t)sqrt(nbytes);
+
+ /* Contiguous Pattern: */
+ if (!parms->interleaved) {
+ bytes_begin[0] = (off_t)((double)snbytes*pio_mpi_rank_g / pio_mpi_nprocs_g);
+ bytes_begin[1] = 0;
+ } /* end if */
+ /* Interleaved Pattern: */
+ else {
+ bytes_begin[0] = 0;
+
+ if(!parms->h5_use_chunks || parms->io_type==PHDF5)
+ bytes_begin[1] = (off_t)(blk_size*pio_mpi_rank_g);
+ else
+ bytes_begin[1] = (off_t)(blk_size*blk_size*pio_mpi_rank_g);
+ } /* end else */
+
+ /* Prepare buffer for verifying data */
+ if (parms->verify)
+ memset(buffer,pio_mpi_rank_g+1,buf_size*blk_size);
+ } /* end else */
+
+
+ /* Calculate the total number of bytes (bytes_count) to be
+ * transferred by this process. It may be different for different
+ * transfer pattern due to rounding to integral values.
+ */
+ /*
+ * Calculate the beginning bytes of this process and the next.
+ * bytes_count is the difference between these two beginnings.
+ * This way, it eliminates any rounding errors.
+ * (This is tricky, don't mess with the formula, rounding errors
+ * can easily get introduced) */
+ bytes_count = (off_t)(((double)nbytes*(pio_mpi_rank_g+1)) / pio_mpi_nprocs_g)
+ - (off_t)(((double)nbytes*pio_mpi_rank_g) / pio_mpi_nprocs_g);
+
+ /* debug */
+ if (pio_debug_level >= 4) {
+ HDprint_rank(output);
+ if (!parms->dim2d) {
+ HDfprintf(output, "Debug(do_write): "
+ "buf_size=%zu, bytes_begin=%" H5_PRINTF_LL_WIDTH "d, bytes_count=%" H5_PRINTF_LL_WIDTH "d\n",
+ buf_size, (long long)bytes_begin[0],
+ (long long)bytes_count);
+ } else {
+ HDfprintf(output, "Debug(do_write): "
+ "linear buf_size=%zu, bytes_begin=(%" H5_PRINTF_LL_WIDTH "d,%" H5_PRINTF_LL_WIDTH "d), bytes_count=%" H5_PRINTF_LL_WIDTH "d\n",
+ buf_size*blk_size, (long long)bytes_begin[0],
+ (long long)bytes_begin[1], (long long)bytes_count);
+ }
+ }
+
+ /* I/O Access specific setup */
+ switch (parms->io_type) {
+ case POSIXIO:
+ /* No extra setup */
+ break;
+
+ case MPIO: /* MPI-I/O setup */
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Build block's derived type */
+ mrc = MPI_Type_contiguous((int)blk_size,
+ MPI_BYTE, &mpi_blk_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Build file's derived type */
+ mrc = MPI_Type_vector((int)(buf_size/blk_size), (int)1,
+ (int)pio_mpi_nprocs_g, mpi_blk_type, &mpi_file_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit file type */
+ mrc = MPI_Type_commit( &mpi_file_type );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Commit buffer type */
+ mrc = MPI_Type_commit( &mpi_blk_type );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+ } /* end if */
+ /* 2D dataspace */
+ else {
+ /* Build partial buffer derived type for contiguous access */
+
+ mrc = MPI_Type_contiguous((int)buf_size, MPI_BYTE,
+ &mpi_partial_buffer_cont);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit partial buffer derived type */
+ mrc = MPI_Type_commit(&mpi_partial_buffer_cont);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Build contiguous file's derived type */
+ mrc = MPI_Type_vector((int)blk_size, (int)1, (int)(snbytes/buf_size),
+ mpi_partial_buffer_cont, &mpi_cont_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit contiguous file type */
+ mrc = MPI_Type_commit(&mpi_cont_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Build partial buffer derived type for interleaved access */
+ mrc = MPI_Type_contiguous((int)blk_size, MPI_BYTE,
+ &mpi_partial_buffer_inter);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit partial buffer derived type */
+ mrc = MPI_Type_commit(&mpi_partial_buffer_inter);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Build interleaved file's derived type */
+ mrc = MPI_Type_vector((int)buf_size, (int)1, (int)(snbytes/blk_size),
+ mpi_partial_buffer_inter, &mpi_inter_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit interleaved file type */
+ mrc = MPI_Type_commit(&mpi_inter_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Build full buffer derived type */
+ mrc = MPI_Type_contiguous((int)(blk_size*buf_size), MPI_BYTE,
+ &mpi_full_buffer);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit full buffer derived type */
+ mrc = MPI_Type_commit(&mpi_full_buffer);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Build full chunk derived type */
+ mrc = MPI_Type_contiguous((int)(blk_size*blk_size), MPI_BYTE,
+ &mpi_full_chunk);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit full chunk derived type */
+ mrc = MPI_Type_commit(&mpi_full_chunk);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Build chunk interleaved file's derived type */
+ mrc = MPI_Type_vector((int)(buf_size/blk_size), (int)1, (int)(snbytes/blk_size),
+ mpi_full_chunk, &mpi_chunk_inter_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit chunk interleaved file type */
+ mrc = MPI_Type_commit(&mpi_chunk_inter_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ } /* end else */
+ break;
+
+ case PHDF5: /* HDF5 setup */
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ if(nbytes>0) {
+ /* define a contiguous dataset of nbytes native bytes */
+ h5dims[0] = nbytes;
+ h5dset_space_id = H5Screate_simple(1, h5dims, NULL);
+ VRFY((h5dset_space_id >= 0), "H5Screate_simple");
+
+ /* Set up the file dset space id to select the pattern to access */
+ if (!parms->interleaved){
+ /* Contiguous pattern */
+ h5start[0] = bytes_begin[0];
+ h5stride[0] = h5block[0] = blk_size;
+ h5count[0] = buf_size/blk_size;
+ } /* end if */
+ else {
+ /* Interleaved access pattern */
+ /* Skip offset over blocks of other processes */
+ h5start[0] = bytes_begin[0];
+ h5stride[0] = blk_size*pio_mpi_nprocs_g;
+ h5block[0] = blk_size;
+ h5count[0] = buf_size/blk_size;
+ } /* end else */
+ hrc = H5Sselect_hyperslab(h5dset_space_id, H5S_SELECT_SET,
+ h5start, h5stride, h5count, h5block);
+ VRFY((hrc >= 0), "H5Sselect_hyperslab");
+ } /* end if */
+ else {
+ h5dset_space_id = H5Screate(H5S_SCALAR);
+ VRFY((h5dset_space_id >= 0), "H5Screate");
+ } /* end else */
+
+ /* Create the memory dataspace that corresponds to the xfer buffer */
+ if(buf_size>0) {
+ h5dims[0] = buf_size;
+ h5mem_space_id = H5Screate_simple(1, h5dims, NULL);
+ VRFY((h5mem_space_id >= 0), "H5Screate_simple");
+ } /* end if */
+ else {
+ h5mem_space_id = H5Screate(H5S_SCALAR);
+ VRFY((h5mem_space_id >= 0), "H5Screate");
+ } /* end else */
+ } /* end if */
+ /* 2D dataspace */
+ else {
+ if(nbytes>0) {
+ /* define a contiguous dataset of nbytes native bytes */
+ h5dims[0] = snbytes;
+ h5dims[1] = snbytes;
+ h5dset_space_id = H5Screate_simple(2, h5dims, NULL);
+ VRFY((h5dset_space_id >= 0), "H5Screate_simple");
+
+ /* Set up the file dset space id to select the pattern to access */
+ if (!parms->interleaved){
+ /* Contiguous pattern */
+ h5start[0] = bytes_begin[0];
+ h5start[1] = bytes_begin[1];
+ h5stride[0] = 1;
+ h5stride[1] = h5block[0] = h5block[1] = blk_size;
+ h5count[0] = 1;
+ h5count[1] = buf_size/blk_size;
+ } /* end if */
+ else {
+ /* Interleaved access pattern */
+ /* Skip offset over blocks of other processes */
+ h5start[0] = bytes_begin[0];
+ h5start[1] = bytes_begin[1];
+ h5stride[0] = blk_size;
+ h5stride[1] = blk_size*pio_mpi_nprocs_g;
+ h5block[0] = h5block[1] = blk_size;
+ h5count[0] = buf_size/blk_size;
+ h5count[1] = 1;
+ } /* end else */
+ hrc = H5Sselect_hyperslab(h5dset_space_id, H5S_SELECT_SET,
+ h5start, h5stride, h5count, h5block);
+ VRFY((hrc >= 0), "H5Sselect_hyperslab");
+ } /* end if */
+ else {
+ h5dset_space_id = H5Screate(H5S_SCALAR);
+ VRFY((h5dset_space_id >= 0), "H5Screate");
+ } /* end else */
+
+ /* Create the memory dataspace that corresponds to the xfer buffer */
+ if(buf_size>0) {
+ if (!parms->interleaved){
+ h5dims[0] = blk_size;
+ h5dims[1] = buf_size;
+ }else{
+ h5dims[0] = buf_size;
+ h5dims[1] = blk_size;
+ }
+ h5mem_space_id = H5Screate_simple(2, h5dims, NULL);
+ VRFY((h5mem_space_id >= 0), "H5Screate_simple");
+ } /* end if */
+ else {
+ h5mem_space_id = H5Screate(H5S_SCALAR);
+ VRFY((h5mem_space_id >= 0), "H5Screate");
+ } /* end else */
+ } /* end else */
+
+ /* Create the dataset transfer property list */
+ h5dxpl = H5Pcreate(H5P_DATASET_XFER);
+ if (h5dxpl < 0) {
+ fprintf(stderr, "HDF5 Property List Create failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ /* Change to collective I/O, if asked */
+ if(parms->collective) {
+ hrc = H5Pset_dxpl_mpio(h5dxpl, H5FD_MPIO_COLLECTIVE);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Property List Set failed\n");
+ GOTOERROR(FAIL);
+ } /* end if */
+ } /* end if */
+ break;
+ } /* end switch */
+
+ for (ndset = 1; ndset <= ndsets; ++ndset) {
+
+ /* Calculate dataset offset within a file */
+
+ /* create dataset */
+ switch (parms->io_type) {
+ case POSIXIO:
+ case MPIO:
+ /* both posix and mpi io just need dataset offset in file*/
+ dset_offset = (ndset - 1) * nbytes;
+ break;
+
+ case PHDF5:
+ h5dcpl = H5Pcreate(H5P_DATASET_CREATE);
+ if (h5dcpl < 0) {
+ fprintf(stderr, "HDF5 Property List Create failed\n");
+ GOTOERROR(FAIL);
+ }
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Make the dataset chunked if asked */
+ if(parms->h5_use_chunks) {
+ /* Set the chunk size to be the same as the buffer size */
+ h5dims[0] = blk_size;
+ hrc = H5Pset_chunk(h5dcpl, 1, h5dims);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Property List Set failed\n");
+ GOTOERROR(FAIL);
+ } /* end if */
+ } /* end if */
+ }/* end if */
+ else{
+ /* 2D dataspace */
+ if(parms->h5_use_chunks) {
+ /* Set the chunk size to be the same as the block size */
+ h5dims[0] = blk_size;
+ h5dims[1] = blk_size;
+ hrc = H5Pset_chunk(h5dcpl, 2, h5dims);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Property List Set failed\n");
+ GOTOERROR(FAIL);
+ } /* end if */
+ } /* end if */
+ }/* end else */
+
+ sprintf(dname, "Dataset_%ld", ndset);
+ h5ds_id = H5DCREATE(fd->h5fd, dname, ELMT_H5_TYPE,
+ h5dset_space_id, h5dcpl);
+
+ if (h5ds_id < 0) {
+ fprintf(stderr, "HDF5 Dataset Create failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ hrc = H5Pclose(h5dcpl);
+ /* verifying the close of the dcpl */
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Property List Close failed\n");
+ GOTOERROR(FAIL);
+ }
+ break;
+ }
+
+ /* The task is to transfer bytes_count bytes, starting at
+ * bytes_begin position, using transfer buffer of buf_size bytes.
+ * If interleaved, select buf_size at a time, in round robin
+ * fashion, according to number of process. Otherwise, select
+ * all bytes_count in contiguous.
+ */
+ nbytes_xfer = 0 ;
+
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Set base file offset for all I/O patterns and POSIX access */
+ posix_file_offset = dset_offset + bytes_begin[0];
+
+ /* Set base file offset for all I/O patterns and MPI access */
+ mpi_file_offset = (MPI_Offset)(dset_offset + bytes_begin[0]);
+ } /* end if */
+ else {
+ /* Set base file offset for all I/O patterns and POSIX access */
+ posix_file_offset=dset_offset + bytes_begin[0]*snbytes+
+ bytes_begin[1];
+
+ /* Set base file offset for all I/O patterns and MPI access */
+ mpi_file_offset=(MPI_Offset)(dset_offset + bytes_begin[0]*snbytes+
+ bytes_begin[1]);
+ } /* end else */
+
+ /* Start "raw data" write timer */
+ set_time(res->timers, HDF5_RAW_WRITE_FIXED_DIMS, TSTART);
+
+ while (nbytes_xfer < bytes_count){
+ /* Write */
+ /* Calculate offset of write within a dataset/file */
+ switch (parms->io_type) {
+ case POSIXIO:
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Contiguous pattern */
+ if (!parms->interleaved) {
+ /* Compute file offset */
+ file_offset = posix_file_offset + (off_t)nbytes_xfer;
+
+ /* only care if seek returns error */
+ rc = POSIXSEEK(fd->posixfd, file_offset) < 0 ? -1 : 0;
+ VRFY((rc==0), "POSIXSEEK");
+
+ /* check if all bytes are written */
+ rc = ((ssize_t)buf_size ==
+ POSIXWRITE(fd->posixfd, buffer, buf_size));
+ VRFY((rc != 0), "POSIXWRITE");
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=buf_size;
+ } /* end if */
+ /* Interleaved access pattern */
+ else {
+ /* Set the base of user's buffer */
+ buf_p=(unsigned char *)buffer;
+
+ /* Set the number of bytes to transfer this time */
+ nbytes_toxfer = buf_size;
+
+ /* Loop over the buffers to write */
+ while(nbytes_toxfer>0) {
+ /* Skip offset over blocks of other processes */
+ file_offset = posix_file_offset +
+ (off_t)(nbytes_xfer*pio_mpi_nprocs_g);
+
+ /* only care if seek returns error */
+ rc = POSIXSEEK(fd->posixfd, file_offset) < 0 ? -1 : 0;
+ VRFY((rc==0), "POSIXSEEK");
+
+ /* check if all bytes are written */
+ rc = ((ssize_t)blk_size ==
+ POSIXWRITE(fd->posixfd, buf_p, blk_size));
+ VRFY((rc != 0), "POSIXWRITE");
+
+ /* Advance location in buffer */
+ buf_p+=blk_size;
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=blk_size;
+
+ /* Decrement number of bytes left this time */
+ nbytes_toxfer-=blk_size;
+ } /* end while */
+ } /* end else */
+ } /* end if */
+ /* 2D dataspace */
+ else {
+ /* Contiguous storage */
+ if (!parms->h5_use_chunks) {
+ /* Contiguous access pattern */
+ if (!parms->interleaved) {
+ /* Compute file offset */
+ file_offset=posix_file_offset+(off_t)(((nbytes_xfer/blk_size)
+ /snbytes)*(blk_size*snbytes)+((nbytes_xfer/blk_size)%snbytes));
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = buf_size;
+
+ /* Global offset advance after each I/O operation */
+ file_offset_advance = (off_t)snbytes;
+ } /* end if */
+ /* Interleaved access pattern */
+ else {
+ /* Compute file offset */
+ file_offset=posix_file_offset+(off_t)((((nbytes_xfer/buf_size)
+ *pio_mpi_nprocs_g)/snbytes)*(buf_size*snbytes)
+ +((nbytes_xfer/buf_size)*pio_mpi_nprocs_g)%snbytes);
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = blk_size;
+
+ /* Global offset advance after each I/O operation */
+ file_offset_advance = (off_t)snbytes;
+ } /* end else */
+ } /* end if */
+ /* Chunked storage */
+ else {
+ /*Contiguous access pattern */
+ if (!parms->interleaved) {
+ /* Compute file offset */
+ file_offset=posix_file_offset+(off_t)nbytes_xfer;
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = blk_size * buf_size;
+
+ /* Global offset advance after each I/O operation */
+ file_offset_advance = 0;
+ } /* end if */
+ /*Interleaved access pattern */
+ else {
+ /* Compute file offset */
+ /* Before simplification */
+ /* file_offset=posix_file_offset+(off_t)((nbytes_xfer/(buf_size/blk_size)
+ *pio_mpi_nprocs_g)/(snbytes/blk_size*(blk_size*blk_size))*(buf_size/blk_size
+ *snbytes/blk_size*(blk_size*blk_size))+((nbytes_xfer/(buf_size/blk_size))
+ *pio_mpi_nprocs_g)%(snbytes/blk_size*(blk_size*blk_size))); */
+
+ file_offset=posix_file_offset+(off_t)(((nbytes_xfer/(buf_size/blk_size)
+ *pio_mpi_nprocs_g)/(snbytes*blk_size))*(buf_size*snbytes)+((nbytes_xfer/(buf_size/blk_size))
+ *pio_mpi_nprocs_g)%(snbytes*blk_size));
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = blk_size * blk_size;
+
+ /* Global offset advance after each I/O operation */
+ /* file_offset_advance = (off_t)(snbytes/blk_size*(blk_size*blk_size)); */
+ file_offset_advance = (off_t)(snbytes*blk_size);
+ } /* end else */
+ } /* end else */
+
+ /* Common code for file access */
+
+ /* Set the base of user's buffer */
+ buf_p = (unsigned char *)buffer;
+
+ /* Set the number of bytes to transfer this time */
+ nbytes_toxfer = buf_size*blk_size;
+
+ /* Loop over portions of the buffer to write */
+ while(nbytes_toxfer>0){
+ /* only care if seek returns error */
+ rc = POSIXSEEK(fd->posixfd, file_offset) < 0 ? -1 : 0;
+ VRFY((rc==0), "POSIXSEEK");
+
+ /* check if all bytes are written */
+ rc = ((ssize_t)nbytes_xfer_advance ==
+ POSIXWRITE(fd->posixfd, buf_p, nbytes_xfer_advance));
+ VRFY((rc != 0), "POSIXWRITE");
+
+ /* Advance location in buffer */
+ buf_p+=nbytes_xfer_advance;
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=nbytes_xfer_advance;
+
+ /* Decrement number of bytes left this time */
+ nbytes_toxfer-=nbytes_xfer_advance;
+
+ /* Partially advance file offset */
+ file_offset+=file_offset_advance;
+ } /* end while */
+
+ } /* end else */
+
+ break;
+
+ case MPIO:
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Independent file access */
+ if(!parms->collective) {
+ /* Contiguous pattern */
+ if (!parms->interleaved){
+ /* Compute offset in file */
+ mpi_offset = mpi_file_offset +
+ nbytes_xfer;
+
+ /* Perform independent write */
+ mrc = MPI_File_write_at(fd->mpifd, mpi_offset, buffer,
+ (int)(buf_size/blk_size), mpi_blk_type,
+ &mpi_status);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_WRITE");
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=buf_size;
+ } /* end if */
+ /* Interleaved access pattern */
+ else {
+ /* Set the base of user's buffer */
+ buf_p=(unsigned char *)buffer;
+
+ /* Set the number of bytes to transfer this time */
+ nbytes_toxfer = buf_size;
+
+ /* Loop over the buffers to write */
+ while(nbytes_toxfer>0) {
+ /* Skip offset over blocks of other processes */
+ mpi_offset = mpi_file_offset +
+ (nbytes_xfer*pio_mpi_nprocs_g);
+
+ /* Perform independent write */
+ mrc = MPI_File_write_at(fd->mpifd, mpi_offset, buf_p,
+ (int)1, mpi_blk_type, &mpi_status);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_WRITE");
+
+ /* Advance location in buffer */
+ buf_p+=blk_size;
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=blk_size;
+
+ /* Decrement number of bytes left this time */
+ nbytes_toxfer-=blk_size;
+ } /* end while */
+ } /* end else */
+ } /* end if */
+ /* Collective file access */
+ else {
+ /* Contiguous access pattern */
+ if (!parms->interleaved){
+ /* Compute offset in file */
+ mpi_offset = mpi_file_offset +
+ nbytes_xfer;
+
+ /* Perform independent write */
+ mrc = MPI_File_write_at_all(fd->mpifd, mpi_offset, buffer,
+ (int)(buf_size/blk_size), mpi_blk_type, &mpi_status);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_WRITE");
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=buf_size;
+ } /* end if */
+ /* Interleaved access pattern */
+ else {
+ /* Compute offset in file */
+ mpi_offset = mpi_file_offset +
+ (nbytes_xfer*pio_mpi_nprocs_g);
+
+ /* Set the file view */
+ mrc = MPI_File_set_view(fd->mpifd, mpi_offset, mpi_blk_type,
+ mpi_file_type, (char*)"native", h5_io_info_g);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_VIEW");
+
+ /* Perform write */
+ mrc = MPI_File_write_at_all(fd->mpifd, 0, buffer,
+ (int)(buf_size/blk_size), mpi_blk_type, &mpi_status);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_WRITE");
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=buf_size;
+ } /* end else */
+ } /* end else */
+ } /* end if */
+ /* 2D dataspace */
+ else {
+ /* Contiguous storage */
+ if (!parms->h5_use_chunks) {
+ /* Contiguous access pattern */
+ if (!parms->interleaved) {
+ /* Compute offset in file */
+ mpi_offset=mpi_file_offset+((nbytes_xfer/blk_size)/snbytes)*
+ (blk_size*snbytes)+((nbytes_xfer/blk_size)%snbytes);
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = buf_size;
+
+ /* Global offset advance after each I/O operation */
+ mpi_offset_advance = snbytes;
+
+ /* MPI type to be used for collective access */
+ mpi_collective_type = mpi_cont_type;
+ } /* end if */
+ /* Interleaved access pattern */
+ else {
+ /* Compute offset in file */
+ mpi_offset=mpi_file_offset+(((nbytes_xfer/buf_size)*pio_mpi_nprocs_g)/snbytes)*
+ (buf_size*snbytes)+((nbytes_xfer/buf_size)*pio_mpi_nprocs_g)%snbytes;
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = blk_size;
+
+ /* Global offset advance after each I/O operation */
+ mpi_offset_advance = snbytes;
+
+ /* MPI type to be used for collective access */
+ mpi_collective_type = mpi_inter_type;
+ } /* end else */
+ } /* end if */
+ /* Chunked storage */
+ else {
+ /*Contiguous access pattern */
+ if (!parms->interleaved) {
+ /* Compute offset in file */
+ mpi_offset=mpi_file_offset+nbytes_xfer;
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = blk_size * buf_size;
+
+ /* Global offset advance after each I/O operation */
+ mpi_offset_advance = 0;
+
+ /* MPI type to be used for collective access */
+ mpi_collective_type = mpi_full_buffer;
+ } /* end if */
+ /*Interleaved access pattern */
+ else {
+ /* Compute offset in file */
+ /* Before simplification */
+ /* mpi_offset=mpi_file_offset+(nbytes_xfer/(buf_size/blk_size)
+ *pio_mpi_nprocs_g)/(snbytes/blk_size*(blk_size*blk_size))*
+ (buf_size/blk_size*snbytes/blk_size*(blk_size*blk_size))+
+ ((nbytes_xfer/(buf_size/blk_size))*pio_mpi_nprocs_g)%(snbytes
+ /blk_size*(blk_size*blk_size)); */
+ mpi_offset=mpi_file_offset+((nbytes_xfer/(buf_size/blk_size)
+ *pio_mpi_nprocs_g)/(snbytes*blk_size))*(buf_size*snbytes)
+ +((nbytes_xfer/(buf_size/blk_size))*pio_mpi_nprocs_g)%(snbytes*blk_size);
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = blk_size * blk_size;
+
+ /* Global offset advance after each I/O operation */
+ /* mpi_offset_advance = (MPI_Offset)(snbytes/blk_size*(blk_size*blk_size)); */
+ mpi_offset_advance = (MPI_Offset)(snbytes*blk_size);
+
+ /* MPI type to be used for collective access */
+ mpi_collective_type = mpi_chunk_inter_type;
+ } /* end else */
+ } /* end else */
+
+ /* Common code for independent file access */
+ if (!parms->collective) {
+ /* Set the base of user's buffer */
+ buf_p = (unsigned char *)buffer;
+
+ /* Set the number of bytes to transfer this time */
+ nbytes_toxfer = buf_size * blk_size;
+
+ /* Loop over portions of the buffer to write */
+ while(nbytes_toxfer>0){
+ /* Perform independent write */
+ mrc = MPI_File_write_at(fd->mpifd, mpi_offset, buf_p,
+ (int)nbytes_xfer_advance, MPI_BYTE, &mpi_status);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_WRITE");
+
+ /* Advance location in buffer */
+ buf_p+=nbytes_xfer_advance;
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=nbytes_xfer_advance;
+
+ /* Decrement number of bytes left this time */
+ nbytes_toxfer-=nbytes_xfer_advance;
+
+ /* Partially advance global offset in dataset */
+ mpi_offset+=mpi_offset_advance;
+ } /* end while */
+ } /* end if */
+
+ /* Common code for collective file access */
+ else {
+ /* Set the file view */
+ mrc = MPI_File_set_view(fd->mpifd, mpi_offset, MPI_BYTE,
+ mpi_collective_type, (char *)"native", h5_io_info_g);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_VIEW");
+
+ /* Perform write */
+ MPI_File_write_at_all(fd->mpifd, 0, buffer,(int)(buf_size*blk_size),
+ MPI_BYTE, &mpi_status);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_WRITE");
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=buf_size*blk_size;
+ } /* end else */
+
+ } /* end else */
+
+ break;
+
+ case PHDF5:
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Set up the file dset space id to move the selection to process */
+ if (!parms->interleaved){
+ /* Contiguous pattern */
+ h5offset[0] = nbytes_xfer;
+ } /* end if */
+ else {
+ /* Interleaved access pattern */
+ /* Skip offset over blocks of other processes */
+ h5offset[0] = (nbytes_xfer*pio_mpi_nprocs_g);
+ } /* end else */
+ hrc = H5Soffset_simple(h5dset_space_id, h5offset);
+ VRFY((hrc >= 0), "H5Soffset_simple");
+
+ /* Write the buffer out */
+ hrc = H5Dwrite(h5ds_id, ELMT_H5_TYPE, h5mem_space_id,
+ h5dset_space_id, h5dxpl, buffer);
+ VRFY((hrc >= 0), "H5Dwrite");
+
+ /* Increment number of bytes transferred */
+ nbytes_xfer += buf_size;
+ } /* end if */
+ /* 2D dataspace */
+ else {
+ /* Set up the file dset space id to move the selection to process */
+ if (!parms->interleaved){
+ /* Contiguous pattern */
+ h5offset[0] = (nbytes_xfer/(snbytes*blk_size))*blk_size;
+ h5offset[1] = (nbytes_xfer%(snbytes*blk_size))/blk_size;
+
+ } /* end if */
+ else {
+ /* Interleaved access pattern */
+ /* Skip offset over blocks of other processes */
+ h5offset[0] = ((nbytes_xfer*pio_mpi_nprocs_g)/(snbytes*buf_size))*buf_size;
+ h5offset[1] = ((nbytes_xfer*pio_mpi_nprocs_g)%(snbytes*buf_size))/buf_size;
+
+ } /* end else */
+ hrc = H5Soffset_simple(h5dset_space_id, h5offset);
+ VRFY((hrc >= 0), "H5Soffset_simple");
+
+ /* Write the buffer out */
+ hrc = H5Dwrite(h5ds_id, ELMT_H5_TYPE, h5mem_space_id,
+ h5dset_space_id, h5dxpl, buffer);
+ VRFY((hrc >= 0), "H5Dwrite");
+
+ /* Increment number of bytes transferred */
+ nbytes_xfer += buf_size*blk_size;
+
+ } /* end else */
+
+ break;
+ } /* switch (parms->io_type) */
+ } /* end while */
+
+ /* Stop "raw data" write timer */
+ set_time(res->timers, HDF5_RAW_WRITE_FIXED_DIMS, TSTOP);
+
+ /* Calculate write time */
+
+ /* Close dataset. Only HDF5 needs to do an explicit close. */
+ if (parms->io_type == PHDF5) {
+ hrc = H5Dclose(h5ds_id);
+
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Dataset Close failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ h5ds_id = -1;
+ } /* end if */
+ } /* end for */
+
+done:
+ /* release MPI-I/O objects */
+ if (parms->io_type == MPIO) {
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Free file type */
+ mrc = MPI_Type_free( &mpi_file_type );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free buffer type */
+ mrc = MPI_Type_free( &mpi_blk_type );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+ } /* end if */
+ /* 2D dataspace */
+ else {
+ /* Free partial buffer type for contiguous access */
+ mrc = MPI_Type_free( &mpi_partial_buffer_cont );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free contiguous file type */
+ mrc = MPI_Type_free( &mpi_cont_type );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free partial buffer type for interleaved access */
+ mrc = MPI_Type_free( &mpi_partial_buffer_inter );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free interleaved file type */
+ mrc = MPI_Type_free( &mpi_inter_type );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free full buffer type */
+ mrc = MPI_Type_free(&mpi_full_buffer);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free full chunk type */
+ mrc = MPI_Type_free(&mpi_full_chunk);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free chunk interleaved file type */
+ mrc = MPI_Type_free(&mpi_chunk_inter_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+ } /* end else */
+ } /* end if */
+
+ /* release HDF5 objects */
+ if (h5dset_space_id != -1) {
+ hrc = H5Sclose(h5dset_space_id);
+ if (hrc < 0){
+ fprintf(stderr, "HDF5 Dataset Space Close failed\n");
+ ret_code = FAIL;
+ } else {
+ h5dset_space_id = -1;
+ }
+ }
+
+ if (h5mem_space_id != -1) {
+ hrc = H5Sclose(h5mem_space_id);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Memory Space Close failed\n");
+ ret_code = FAIL;
+ } else {
+ h5mem_space_id = -1;
+ }
+ }
+
+ if (h5dxpl != -1) {
+ hrc = H5Pclose(h5dxpl);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Dataset Transfer Property List Close failed\n");
+ ret_code = FAIL;
+ } else {
+ h5dxpl = -1;
+ }
+ }
+
+ return ret_code;
+}
+
+/*
+ * Function: do_read
+ * Purpose: read the required amount of data from the file.
+ * Return: SUCCESS or FAIL
+ * Programmer: Albert Cheng 2001/12/13
+ * Modifications:
+ * Added 2D testing (Christian Chilan, 10. August 2005)
+ */
+ static herr_t
+do_read(results *res, file_descr *fd, parameters *parms, long ndsets,
+ off_t nbytes, size_t buf_size, void *buffer /*out*/)
+{
+ int ret_code = SUCCESS;
+ int rc; /*routine return code */
+ long ndset;
+ size_t blk_size; /* The block size to subdivide the xfer buffer into */
+ size_t bsize; /* Size of the actual buffer */
+ off_t nbytes_xfer; /* Total number of bytes transferred so far */
+ size_t nbytes_xfer_advance; /* Number of bytes transferred in a single I/O operation */
+ size_t nbytes_toxfer; /* Number of bytes to transfer a particular time */
+ char dname[64];
+ off_t dset_offset=0; /*dataset offset in a file */
+ off_t bytes_begin[2]; /*first elmt this process transfer */
+ off_t bytes_count; /*number of elmts this process transfer */
+ off_t snbytes=0; /*size of a side of the dataset square */
+ unsigned char *buf_p; /* Current buffer pointer */
+
+ /* POSIX variables */
+ off_t file_offset; /* File offset of the next transfer */
+ off_t file_offset_advance; /* File offset advance after each I/O operation */
+ off_t posix_file_offset; /* Base file offset of the next transfer */
+
+ /* MPI variables */
+ MPI_Offset mpi_file_offset;/* Base file offset of the next transfer*/
+ MPI_Offset mpi_offset; /* Offset in MPI file */
+ MPI_Offset mpi_offset_advance; /* Offset advance after each I/O operation */
+ MPI_Datatype mpi_file_type; /* MPI derived type for 1D file */
+ MPI_Datatype mpi_blk_type; /* MPI derived type for 1D buffer */
+ MPI_Datatype mpi_cont_type; /* MPI derived type for 2D contiguous file */
+ MPI_Datatype mpi_partial_buffer_cont; /* MPI derived type for partial 2D contiguous buffer */
+ MPI_Datatype mpi_inter_type; /* MPI derived type for 2D interleaved file */
+ MPI_Datatype mpi_partial_buffer_inter; /* MPI derived type for partial 2D interleaved buffer */
+ MPI_Datatype mpi_full_buffer; /* MPI derived type for 2D full buffer */
+ MPI_Datatype mpi_full_chunk; /* MPI derived type for 2D full chunk */
+ MPI_Datatype mpi_chunk_inter_type; /* MPI derived type for 2D chunk interleaved file */
+ MPI_Datatype mpi_collective_type; /* Generic MPI derived type for 2D collective access */
+ MPI_Status mpi_status;
+ int mrc; /* MPI return code */
+
+ /* HDF5 variables */
+ herr_t hrc; /*HDF5 return code */
+ hsize_t h5dims[2]; /*dataset dim sizes */
+ hid_t h5dset_space_id = -1; /*dataset space ID */
+ hid_t h5mem_space_id = -1; /*memory dataspace ID */
+ hid_t h5ds_id = -1; /*dataset handle */
+ hsize_t h5block[2]; /*dataspace selection */
+ hsize_t h5stride[2];
+ hsize_t h5count[2];
+ hsize_t h5start[2];
+ hssize_t h5offset[2]; /* Selection offset within dataspace */
+ hid_t h5dxpl = -1; /* Dataset transfer property list */
+
+ /* Get the parameters from the parameter block */
+ blk_size=parms->blk_size;
+
+ /* There are two kinds of transfer patterns, contiguous and interleaved.
+ * Let 0,1,2,...,n be data accessed by process 0,1,2,...,n
+ * where n is rank of the last process.
+ * In contiguous pattern, data are accessed as
+ * 000...111...222...nnn...
+ * In interleaved pattern, data are accessed as
+ * 012...n012...n...
+ * These are all in the scope of one dataset.
+ */
+
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ bsize = buf_size;
+ /* Contiguous Pattern: */
+ if (!parms->interleaved) {
+ bytes_begin[0] = (off_t)(((double)nbytes*pio_mpi_rank_g)/pio_mpi_nprocs_g);
+ } /* end if */
+ /* Interleaved Pattern: */
+ else {
+ bytes_begin[0] = (off_t)(blk_size*pio_mpi_rank_g);
+ } /* end else */
+ }/* end if */
+ /* 2D dataspace */
+ else {
+ /* nbytes is always the number of bytes per dataset (1D or 2D). If the
+ dataspace is 2D, snbytes is the size of a side of the 'dataset square'.
+ */
+ snbytes = (off_t)sqrt(nbytes);
+
+ bsize = buf_size * blk_size;
+
+ /* Contiguous Pattern: */
+ if (!parms->interleaved) {
+ bytes_begin[0] = (off_t)((double)snbytes*pio_mpi_rank_g / pio_mpi_nprocs_g);
+ bytes_begin[1] = 0;
+ } /* end if */
+ /* Interleaved Pattern: */
+ else {
+ bytes_begin[0] = 0;
+
+ if (!parms->h5_use_chunks || parms->io_type==PHDF5)
+ bytes_begin[1] = (off_t)(blk_size*pio_mpi_rank_g);
+ else
+ bytes_begin[1] = (off_t)(blk_size*blk_size*pio_mpi_rank_g);
+ } /* end else */
+ } /* end else */
+
+ /* Calculate the total number of bytes (bytes_count) to be
+ * transferred by this process. It may be different for different
+ * transfer pattern due to rounding to integral values.
+ */
+ /*
+ * Calculate the beginning bytes of this process and the next.
+ * bytes_count is the difference between these two beginnings.
+ * This way, it eliminates any rounding errors.
+ * (This is tricky, don't mess with the formula, rounding errors
+ * can easily get introduced) */
+ bytes_count = (off_t)(((double)nbytes*(pio_mpi_rank_g+1)) / pio_mpi_nprocs_g)
+ - (off_t)(((double)nbytes*pio_mpi_rank_g) / pio_mpi_nprocs_g);
+
+ /* debug */
+ if (pio_debug_level >= 4) {
+ HDprint_rank(output);
+ if (!parms->dim2d) {
+ HDfprintf(output, "Debug(do_write): "
+ "buf_size=%zu, bytes_begin=%" H5_PRINTF_LL_WIDTH "d, bytes_count=%" H5_PRINTF_LL_WIDTH "d\n",
+ buf_size, (long long)bytes_begin[0],
+ (long long)bytes_count);
+ } else {
+ HDfprintf(output, "Debug(do_write): "
+ "linear buf_size=%zu, bytes_begin=(%" H5_PRINTF_LL_WIDTH "d,%" H5_PRINTF_LL_WIDTH "d), bytes_count=%" H5_PRINTF_LL_WIDTH "d\n",
+ buf_size*blk_size, (long long)bytes_begin[0],
+ (long long)bytes_begin[1], (long long)bytes_count);
+ }
+ }
+
+ /* I/O Access specific setup */
+ switch (parms->io_type) {
+ case POSIXIO:
+ /* No extra setup */
+ break;
+
+ case MPIO: /* MPI-I/O setup */
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Build block's derived type */
+ mrc = MPI_Type_contiguous((int)blk_size,
+ MPI_BYTE, &mpi_blk_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Build file's derived type */
+ mrc = MPI_Type_vector((int)(buf_size/blk_size), (int)1,
+ (int)pio_mpi_nprocs_g, mpi_blk_type, &mpi_file_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit file type */
+ mrc = MPI_Type_commit( &mpi_file_type );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Commit buffer type */
+ mrc = MPI_Type_commit( &mpi_blk_type );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+ } /* end if */
+ /* 2D dataspace */
+ else {
+ /* Build partial buffer derived type for contiguous access */
+ mrc = MPI_Type_contiguous((int)buf_size, MPI_BYTE,
+ &mpi_partial_buffer_cont);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit partial buffer derived type */
+ mrc = MPI_Type_commit(&mpi_partial_buffer_cont);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Build contiguous file's derived type */
+ mrc = MPI_Type_vector((int)blk_size, (int)1, (int)(snbytes/buf_size),
+ mpi_partial_buffer_cont, &mpi_cont_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit contiguous file type */
+ mrc = MPI_Type_commit(&mpi_cont_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Build partial buffer derived type for interleaved access */
+ mrc = MPI_Type_contiguous((int)blk_size, MPI_BYTE,
+ &mpi_partial_buffer_inter);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit partial buffer derived type */
+ mrc = MPI_Type_commit(&mpi_partial_buffer_inter);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Build interleaved file's derived type */
+ mrc = MPI_Type_vector((int)buf_size, (int)1, (int)(snbytes/blk_size),
+ mpi_partial_buffer_inter, &mpi_inter_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit interleaved file type */
+ mrc = MPI_Type_commit(&mpi_inter_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Build full buffer derived type */
+ mrc = MPI_Type_contiguous((int)(blk_size*buf_size), MPI_BYTE,
+ &mpi_full_buffer);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit full buffer derived type */
+ mrc = MPI_Type_commit(&mpi_full_buffer);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Build full chunk derived type */
+ mrc = MPI_Type_contiguous((int)(blk_size*blk_size), MPI_BYTE,
+ &mpi_full_chunk);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit full chunk derived type */
+ mrc = MPI_Type_commit(&mpi_full_chunk);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+
+ /* Build chunk interleaved file's derived type */
+ mrc = MPI_Type_vector((int)(buf_size/blk_size), (int)1, (int)(snbytes/blk_size),
+ mpi_full_chunk, &mpi_chunk_inter_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_CREATE");
+
+ /* Commit chunk interleaved file type */
+ mrc = MPI_Type_commit(&mpi_chunk_inter_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_COMMIT");
+ } /* end else */
+ break;
+
+ case PHDF5: /* HDF5 setup */
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ if(nbytes>0) {
+ /* define a contiguous dataset of nbytes native bytes */
+ h5dims[0] = nbytes;
+ h5dset_space_id = H5Screate_simple(1, h5dims, NULL);
+ VRFY((h5dset_space_id >= 0), "H5Screate_simple");
+
+ /* Set up the file dset space id to select the pattern to access */
+ if (!parms->interleaved){
+ /* Contiguous pattern */
+ h5start[0] = bytes_begin[0];
+ h5stride[0] = h5block[0] = blk_size;
+ h5count[0] = buf_size/blk_size;
+ } /* end if */
+ else {
+ /* Interleaved access pattern */
+ /* Skip offset over blocks of other processes */
+ h5start[0] = bytes_begin[0];
+ h5stride[0] = blk_size*pio_mpi_nprocs_g;
+ h5block[0] = blk_size;
+ h5count[0] = buf_size/blk_size;
+ } /* end else */
+ hrc = H5Sselect_hyperslab(h5dset_space_id, H5S_SELECT_SET,
+ h5start, h5stride, h5count, h5block);
+ VRFY((hrc >= 0), "H5Sselect_hyperslab");
+ } /* end if */
+ else {
+ h5dset_space_id = H5Screate(H5S_SCALAR);
+ VRFY((h5dset_space_id >= 0), "H5Screate");
+ } /* end else */
+
+ /* Create the memory dataspace that corresponds to the xfer buffer */
+ if(buf_size>0) {
+ h5dims[0] = buf_size;
+ h5mem_space_id = H5Screate_simple(1, h5dims, NULL);
+ VRFY((h5mem_space_id >= 0), "H5Screate_simple");
+ } /* end if */
+ else {
+ h5mem_space_id = H5Screate(H5S_SCALAR);
+ VRFY((h5mem_space_id >= 0), "H5Screate");
+ } /* end else */
+ } /* end if */
+ /* 2D dataspace */
+ else {
+ if(nbytes>0) {
+ /* define a contiguous dataset of nbytes native bytes */
+ h5dims[0] = snbytes;
+ h5dims[1] = snbytes;
+ h5dset_space_id = H5Screate_simple(2, h5dims, NULL);
+ VRFY((h5dset_space_id >= 0), "H5Screate_simple");
+
+ /* Set up the file dset space id to select the pattern to access */
+ if (!parms->interleaved){
+ /* Contiguous pattern */
+ h5start[0] = bytes_begin[0];
+ h5start[1] = bytes_begin[1];
+ h5stride[0] = 1;
+ h5stride[1] = h5block[0] = h5block[1] = blk_size;
+ h5count[0] = 1;
+ h5count[1] = buf_size/blk_size;
+ } /* end if */
+ else {
+ /* Interleaved access pattern */
+ /* Skip offset over blocks of other processes */
+ h5start[0] = bytes_begin[0];
+ h5start[1] = bytes_begin[1];
+ h5stride[0] = blk_size;
+ h5stride[1] = blk_size*pio_mpi_nprocs_g;
+ h5block[0] = h5block[1] = blk_size;
+ h5count[0] = buf_size/blk_size;
+ h5count[1] = 1;
+ } /* end else */
+ hrc = H5Sselect_hyperslab(h5dset_space_id, H5S_SELECT_SET,
+ h5start, h5stride, h5count, h5block);
+ VRFY((hrc >= 0), "H5Sselect_hyperslab");
+ } /* end if */
+ else {
+ h5dset_space_id = H5Screate(H5S_SCALAR);
+ VRFY((h5dset_space_id >= 0), "H5Screate");
+ } /* end else */
+
+ /* Create the memory dataspace that corresponds to the xfer buffer */
+ if(buf_size>0) {
+ if (!parms->interleaved){
+ h5dims[0] = blk_size;
+ h5dims[1] = buf_size;
+ }else{
+ h5dims[0] = buf_size;
+ h5dims[1] = blk_size;
+ }
+ h5mem_space_id = H5Screate_simple(2, h5dims, NULL);
+ VRFY((h5mem_space_id >= 0), "H5Screate_simple");
+ } /* end if */
+ else {
+ h5mem_space_id = H5Screate(H5S_SCALAR);
+ VRFY((h5mem_space_id >= 0), "H5Screate");
+ } /* end else */
+ } /* end else */
+
+ /* Create the dataset transfer property list */
+ h5dxpl = H5Pcreate(H5P_DATASET_XFER);
+ if (h5dxpl < 0) {
+ fprintf(stderr, "HDF5 Property List Create failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ /* Change to collective I/O, if asked */
+ if(parms->collective) {
+ hrc = H5Pset_dxpl_mpio(h5dxpl, H5FD_MPIO_COLLECTIVE);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Property List Set failed\n");
+ GOTOERROR(FAIL);
+ } /* end if */
+ } /* end if */
+ break;
+ } /* end switch */
+
+ for (ndset = 1; ndset <= ndsets; ++ndset) {
+
+ /* Calculate dataset offset within a file */
+
+ /* create dataset */
+ switch (parms->io_type) {
+ case POSIXIO:
+ case MPIO:
+ /* both posix and mpi io just need dataset offset in file*/
+ dset_offset = (ndset - 1) * nbytes;
+ break;
+
+ case PHDF5:
+ sprintf(dname, "Dataset_%ld", ndset);
+ h5ds_id = H5DOPEN(fd->h5fd, dname);
+ if (h5ds_id < 0) {
+ fprintf(stderr, "HDF5 Dataset open failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ break;
+ }
+
+ /* The task is to transfer bytes_count bytes, starting at
+ * bytes_begin position, using transfer buffer of buf_size bytes.
+ * If interleaved, select buf_size at a time, in round robin
+ * fashion, according to number of process. Otherwise, select
+ * all bytes_count in contiguous.
+ */
+ nbytes_xfer = 0 ;
+
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Set base file offset for all I/O patterns and POSIX access */
+ posix_file_offset = dset_offset + bytes_begin[0];
+
+ /* Set base file offset for all I/O patterns and MPI access */
+ mpi_file_offset = (MPI_Offset)(dset_offset + bytes_begin[0]);
+ } /* end if */
+ else {
+ /* Set base file offset for all I/O patterns and POSIX access */
+ posix_file_offset=dset_offset + bytes_begin[0]*snbytes+
+ bytes_begin[1];
+
+ /* Set base file offset for all I/O patterns and MPI access */
+ mpi_file_offset=(MPI_Offset)(dset_offset + bytes_begin[0]*snbytes+
+ bytes_begin[1]);
+ } /* end else */
+
+ /* Start "raw data" read timer */
+ set_time(res->timers, HDF5_RAW_READ_FIXED_DIMS, TSTART);
+
+ while (nbytes_xfer < bytes_count){
+ /* Read */
+ /* Calculate offset of read within a dataset/file */
+ switch (parms->io_type) {
+ case POSIXIO:
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Contiguous pattern */
+ if (!parms->interleaved) {
+ /* Compute file offset */
+ file_offset = posix_file_offset + (off_t)nbytes_xfer;
+
+ /* only care if seek returns error */
+ rc = POSIXSEEK(fd->posixfd, file_offset) < 0 ? -1 : 0;
+ VRFY((rc==0), "POSIXSEEK");
+
+ /* check if all bytes are read */
+ rc = ((ssize_t)buf_size ==
+ POSIXREAD(fd->posixfd, buffer, buf_size));
+ VRFY((rc != 0), "POSIXREAD");
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=buf_size;
+ } /* end if */
+ /* Interleaved access pattern */
+ else {
+ /* Set the base of user's buffer */
+ buf_p=(unsigned char *)buffer;
+
+ /* Set the number of bytes to transfer this time */
+ nbytes_toxfer = buf_size;
+
+ /* Loop over the buffers to read */
+ while(nbytes_toxfer>0) {
+ /* Skip offset over blocks of other processes */
+ file_offset = posix_file_offset +
+ (off_t)(nbytes_xfer*pio_mpi_nprocs_g);
+
+ /* only care if seek returns error */
+ rc = POSIXSEEK(fd->posixfd, file_offset) < 0 ? -1 : 0;
+ VRFY((rc==0), "POSIXSEEK");
+
+ /* check if all bytes are read */
+ rc = ((ssize_t)blk_size ==
+ POSIXREAD(fd->posixfd, buf_p, blk_size));
+ VRFY((rc != 0), "POSIXREAD");
+
+ /* Advance location in buffer */
+ buf_p+=blk_size;
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=blk_size;
+
+ /* Decrement number of bytes left this time */
+ nbytes_toxfer-=blk_size;
+ } /* end while */
+ } /* end else */
+ } /* end if */
+ /* 2D dataspace */
+ else {
+ /* Contiguous storage */
+ if (!parms->h5_use_chunks) {
+ /* Contiguous access pattern */
+ if (!parms->interleaved) {
+ /* Compute file offset */
+ file_offset=posix_file_offset+(off_t)(((nbytes_xfer/blk_size)
+ /snbytes)*(blk_size*snbytes)+((nbytes_xfer/blk_size)%snbytes));
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = buf_size;
+
+ /* Global offset advance after each I/O operation */
+ file_offset_advance = (off_t)snbytes;
+ } /* end if */
+ /* Interleaved access pattern */
+ else {
+ /* Compute file offset */
+ file_offset=posix_file_offset+(off_t)((((nbytes_xfer/buf_size)
+ *pio_mpi_nprocs_g)/snbytes)*(buf_size*snbytes)
+ +((nbytes_xfer/buf_size)*pio_mpi_nprocs_g)%snbytes);
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = blk_size;
+
+ /* Global offset advance after each I/O operation */
+ file_offset_advance = (off_t)snbytes;
+ } /* end else */
+ } /* end if */
+ /* Chunked storage */
+ else {
+ /*Contiguous access pattern */
+ if (!parms->interleaved) {
+ /* Compute file offset */
+ file_offset=posix_file_offset+(off_t)nbytes_xfer;
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = blk_size * buf_size;
+
+ /* Global offset advance after each I/O operation */
+ file_offset_advance = 0;
+ } /* end if */
+ /*Interleaved access pattern */
+ else {
+ /* Compute file offset */
+ /* Before simplification */
+ /* file_offset=posix_file_offset+(off_t)((nbytes_xfer/(buf_size/blk_size)
+ *pio_mpi_nprocs_g)/(snbytes/blk_size*(blk_size*blk_size))*(buf_size/blk_size
+ *snbytes/blk_size*(blk_size*blk_size))+((nbytes_xfer/(buf_size/blk_size))
+ *pio_mpi_nprocs_g)%(snbytes/blk_size*(blk_size*blk_size))); */
+
+ file_offset=posix_file_offset+(off_t)(((nbytes_xfer/(buf_size/blk_size)
+ *pio_mpi_nprocs_g)/(snbytes*blk_size))*(buf_size*snbytes)+((nbytes_xfer/(buf_size/blk_size))
+ *pio_mpi_nprocs_g)%(snbytes*blk_size));
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = blk_size * blk_size;
+
+ /* Global offset advance after each I/O operation */
+ /* file_offset_advance = (off_t)(snbytes/blk_size*(blk_size*blk_size)); */
+ file_offset_advance = (off_t)(snbytes*blk_size);
+ } /* end else */
+ } /* end else */
+
+ /* Common code for file access */
+
+ /* Set the base of user's buffer */
+ buf_p = (unsigned char *)buffer;
+
+ /* Set the number of bytes to transfer this time */
+ nbytes_toxfer = buf_size*blk_size;
+
+ /* Loop over portions of the buffer to read */
+ while(nbytes_toxfer>0){
+ /* only care if seek returns error */
+ rc = POSIXSEEK(fd->posixfd, file_offset) < 0 ? -1 : 0;
+ VRFY((rc==0), "POSIXSEEK");
+
+ /* check if all bytes are read */
+ rc = ((ssize_t)nbytes_xfer_advance ==
+ POSIXREAD(fd->posixfd, buf_p, nbytes_xfer_advance));
+ VRFY((rc != 0), "POSIXREAD");
+
+ /* Advance location in buffer */
+ buf_p+=nbytes_xfer_advance;
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=nbytes_xfer_advance;
+
+ /* Decrement number of bytes left this time */
+ nbytes_toxfer-=nbytes_xfer_advance;
+
+ /* Partially advance file offset */
+ file_offset+=file_offset_advance;
+ } /* end while */
+
+ } /* end else */
+ break;
+
+ case MPIO:
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Independent file access */
+ if(!parms->collective) {
+ /* Contiguous pattern */
+ if (!parms->interleaved){
+ /* Compute offset in file */
+ mpi_offset = mpi_file_offset +
+ nbytes_xfer;
+
+ /* Perform independent read */
+ mrc = MPI_File_read_at(fd->mpifd, mpi_offset, buffer,
+ (int)(buf_size/blk_size), mpi_blk_type,
+ &mpi_status);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_READ");
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=buf_size;
+ } /* end if */
+ /* Interleaved access pattern */
+ else {
+ /* Set the base of user's buffer */
+ buf_p=(unsigned char *)buffer;
+
+ /* Set the number of bytes to transfer this time */
+ nbytes_toxfer = buf_size;
+
+ /* Loop over the buffers to read */
+ while(nbytes_toxfer>0) {
+ /* Skip offset over blocks of other processes */
+ mpi_offset = mpi_file_offset +
+ (nbytes_xfer*pio_mpi_nprocs_g);
+
+ /* Perform independent read */
+ mrc = MPI_File_read_at(fd->mpifd, mpi_offset, buf_p,
+ (int)1, mpi_blk_type, &mpi_status);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_READ");
+
+ /* Advance location in buffer */
+ buf_p+=blk_size;
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=blk_size;
+
+ /* Decrement number of bytes left this time */
+ nbytes_toxfer-=blk_size;
+ } /* end while */
+ } /* end else */
+ } /* end if */
+ /* Collective file access */
+ else {
+ /* Contiguous access pattern */
+ if (!parms->interleaved){
+ /* Compute offset in file */
+ mpi_offset = mpi_file_offset +
+ nbytes_xfer;
+
+ /* Perform collective read */
+ mrc = MPI_File_read_at_all(fd->mpifd, mpi_offset, buffer,
+ (int)(buf_size/blk_size), mpi_blk_type, &mpi_status);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_READ");
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=buf_size;
+ } /* end if */
+ /* Interleaved access pattern */
+ else {
+ /* Compute offset in file */
+ mpi_offset = mpi_file_offset +
+ (nbytes_xfer*pio_mpi_nprocs_g);
+
+ /* Set the file view */
+ mrc = MPI_File_set_view(fd->mpifd, mpi_offset, mpi_blk_type,
+ mpi_file_type, (char*)"native", h5_io_info_g);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_VIEW");
+
+ /* Perform collective read */
+ mrc = MPI_File_read_at_all(fd->mpifd, 0, buffer,
+ (int)(buf_size/blk_size), mpi_blk_type, &mpi_status);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_READ");
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=buf_size;
+ } /* end else */
+ } /* end else */
+ } /* end if */
+ /* 2D dataspace */
+ else {
+ /* Contiguous storage */
+ if (!parms->h5_use_chunks) {
+ /* Contiguous access pattern */
+ if (!parms->interleaved) {
+ /* Compute offset in file */
+ mpi_offset=mpi_file_offset+((nbytes_xfer/blk_size)/snbytes)*
+ (blk_size*snbytes)+((nbytes_xfer/blk_size)%snbytes);
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = buf_size;
+
+ /* Global offset advance after each I/O operation */
+ mpi_offset_advance = snbytes;
+
+ /* MPI type to be used for collective access */
+ mpi_collective_type = mpi_cont_type;
+ } /* end if */
+ /* Interleaved access pattern */
+ else {
+ /* Compute offset in file */
+ mpi_offset=mpi_file_offset+(((nbytes_xfer/buf_size)*pio_mpi_nprocs_g)/snbytes)*
+ (buf_size*snbytes)+((nbytes_xfer/buf_size)*pio_mpi_nprocs_g)%snbytes;
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = blk_size;
+
+ /* Global offset advance after each I/O operation */
+ mpi_offset_advance = snbytes;
+
+ /* MPI type to be used for collective access */
+ mpi_collective_type = mpi_inter_type;
+ } /* end else */
+ } /* end if */
+ /* Chunked storage */
+ else {
+ /*Contiguous access pattern */
+ if (!parms->interleaved) {
+ /* Compute offset in file */
+ mpi_offset=mpi_file_offset+nbytes_xfer;
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = blk_size * buf_size;
+
+ /* Global offset advance after each I/O operation */
+ mpi_offset_advance = 0;
+
+ /* MPI type to be used for collective access */
+ mpi_collective_type = mpi_full_buffer;
+ } /* end if */
+ /*Interleaved access pattern */
+ else {
+ /* Compute offset in file */
+ /* Before simplification */
+ /* mpi_offset=mpi_file_offset+(nbytes_xfer/(buf_size/blk_size)
+ *pio_mpi_nprocs_g)/(snbytes/blk_size*(blk_size*blk_size))*
+ (buf_size/blk_size*snbytes/blk_size*(blk_size*blk_size))+
+ ((nbytes_xfer/(buf_size/blk_size))*pio_mpi_nprocs_g)%(snbytes
+ /blk_size*(blk_size*blk_size)); */
+ mpi_offset=mpi_file_offset+((nbytes_xfer/(buf_size/blk_size)
+ *pio_mpi_nprocs_g)/(snbytes*blk_size))*(buf_size*snbytes)
+ +((nbytes_xfer/(buf_size/blk_size))*pio_mpi_nprocs_g)%(snbytes*blk_size);
+
+ /* Number of bytes to be transferred per I/O operation */
+ nbytes_xfer_advance = blk_size * blk_size;
+
+ /* Global offset advance after each I/O operation */
+ /* mpi_offset_advance = (MPI_Offset)(snbytes/blk_size*(blk_size*blk_size)); */
+ mpi_offset_advance = (MPI_Offset)(snbytes*blk_size);
+
+ /* MPI type to be used for collective access */
+ mpi_collective_type = mpi_chunk_inter_type;
+ } /* end else */
+ } /* end else */
+
+ /* Common code for independent file access */
+ if (!parms->collective) {
+ /* Set the base of user's buffer */
+ buf_p = (unsigned char *)buffer;
+
+ /* Set the number of bytes to transfer this time */
+ nbytes_toxfer = buf_size * blk_size;
+
+ /* Loop over portions of the buffer to read */
+ while(nbytes_toxfer>0){
+ /* Perform independent read */
+ mrc = MPI_File_read_at(fd->mpifd, mpi_offset, buf_p,
+ (int)nbytes_xfer_advance, MPI_BYTE, &mpi_status);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_READ");
+
+ /* Advance location in buffer */
+ buf_p+=nbytes_xfer_advance;
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=nbytes_xfer_advance;
+
+ /* Decrement number of bytes left this time */
+ nbytes_toxfer-=nbytes_xfer_advance;
+
+ /* Partially advance global offset in dataset */
+ mpi_offset+=mpi_offset_advance;
+ } /* end while */
+ } /* end if */
+
+ /* Common code for collective file access */
+ else {
+ /* Set the file view */
+ mrc = MPI_File_set_view(fd->mpifd, mpi_offset, MPI_BYTE,
+ mpi_collective_type, (char *)"native", h5_io_info_g);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_VIEW");
+
+ /* Perform read */
+ MPI_File_read_at_all(fd->mpifd, 0, buffer,(int)(buf_size*blk_size),
+ MPI_BYTE, &mpi_status);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_READ");
+
+ /* Advance global offset in dataset */
+ nbytes_xfer+=buf_size*blk_size;
+ } /* end else */
+
+ } /* end else */
+ break;
+
+ case PHDF5:
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Set up the file dset space id to move the selection to process */
+ if (!parms->interleaved){
+ /* Contiguous pattern */
+ h5offset[0] = nbytes_xfer;
+ } /* end if */
+ else {
+ /* Interleaved access pattern */
+ /* Skip offset over blocks of other processes */
+ h5offset[0] = (nbytes_xfer*pio_mpi_nprocs_g);
+ } /* end else */
+ hrc = H5Soffset_simple(h5dset_space_id, h5offset);
+ VRFY((hrc >= 0), "H5Soffset_simple");
+
+ /* Read the buffer in */
+ hrc = H5Dread(h5ds_id, ELMT_H5_TYPE, h5mem_space_id,
+ h5dset_space_id, h5dxpl, buffer);
+ VRFY((hrc >= 0), "H5Dread");
+
+ /* Increment number of bytes transferred */
+ nbytes_xfer += buf_size;
+ } /* end if */
+ /* 2D dataspace */
+ else {
+ /* Set up the file dset space id to move the selection to process */
+ if (!parms->interleaved){
+ /* Contiguous pattern */
+ h5offset[0] = (nbytes_xfer/(snbytes*blk_size))*blk_size;
+ h5offset[1] = (nbytes_xfer%(snbytes*blk_size))/blk_size;
+ } /* end if */
+ else {
+ /* Interleaved access pattern */
+ /* Skip offset over blocks of other processes */
+ h5offset[0] = ((nbytes_xfer*pio_mpi_nprocs_g)/(snbytes*buf_size))*buf_size;
+ h5offset[1] = ((nbytes_xfer*pio_mpi_nprocs_g)%(snbytes*buf_size))/buf_size;
+
+ } /* end else */
+ hrc = H5Soffset_simple(h5dset_space_id, h5offset);
+ VRFY((hrc >= 0), "H5Soffset_simple");
+
+ /* Write the buffer out */
+ hrc = H5Dread(h5ds_id, ELMT_H5_TYPE, h5mem_space_id,
+ h5dset_space_id, h5dxpl, buffer);
+ VRFY((hrc >= 0), "H5Dread");
+
+ /* Increment number of bytes transferred */
+ nbytes_xfer += buf_size*blk_size;
+
+ } /* end else */
+ break;
+ } /* switch (parms->io_type) */
+
+ /* Verify raw data, if asked */
+ if (parms->verify) {
+ /* Verify data read */
+ unsigned char *ucharptr = (unsigned char *)buffer;
+ size_t i;
+ int nerror=0;
+
+ for (i = 0; i < bsize; ++i){
+ if (*ucharptr++ != pio_mpi_rank_g+1) {
+ if (++nerror < 20){
+ /* report at most 20 errors */
+ HDprint_rank(output);
+ HDfprintf(output, "read data error, expected (%d), "
+ "got (%d)\n",
+ pio_mpi_rank_g+1,
+ (int)*(ucharptr-1));
+ } /* end if */
+ } /* end if */
+ } /* end for */
+ if (nerror >= 20) {
+ HDprint_rank(output);
+ HDfprintf(output, "...");
+ HDfprintf(output, "total read data errors=%d\n",
+ nerror);
+ } /* end if */
+ } /* if (parms->verify) */
+
+ } /* end while */
+
+ /* Stop "raw data" read timer */
+ set_time(res->timers, HDF5_RAW_READ_FIXED_DIMS, TSTOP);
+
+ /* Calculate read time */
+
+ /* Close dataset. Only HDF5 needs to do an explicit close. */
+ if (parms->io_type == PHDF5) {
+ hrc = H5Dclose(h5ds_id);
+
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Dataset Close failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ h5ds_id = -1;
+ } /* end if */
+ } /* end for */
+
+done:
+ /* release MPI-I/O objects */
+ if (parms->io_type == MPIO) {
+ /* 1D dataspace */
+ if (!parms->dim2d){
+ /* Free file type */
+ mrc = MPI_Type_free( &mpi_file_type );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free buffer type */
+ mrc = MPI_Type_free( &mpi_blk_type );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+ } /* end if */
+ /* 2D dataspace */
+ else {
+ /* Free partial buffer type for contiguous access */
+ mrc = MPI_Type_free( &mpi_partial_buffer_cont );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free contiguous file type */
+ mrc = MPI_Type_free( &mpi_cont_type );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free partial buffer type for interleaved access */
+ mrc = MPI_Type_free( &mpi_partial_buffer_inter );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free interleaved file type */
+ mrc = MPI_Type_free( &mpi_inter_type );
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free full buffer type */
+ mrc = MPI_Type_free(&mpi_full_buffer);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free full chunk type */
+ mrc = MPI_Type_free(&mpi_full_chunk);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+
+ /* Free chunk interleaved file type */
+ mrc = MPI_Type_free(&mpi_chunk_inter_type);
+ VRFY((mrc==MPI_SUCCESS), "MPIO_TYPE_FREE");
+ } /* end else */
+ } /* end if */
+
+ /* release HDF5 objects */
+ if (h5dset_space_id != -1) {
+ hrc = H5Sclose(h5dset_space_id);
+ if (hrc < 0){
+ fprintf(stderr, "HDF5 Dataset Space Close failed\n");
+ ret_code = FAIL;
+ } else {
+ h5dset_space_id = -1;
+ }
+ }
+
+ if (h5mem_space_id != -1) {
+ hrc = H5Sclose(h5mem_space_id);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Memory Space Close failed\n");
+ ret_code = FAIL;
+ } else {
+ h5mem_space_id = -1;
+ }
+ }
+
+ if (h5dxpl != -1) {
+ hrc = H5Pclose(h5dxpl);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Dataset Transfer Property List Close failed\n");
+ ret_code = FAIL;
+ } else {
+ h5dxpl = -1;
+ }
+ }
+
+ return ret_code;
+}
+
+/*
+ * Function: do_fopen
+ * Purpose: Open the specified file.
+ * Return: SUCCESS or FAIL
+ * Programmer: Albert Cheng, Bill Wendling, 2001/12/13
+ * Modifications:
+ */
+ static herr_t
+do_fopen(parameters *param, char *fname, file_descr *fd /*out*/, int flags)
+{
+ int ret_code = SUCCESS, mrc;
+ hid_t acc_tpl = -1; /* file access templates */
+
+ switch (param->io_type) {
+ case POSIXIO:
+ if (flags & (PIO_CREATE | PIO_WRITE))
+ fd->posixfd = POSIXCREATE(fname);
+ else
+ fd->posixfd = POSIXOPEN(fname, O_RDONLY);
+
+ if (fd->posixfd < 0 ) {
+ fprintf(stderr, "POSIX File Open failed(%s)\n", fname);
+ GOTOERROR(FAIL);
+ }
+
+
+ /* The perils of POSIX I/O in a parallel environment. The problem is:
+ *
+ * - Process n opens a file with truncation and then starts
+ * writing to the file.
+ * - Process m also opens the file with truncation, but after
+ * process n has already started to write to the file. Thus,
+ * all of the stuff process n wrote is now lost.
+ */
+ MPI_Barrier(pio_comm_g);
+
+ break;
+
+ case MPIO:
+ if (flags & (PIO_CREATE | PIO_WRITE)) {
+ MPI_File_delete(fname, h5_io_info_g);
+ mrc = MPI_File_open(pio_comm_g, fname, MPI_MODE_CREATE | MPI_MODE_RDWR,
+ h5_io_info_g, &fd->mpifd);
+
+ if (mrc != MPI_SUCCESS) {
+ fprintf(stderr, "MPI File Open failed(%s)\n", fname);
+ GOTOERROR(FAIL);
+ }
+
+ /*since MPI_File_open with MPI_MODE_CREATE does not truncate */
+ /*filesize , set size to 0 explicitedly. */
+ mrc = MPI_File_set_size(fd->mpifd, (MPI_Offset)0);
+ if (mrc != MPI_SUCCESS) {
+ fprintf(stderr, "MPI_File_set_size failed\n");
+ GOTOERROR(FAIL);
+ }
+ } else {
+ mrc = MPI_File_open(pio_comm_g, fname, MPI_MODE_RDONLY, h5_io_info_g, &fd->mpifd);
+ if (mrc != MPI_SUCCESS) {
+ fprintf(stderr, "MPI File Open failed(%s)\n", fname);
+ GOTOERROR(FAIL);
+ }
+ }
+
+ break;
+
+ case PHDF5:
+ if ((acc_tpl = H5Pcreate(H5P_FILE_ACCESS)) < 0) {
+ fprintf(stderr, "HDF5 Property List Create failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ /* Set the file driver to the MPI-IO driver */
+ if (H5Pset_fapl_mpio(acc_tpl, pio_comm_g, h5_io_info_g) < 0) {
+ fprintf(stderr, "HDF5 Property List Set failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ /* Set the alignment of objects in HDF5 file */
+ if (H5Pset_alignment(acc_tpl, param->h5_thresh, param->h5_align) < 0) {
+ fprintf(stderr, "HDF5 Property List Set failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ /* create the parallel file */
+ if (flags & (PIO_CREATE | PIO_WRITE))
+ fd->h5fd = H5Fcreate(fname, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl);
+ else
+ fd->h5fd = H5Fopen(fname, H5F_ACC_RDONLY, acc_tpl);
+ if (fd->h5fd < 0) {
+ fprintf(stderr, "HDF5 File Create failed(%s)\n", fname);
+ GOTOERROR(FAIL);
+ }
+
+ /* verifying the close of the acc_tpl */
+ if (H5Pclose(acc_tpl) < 0) {
+ fprintf(stderr, "HDF5 Property List Close failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ break;
+ }
+
+done:
+ return ret_code;
+}
+
+/*
+ * Function: do_fclose
+ * Purpose: Close the specified file descriptor.
+ * Return: SUCCESS or FAIL
+ * Programmer: Albert Cheng, Bill Wendling, 2001/12/13
+ * Modifications:
+ */
+ static herr_t
+do_fclose(iotype iot, file_descr *fd /*out*/)
+{
+ herr_t ret_code = SUCCESS, hrc;
+ int mrc = 0, rc = 0;
+
+ switch (iot) {
+ case POSIXIO:
+ rc = POSIXCLOSE(fd->posixfd);
+
+ if (rc != 0){
+ fprintf(stderr, "POSIX File Close failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ fd->posixfd = -1;
+ break;
+
+ case MPIO:
+ mrc = MPI_File_close(&fd->mpifd);
+
+ if (mrc != MPI_SUCCESS){
+ fprintf(stderr, "MPI File close failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ fd->mpifd = MPI_FILE_NULL;
+ break;
+
+ case PHDF5:
+ hrc = H5Fclose(fd->h5fd);
+
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 File Close failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ fd->h5fd = -1;
+ break;
+ }
+
+done:
+ return ret_code;
+}
+
+
+/*
+ * Function: do_fclose
+ * Purpose: Cleanup temporary file unless HDF5_NOCLEANUP is set.
+ * Only Proc 0 of the PIO communicator will do the cleanup.
+ * Other processes just return.
+ * Return: void
+ * Programmer: Albert Cheng 2001/12/12
+ * Modifications:
+ */
+ static void
+do_cleanupfile(iotype iot, char *fname)
+{
+ if (pio_mpi_rank_g != 0)
+ return;
+
+ if (clean_file_g == -1)
+ clean_file_g = (getenv("HDF5_NOCLEANUP")==NULL) ? 1 : 0;
+
+ if (clean_file_g){
+ switch (iot){
+ case POSIXIO:
+ remove(fname);
+ break;
+ case MPIO:
+ case PHDF5:
+ MPI_File_delete(fname, h5_io_info_g);
+ break;
+ }
+ }
+}
+
+#ifdef TIME_MPI
+/* instrument the MPI_File_wrirte_xxx and read_xxx calls to measure
+ * pure time spent in MPI_File code.
+ */
+int MPI_File_read_at(MPI_File fh, MPI_Offset offset, void *buf,
+ int count, MPI_Datatype datatype, MPI_Status *status)
+{
+ int err;
+ set_time(timer_g, HDF5_MPI_READ, TSTART);
+ err=PMPI_File_read_at(fh, offset, buf, count, datatype, status);
+ set_time(timer_g, HDF5_MPI_READ, TSTOP);
+ return err;
+}
+
+
+int MPI_File_read_at_all(MPI_File fh, MPI_Offset offset, void *buf,
+ int count, MPI_Datatype datatype, MPI_Status *status)
+{
+ int err;
+ set_time(timer_g, HDF5_MPI_READ, TSTART);
+ err=PMPI_File_read_at_all(fh, offset, buf, count, datatype, status);
+ set_time(timer_g, HDF5_MPI_READ, TSTOP);
+ return err;
+}
+
+int MPI_File_write_at(MPI_File fh, MPI_Offset offset, void *buf,
+ int count, MPI_Datatype datatype, MPI_Status *status)
+{
+ int err;
+ set_time(timer_g, HDF5_MPI_WRITE, TSTART);
+ err=PMPI_File_write_at(fh, offset, buf, count, datatype, status);
+ set_time(timer_g, HDF5_MPI_WRITE, TSTOP);
+ return err;
+}
+
+int MPI_File_write_at_all(MPI_File fh, MPI_Offset offset, void *buf,
+ int count, MPI_Datatype datatype, MPI_Status *status)
+{
+ int err;
+ set_time(timer_g, HDF5_MPI_WRITE, TSTART);
+ err=PMPI_File_write_at_all(fh, offset, buf, count, datatype, status);
+ set_time(timer_g, HDF5_MPI_WRITE, TSTOP);
+ return err;
+}
+
+#endif /* TIME_MPI */
+#endif /* H5_HAVE_PARALLEL */
+
+
+
+
+
diff --git a/tools/perform/pio_perf.c b/tools/perform/pio_perf.c
new file mode 100644
index 0000000..cf41cbe
--- /dev/null
+++ b/tools/perform/pio_perf.c
@@ -0,0 +1,1696 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Parallel HDF5 Performance Testing Code
+ * --------------------------------------
+ *
+ * Portable code to test performance on the different platforms we support.
+ * This is what the report should look like:
+ *
+ * nprocs = Max#Procs
+ * IO API = POSIXIO
+ * # Files = 1, # of dsets = 1000, Elements per dset = 37000
+ * Write Results = x MB/s
+ * Read Results = x MB/s
+ * # Files = 1, # of dsets = 3000, Elements per dset = 37000
+ * Write Results = x MB/s
+ * Read Results = x MB/s
+ *
+ * . . .
+ *
+ * IO API = MPIO
+ * # Files = 1, # of dsets = 1000, Elements per dset = 37000
+ * Write Results = x MB/s
+ * Read Results = x MB/s
+ * # Files = 1, # of dsets = 3000, Elements per dset = 37000
+ * Write Results = x MB/s
+ * Read Results = x MB/s
+ *
+ * . . .
+ *
+ * IO API = PHDF5
+ * # Files = 1, # of dsets = 1000, Elements per dset = 37000
+ * Write Results = x MB/s
+ * Read Results = x MB/s
+ * # Files = 1, # of dsets = 3000, Elements per dset = 37000
+ * Write Results = x MB/s
+ * Read Results = x MB/s
+ *
+ * . . .
+ *
+ * nprocs = Max#Procs / 2
+ *
+ * . . .
+ *
+ */
+
+/* system header files */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "hdf5.h"
+
+#ifdef H5_HAVE_PARALLEL
+
+/* library header files */
+#include <mpi.h>
+
+/* our header files */
+#include "pio_perf.h"
+
+/* useful macros */
+#define TAB_SPACE 4
+
+#define ONE_KB 1024
+#define ONE_MB (ONE_KB * ONE_KB)
+#define ONE_GB (ONE_MB * ONE_KB)
+
+#define PIO_POSIX 0x1
+#define PIO_MPI 0x2
+#define PIO_HDF5 0x4
+
+/* report 0.0 in case t is zero too */
+#define MB_PER_SEC(bytes,t) (((t)==0.0) ? 0.0 : ((((double)bytes) / ONE_MB) / (t)))
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* TRUE */
+#ifndef FALSE
+#define FALSE (!TRUE)
+#endif /* FALSE */
+
+/* global variables */
+FILE *output; /* output file */
+int comm_world_rank_g; /* my rank in MPI_COMM_RANK */
+int comm_world_nprocs_g;/* num. of processes of MPI_COMM_WORLD */
+MPI_Comm pio_comm_g; /* Communicator to run the PIO */
+int pio_mpi_rank_g; /* MPI rank of pio_comm_g */
+int pio_mpi_nprocs_g; /* Number of processes of pio_comm_g */
+int pio_debug_level = 0;/* The debug level:
+ * 0 - Off
+ * 1 - Minimal
+ * 2 - Some more
+ * 3 - Maximal
+ * 4 - Maximal & then some
+ */
+
+/* local variables */
+static const char *progname = "h5perf";
+
+/*
+ * Command-line options: The user can specify short or long-named
+ * parameters. The long-named ones can be partially spelled. When
+ * adding more, make sure that they don't clash with each other.
+ */
+#if 1
+static const char *s_opts = "a:A:B:cCd:D:e:F:ghi:Imno:p:P:stT:wx:X:";
+#else
+static const char *s_opts = "a:A:bB:cCd:D:e:F:ghi:Imno:p:P:stT:wx:X:";
+#endif /* 1 */
+static struct long_options l_opts[] = {
+ { "align", require_arg, 'a' },
+ { "alig", require_arg, 'a' },
+ { "ali", require_arg, 'a' },
+ { "al", require_arg, 'a' },
+ { "api", require_arg, 'A' },
+ { "ap", require_arg, 'A' },
+#if 0
+ /* a sighting of the elusive binary option */
+ { "binary", no_arg, 'b' },
+ { "binar", no_arg, 'b' },
+ { "bina", no_arg, 'b' },
+ { "bin", no_arg, 'b' },
+ { "bi", no_arg, 'b' },
+#endif /* 0 */
+ { "block-size", require_arg, 'B' },
+ { "block-siz", require_arg, 'B' },
+ { "block-si", require_arg, 'B' },
+ { "block-s", require_arg, 'B' },
+ { "block-", require_arg, 'B' },
+ { "block", require_arg, 'B' },
+ { "bloc", require_arg, 'B' },
+ { "blo", require_arg, 'B' },
+ { "bl", require_arg, 'B' },
+ { "chunk", no_arg, 'c' },
+ { "chun", no_arg, 'c' },
+ { "chu", no_arg, 'c' },
+ { "ch", no_arg, 'c' },
+ { "collective", no_arg, 'C' },
+ { "collectiv", no_arg, 'C' },
+ { "collecti", no_arg, 'C' },
+ { "collect", no_arg, 'C' },
+ { "collec", no_arg, 'C' },
+ { "colle", no_arg, 'C' },
+ { "coll", no_arg, 'C' },
+ { "col", no_arg, 'C' },
+ { "co", no_arg, 'C' },
+ { "debug", require_arg, 'D' },
+ { "debu", require_arg, 'D' },
+ { "deb", require_arg, 'D' },
+ { "de", require_arg, 'D' },
+ { "geometry", no_arg, 'g' },
+ { "geometr", no_arg, 'g' },
+ { "geomet", no_arg, 'g' },
+ { "geome", no_arg, 'g' },
+ { "geom", no_arg, 'g' },
+ { "geo", no_arg, 'g' },
+ { "ge", no_arg, 'g' },
+ { "help", no_arg, 'h' },
+ { "hel", no_arg, 'h' },
+ { "he", no_arg, 'h' },
+ { "interleaved", require_arg, 'I' },
+ { "interleave", require_arg, 'I' },
+ { "interleav", require_arg, 'I' },
+ { "interlea", require_arg, 'I' },
+ { "interle", require_arg, 'I' },
+ { "interl", require_arg, 'I' },
+ { "inter", require_arg, 'I' },
+ { "inte", require_arg, 'I' },
+ { "int", require_arg, 'I' },
+ { "in", require_arg, 'I' },
+ { "max-num-processes", require_arg, 'P' },
+ { "max-num-processe", require_arg, 'P' },
+ { "max-num-process", require_arg, 'P' },
+ { "max-num-proces", require_arg, 'P' },
+ { "max-num-proce", require_arg, 'P' },
+ { "max-num-proc", require_arg, 'P' },
+ { "max-num-pro", require_arg, 'P' },
+ { "max-num-pr", require_arg, 'P' },
+ { "max-num-p", require_arg, 'P' },
+ { "min-num-processes", require_arg, 'p' },
+ { "min-num-processe", require_arg, 'p' },
+ { "min-num-process", require_arg, 'p' },
+ { "min-num-proces", require_arg, 'p' },
+ { "min-num-proce", require_arg, 'p' },
+ { "min-num-proc", require_arg, 'p' },
+ { "min-num-pro", require_arg, 'p' },
+ { "min-num-pr", require_arg, 'p' },
+ { "min-num-p", require_arg, 'p' },
+ { "max-xfer-size", require_arg, 'X' },
+ { "max-xfer-siz", require_arg, 'X' },
+ { "max-xfer-si", require_arg, 'X' },
+ { "max-xfer-s", require_arg, 'X' },
+ { "max-xfer", require_arg, 'X' },
+ { "max-xfe", require_arg, 'X' },
+ { "max-xf", require_arg, 'X' },
+ { "max-x", require_arg, 'X' },
+ { "min-xfer-size", require_arg, 'x' },
+ { "min-xfer-siz", require_arg, 'x' },
+ { "min-xfer-si", require_arg, 'x' },
+ { "min-xfer-s", require_arg, 'x' },
+ { "min-xfer", require_arg, 'x' },
+ { "min-xfe", require_arg, 'x' },
+ { "min-xf", require_arg, 'x' },
+ { "min-x", require_arg, 'x' },
+ { "num-bytes", require_arg, 'e' },
+ { "num-byte", require_arg, 'e' },
+ { "num-byt", require_arg, 'e' },
+ { "num-by", require_arg, 'e' },
+ { "num-b", require_arg, 'e' },
+ { "num-dsets", require_arg, 'd' },
+ { "num-dset", require_arg, 'd' },
+ { "num-dse", require_arg, 'd' },
+ { "num-ds", require_arg, 'd' },
+ { "num-d", require_arg, 'd' },
+ { "num-files", require_arg, 'F' },
+ { "num-file", require_arg, 'F' },
+ { "num-fil", require_arg, 'F' },
+ { "num-fi", require_arg, 'F' },
+ { "num-f", require_arg, 'F' },
+ { "num-iterations", require_arg, 'i' },
+ { "num-iteration", require_arg, 'i' },
+ { "num-iteratio", require_arg, 'i' },
+ { "num-iterati", require_arg, 'i' },
+ { "num-iterat", require_arg, 'i' },
+ { "num-itera", require_arg, 'i' },
+ { "num-iter", require_arg, 'i' },
+ { "num-ite", require_arg, 'i' },
+ { "num-it", require_arg, 'i' },
+ { "num-i", require_arg, 'i' },
+ { "output", require_arg, 'o' },
+ { "outpu", require_arg, 'o' },
+ { "outp", require_arg, 'o' },
+ { "out", require_arg, 'o' },
+ { "ou", require_arg, 'o' },
+ { "threshold", require_arg, 'T' },
+ { "threshol", require_arg, 'T' },
+ { "thresho", require_arg, 'T' },
+ { "thresh", require_arg, 'T' },
+ { "thres", require_arg, 'T' },
+ { "thre", require_arg, 'T' },
+ { "thr", require_arg, 'T' },
+ { "th", require_arg, 'T' },
+ { "write-only", require_arg, 'w' },
+ { "write-onl", require_arg, 'w' },
+ { "write-on", require_arg, 'w' },
+ { "write-o", require_arg, 'w' },
+ { "write", require_arg, 'w' },
+ { "writ", require_arg, 'w' },
+ { "wri", require_arg, 'w' },
+ { "wr", require_arg, 'w' },
+ { NULL, 0, '\0' }
+};
+
+struct options {
+ long io_types; /* bitmask of which I/O types to test */
+ const char *output_file; /* file to print report to */
+ long num_dsets; /* number of datasets */
+ long num_files; /* number of files */
+ off_t num_bpp; /* number of bytes per proc per dset */
+ int num_iters; /* number of iterations */
+ int max_num_procs; /* maximum number of processes to use */
+ int min_num_procs; /* minimum number of processes to use */
+ size_t max_xfer_size; /* maximum transfer buffer size */
+ size_t min_xfer_size; /* minimum transfer buffer size */
+ size_t blk_size; /* Block size */
+ unsigned interleaved; /* Interleaved vs. contiguous blocks */
+ unsigned collective; /* Collective vs. independent I/O */
+ unsigned dim2d; /* 1D vs. 2D geometry */
+ int print_times; /* print times as well as throughputs */
+ int print_raw; /* print raw data throughput info */
+ off_t h5_alignment; /* alignment in HDF5 file */
+ off_t h5_threshold; /* threshold for alignment in HDF5 file */
+ int h5_use_chunks; /* Make HDF5 dataset chunked */
+ int h5_write_only; /* Perform the write tests only */
+ int verify; /* Verify data correctness */
+};
+
+typedef struct _minmax {
+ double min;
+ double max;
+ double sum;
+ int num;
+} minmax;
+
+/* local functions */
+static off_t parse_size_directive(const char *size);
+static struct options *parse_command_line(int argc, char *argv[]);
+static void run_test_loop(struct options *options);
+static int run_test(iotype iot, parameters parms, struct options *opts);
+static void output_all_info(minmax *mm, int count, int indent_level);
+static void get_minmax(minmax *mm, double val);
+static minmax accumulate_minmax_stuff(minmax *mm, int count);
+static int create_comm_world(int num_procs, int *doing_pio);
+static int destroy_comm_world(void);
+static void output_results(const struct options *options, const char *name,
+ minmax *table, int table_size, off_t data_size);
+static void output_times(const struct options *options, const char *name,
+ minmax *table, int table_size);
+static void output_report(const char *fmt, ...);
+static void print_indent(register int indent);
+static void usage(const char *prog);
+static void report_parameters(struct options *opts);
+
+/*
+ * Function: main
+ * Purpose: Start things up. Initialize MPI and then call the test looping
+ * function.
+ * Return: EXIT_SUCCESS or EXIT_FAILURE
+ * Programmer: Bill Wendling, 30. October 2001
+ * Modifications:
+ */
+int
+main(int argc, char **argv)
+{
+ int ret;
+ int exit_value = EXIT_SUCCESS;
+ struct options *opts = NULL;
+
+#ifndef STANDALONE
+ /* Initialize h5tools lib */
+ h5tools_init();
+#endif
+
+ output = stdout;
+
+ /* initialize MPI and get the maximum num of processors we started with */
+ MPI_Init(&argc, &argv);
+ ret = MPI_Comm_size(MPI_COMM_WORLD, &comm_world_nprocs_g);
+
+ if (ret != MPI_SUCCESS) {
+ fprintf(stderr, "%s: MPI_Comm_size call failed\n", progname);
+
+ if (ret == MPI_ERR_COMM)
+ fprintf(stderr, "invalid MPI communicator\n");
+ else
+ fprintf(stderr, "invalid argument\n");
+
+ exit_value = EXIT_FAILURE;
+ goto finish;
+ }
+
+ ret = MPI_Comm_rank(MPI_COMM_WORLD, &comm_world_rank_g);
+
+ if (ret != MPI_SUCCESS) {
+ fprintf(stderr, "%s: MPI_Comm_rank call failed\n", progname);
+
+ if (ret == MPI_ERR_COMM)
+ fprintf(stderr, "invalid MPI communicator\n");
+ else
+ fprintf(stderr, "invalid argument\n");
+
+ exit_value = EXIT_FAILURE;
+ goto finish;
+ }
+
+ pio_comm_g = MPI_COMM_WORLD;
+
+ h5_set_info_object();
+ opts = parse_command_line(argc, argv);
+
+ if (!opts) {
+ exit_value = EXIT_FAILURE;
+ goto finish;
+ }
+
+ if (opts->output_file) {
+ if ((output = fopen(opts->output_file, "w")) == NULL) {
+ fprintf(stderr, "%s: cannot open output file\n", progname);
+ perror(opts->output_file);
+ goto finish;
+ }
+ }
+
+ if ((pio_debug_level == 0 && comm_world_rank_g == 0) || pio_debug_level > 0)
+ report_parameters(opts);
+
+ run_test_loop(opts);
+
+finish:
+ MPI_Finalize();
+ free(opts);
+ return exit_value;
+}
+
+/*
+ * Function: run_test_loop
+ * Purpose: Run the I/O tests. Write the results to OUTPUT.
+ *
+ * - The slowest changing part of the test is the number of
+ * processors to use. For each loop iteration, we divide that
+ * number by 2 and rerun the test.
+ *
+ * - The second slowest is what type of IO API to perform. We have
+ * three choices: POSIXIO, MPI-IO, and PHDF5.
+ *
+ * - Then we change the size of the buffer. This information is
+ * inferred from the number of datasets to create and the number
+ * of integers to put into each dataset. The backend code figures
+ * this out.
+ *
+ * Return: Nothing
+ * Programmer: Bill Wendling, 30. October 2001
+ * Modifications:
+ * Added 2D testing (Christian Chilan, 10. August 2005)
+ */
+static void
+run_test_loop(struct options *opts)
+{
+ parameters parms;
+ int num_procs;
+ int doing_pio; /* if this process is doing PIO */
+
+ parms.num_files = opts->num_files;
+ parms.num_dsets = opts->num_dsets;
+ parms.num_iters = opts->num_iters;
+ parms.blk_size = opts->blk_size;
+ parms.interleaved = opts->interleaved;
+ parms.collective = opts->collective;
+ parms.dim2d = opts->dim2d;
+ parms.h5_align = opts->h5_alignment;
+ parms.h5_thresh = opts->h5_threshold;
+ parms.h5_use_chunks = opts->h5_use_chunks;
+ parms.h5_write_only = opts->h5_write_only;
+ parms.verify = opts->verify;
+
+ /* start with max_num_procs and decrement it by half for each loop. */
+ /* if performance needs restart, fewer processes may be needed. */
+ for (num_procs = opts->max_num_procs;
+ num_procs >= opts->min_num_procs; num_procs >>= 1) {
+ register size_t buf_size;
+
+ parms.num_procs = num_procs;
+
+ if (create_comm_world(parms.num_procs, &doing_pio) != SUCCESS) {
+ /* do something harsh */
+ }
+
+ /* only processes doing PIO will run the tests */
+ if (doing_pio){
+ output_report("Number of processors = %ld\n", parms.num_procs);
+
+ /* multiply the xfer buffer size by 2 for each loop iteration */
+ for (buf_size = opts->min_xfer_size;
+ buf_size <= opts->max_xfer_size; buf_size <<= 1) {
+ parms.buf_size = buf_size;
+
+ if (parms.dim2d){
+ parms.num_bytes = (off_t)pow((double)(opts->num_bpp*parms.num_procs),2);
+ if (parms.interleaved)
+ output_report("Transfer Buffer Size: %ldx%ld bytes, File size: %.2f MBs\n",
+ buf_size, opts->blk_size,
+ ((double)parms.num_dsets * (double)parms.num_bytes)
+ / ONE_MB);
+ else
+ output_report("Transfer Buffer Size: %ldx%ld bytes, File size: %.2f MBs\n",
+ opts->blk_size, buf_size,
+ ((double)parms.num_dsets * (double)parms.num_bytes)
+ / ONE_MB);
+
+ print_indent(1);
+ output_report(" # of files: %ld, # of datasets: %ld, dataset size: %.2fx%.2f KBs\n",
+ parms.num_files, parms.num_dsets, (double)(opts->num_bpp*parms.num_procs)/ONE_KB,
+ (double)(opts->num_bpp*parms.num_procs)/ONE_KB);
+ }
+ else{
+ parms.num_bytes = (off_t)opts->num_bpp*parms.num_procs;
+ output_report("Transfer Buffer Size: %ld bytes, File size: %.2f MBs\n",
+ buf_size,((double)parms.num_dsets * (double)parms.num_bytes) / ONE_MB);
+
+ print_indent(1);
+ output_report(" # of files: %ld, # of datasets: %ld, dataset size: %.2f MBs\n",
+ parms.num_files, parms.num_dsets, (double)(opts->num_bpp*parms.num_procs)/ONE_MB);
+ }
+
+ if (opts->io_types & PIO_POSIX)
+ run_test(POSIXIO, parms, opts);
+
+ if (opts->io_types & PIO_MPI)
+ run_test(MPIO, parms, opts);
+
+ if (opts->io_types & PIO_HDF5)
+ run_test(PHDF5, parms, opts);
+
+ /* Run the tests once if buf_size==0, but then break out */
+ if(buf_size==0)
+ break;
+ }
+
+ if (destroy_comm_world() != SUCCESS) {
+ /* do something harsh */
+ }
+ }
+ }
+}
+
+/*
+ * Function: run_test
+ * Purpose: Inner loop call to actually run the I/O test.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 18. December 2001
+ * Modifications:
+ */
+static int
+run_test(iotype iot, parameters parms, struct options *opts)
+{
+ results res;
+ register int i, ret_value = SUCCESS;
+ int comm_size;
+ off_t raw_size;
+ minmax *write_mpi_mm_table=NULL;
+ minmax *write_mm_table=NULL;
+ minmax *write_gross_mm_table=NULL;
+ minmax *write_raw_mm_table=NULL;
+ minmax *read_mpi_mm_table=NULL;
+ minmax *read_mm_table=NULL;
+ minmax *read_gross_mm_table=NULL;
+ minmax *read_raw_mm_table=NULL;
+ minmax *read_open_mm_table=NULL;
+ minmax *read_close_mm_table=NULL;
+ minmax *write_open_mm_table=NULL;
+ minmax *write_close_mm_table=NULL;
+ minmax write_mpi_mm = {0.0, 0.0, 0.0, 0};
+ minmax write_mm = {0.0, 0.0, 0.0, 0};
+ minmax write_gross_mm = {0.0, 0.0, 0.0, 0};
+ minmax write_raw_mm = {0.0, 0.0, 0.0, 0};
+ minmax read_mpi_mm = {0.0, 0.0, 0.0, 0};
+ minmax read_mm = {0.0, 0.0, 0.0, 0};
+ minmax read_gross_mm = {0.0, 0.0, 0.0, 0};
+ minmax read_raw_mm = {0.0, 0.0, 0.0, 0};
+ minmax read_open_mm = {0.0, 0.0, 0.0, 0};
+ minmax read_close_mm = {0.0, 0.0, 0.0, 0};
+ minmax write_open_mm = {0.0, 0.0, 0.0, 0};
+ minmax write_close_mm = {0.0, 0.0, 0.0, 0};
+
+ raw_size = parms.num_files * (off_t)parms.num_dsets * (off_t)parms.num_bytes;
+ parms.io_type = iot;
+ print_indent(2);
+ output_report("IO API = ");
+
+ switch (iot) {
+ case POSIXIO:
+ output_report("POSIX\n");
+ break;
+ case MPIO:
+ output_report("MPIO\n");
+ break;
+ case PHDF5:
+ output_report("PHDF5 (w/MPI-IO driver)\n");
+ break;
+ }
+
+ MPI_Comm_size(pio_comm_g, &comm_size);
+
+ /* allocate space for tables minmax and that it is sufficient */
+ /* to initialize all elements to zeros by calloc. */
+ write_mpi_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ write_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ write_gross_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ write_raw_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ write_open_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ write_close_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ if (!parms.h5_write_only) {
+ read_mpi_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ read_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ read_gross_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ read_raw_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ read_open_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ read_close_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ }
+
+ /* Do IO iteration times, collecting statistics each time */
+ for (i = 0; i < parms.num_iters; ++i) {
+ double t;
+
+ MPI_Barrier(pio_comm_g);
+ res = do_pio(parms);
+
+ /* gather all of the "mpi write" times */
+ t = get_time(res.timers, HDF5_MPI_WRITE);
+ get_minmax(&write_mpi_mm, t);
+
+ write_mpi_mm_table[i] = write_mpi_mm;
+
+ /* gather all of the "write" times */
+ t = get_time(res.timers, HDF5_FINE_WRITE_FIXED_DIMS);
+ get_minmax(&write_mm, t);
+
+ write_mm_table[i] = write_mm;
+
+ /* gather all of the "write" times from open to close */
+ t = get_time(res.timers, HDF5_GROSS_WRITE_FIXED_DIMS);
+ get_minmax(&write_gross_mm, t);
+
+ write_gross_mm_table[i] = write_gross_mm;
+
+ /* gather all of the raw "write" times */
+ t = get_time(res.timers, HDF5_RAW_WRITE_FIXED_DIMS);
+ get_minmax(&write_raw_mm, t);
+
+ write_raw_mm_table[i] = write_raw_mm;
+
+ /* gather all of the file open times (time from open to first write) */
+ t = get_time(res.timers, HDF5_FILE_WRITE_OPEN);
+ get_minmax(&write_open_mm, t);
+
+ write_open_mm_table[i] = write_open_mm;
+
+ /* gather all of the file close times (time from last write to close) */
+ t = get_time(res.timers, HDF5_FILE_WRITE_CLOSE);
+ get_minmax(&write_close_mm, t);
+
+ write_close_mm_table[i] = write_close_mm;
+
+ if (!parms.h5_write_only) {
+ /* gather all of the "mpi read" times */
+ t = get_time(res.timers, HDF5_MPI_READ);
+ get_minmax(&read_mpi_mm, t);
+
+ read_mpi_mm_table[i] = read_mpi_mm;
+
+ /* gather all of the "read" times */
+ t = get_time(res.timers, HDF5_FINE_READ_FIXED_DIMS);
+ get_minmax(&read_mm, t);
+
+ read_mm_table[i] = read_mm;
+
+ /* gather all of the "read" times from open to close */
+ t = get_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS);
+ get_minmax(&read_gross_mm, t);
+
+ read_gross_mm_table[i] = read_gross_mm;
+
+ /* gather all of the raw "read" times */
+ t = get_time(res.timers, HDF5_RAW_READ_FIXED_DIMS);
+ get_minmax(&read_raw_mm, t);
+
+ read_raw_mm_table[i] = read_raw_mm;
+
+ /* gather all of the file open times (time from open to first read) */
+ t = get_time(res.timers, HDF5_FILE_READ_OPEN);
+ get_minmax(&read_open_mm, t);
+
+ read_open_mm_table[i] = read_open_mm;
+
+ /* gather all of the file close times (time from last read to close) */
+ t = get_time(res.timers, HDF5_FILE_READ_CLOSE);
+ get_minmax(&read_close_mm, t);
+
+ read_close_mm_table[i] = read_close_mm;
+
+ }
+
+ pio_time_destroy(res.timers);
+ }
+
+ /*
+ * Show various statistics
+ */
+ /* Write statistics */
+ /* Print the raw data throughput if desired */
+ if (opts->print_raw) {
+ /* accumulate and output the max, min, and average "raw write" times */
+ if (pio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Raw Data Write details:\n");
+ output_all_info(write_raw_mm_table, parms.num_iters, 4);
+ }
+
+ output_results(opts,"Raw Data Write",write_raw_mm_table,parms.num_iters,raw_size);
+ } /* end if */
+
+ /* show mpi write statics */
+ if (pio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("MPI Write details:\n");
+ output_all_info(write_mpi_mm_table, parms.num_iters, 4);
+ }
+
+ /* We don't currently output the MPI write results */
+
+ /* accumulate and output the max, min, and average "write" times */
+ if (pio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Write details:\n");
+ output_all_info(write_mm_table, parms.num_iters, 4);
+ }
+
+ output_results(opts,"Write",write_mm_table,parms.num_iters,raw_size);
+
+ /* accumulate and output the max, min, and average "gross write" times */
+ if (pio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Write Open-Close details:\n");
+ output_all_info(write_gross_mm_table, parms.num_iters, 4);
+ }
+
+ output_results(opts,"Write Open-Close",write_gross_mm_table,parms.num_iters,raw_size);
+
+ if (opts->print_times) {
+ output_times(opts,"Write File Open",write_open_mm_table,parms.num_iters);
+ output_times(opts,"Write File Close",write_close_mm_table,parms.num_iters);
+ }
+
+ /* Print out time from open to first write */
+ if (pio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Write file open details:\n");
+ output_all_info(write_open_mm_table, parms.num_iters, 4);
+ }
+
+ /* Print out time from last write to close */
+ if (pio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Write file close details:\n");
+ output_all_info(write_close_mm_table, parms.num_iters, 4);
+ }
+
+ if (!parms.h5_write_only) {
+ /* Read statistics */
+ /* Print the raw data throughput if desired */
+ if (opts->print_raw) {
+ /* accumulate and output the max, min, and average "raw read" times */
+ if (pio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Raw Data Read details:\n");
+ output_all_info(read_raw_mm_table, parms.num_iters, 4);
+ }
+
+ output_results(opts, "Raw Data Read", read_raw_mm_table,
+ parms.num_iters, raw_size);
+ } /* end if */
+
+ /* show mpi read statics */
+ if (pio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("MPI Read details:\n");
+ output_all_info(read_mpi_mm_table, parms.num_iters, 4);
+ }
+
+ /* We don't currently output the MPI read results */
+
+ /* accumulate and output the max, min, and average "read" times */
+ if (pio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Read details:\n");
+ output_all_info(read_mm_table, parms.num_iters, 4);
+ }
+
+ output_results(opts, "Read", read_mm_table, parms.num_iters, raw_size);
+
+ /* accumulate and output the max, min, and average "gross read" times */
+ if (pio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Read Open-Close details:\n");
+ output_all_info(read_gross_mm_table, parms.num_iters, 4);
+ }
+
+ output_results(opts, "Read Open-Close", read_gross_mm_table,parms.num_iters, raw_size);
+
+ if (opts->print_times) {
+ output_times(opts,"Read File Open",read_open_mm_table,parms.num_iters);
+ output_times(opts,"Read File Close",read_close_mm_table,parms.num_iters);
+ }
+
+ /* Print out time from open to first read */
+ if (pio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Read file open details:\n");
+ output_all_info(read_open_mm_table, parms.num_iters, 4);
+ }
+
+ /* Print out time from last read to close */
+ if (pio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Read file close details:\n");
+ output_all_info(read_close_mm_table, parms.num_iters, 4);
+ }
+
+ }
+
+ /* clean up our mess */
+ free(write_mpi_mm_table);
+ free(write_mm_table);
+ free(write_gross_mm_table);
+ free(write_raw_mm_table);
+ free(write_open_mm_table);
+ free(write_close_mm_table);
+
+ if (!parms.h5_write_only) {
+ free(read_mpi_mm_table);
+ free(read_mm_table);
+ free(read_gross_mm_table);
+ free(read_raw_mm_table);
+ free(read_open_mm_table);
+ free(read_close_mm_table);
+ }
+
+ return ret_value;
+}
+
+/*
+ * Function: output_all_info
+ * Purpose:
+ * Return: Nothing
+ * Programmer: Bill Wendling, 29. January 2002
+ * Modifications:
+ */
+static void
+output_all_info(minmax *mm, int count, int indent_level)
+{
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ print_indent(indent_level);
+ output_report("Iteration %d:\n", i + 1);
+ print_indent(indent_level + 1);
+ output_report("Minimum Time: %.2fs\n", mm[i].min);
+ print_indent(indent_level + 1);
+ output_report("Maximum Time: %.2fs\n", mm[i].max);
+ }
+}
+
+/*
+ * Function: get_minmax
+ * Purpose: Gather all the min, max and total of val.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 21. December 2001
+ * Modifications:
+ * Use MPI_Allreduce to do it. -akc, 2002/01/11
+ */
+static void
+get_minmax(minmax *mm, double val)
+{
+ int myrank;
+
+ MPI_Comm_rank(pio_comm_g, &myrank);
+ MPI_Comm_size(pio_comm_g, &mm->num);
+
+ MPI_Allreduce(&val, &mm->max, 1, MPI_DOUBLE, MPI_MAX, pio_comm_g);
+ MPI_Allreduce(&val, &mm->min, 1, MPI_DOUBLE, MPI_MIN, pio_comm_g);
+ MPI_Allreduce(&val, &mm->sum, 1, MPI_DOUBLE, MPI_SUM, pio_comm_g);
+}
+
+/*
+ * Function: accumulate_minmax_stuff
+ * Purpose: Accumulate the minimum, maximum, and average of the times
+ * across all processes.
+ * Return: TOTAL_MM - the total of all of these.
+ * Programmer: Bill Wendling, 21. December 2001
+ * Modifications:
+ * Changed to use seconds instead of MB/s - QAK, 5/9/02
+ */
+static minmax
+accumulate_minmax_stuff(minmax *mm, int count)
+{
+ int i;
+ minmax total_mm;
+
+ total_mm.sum = 0.0;
+ total_mm.max = -DBL_MAX;
+ total_mm.min = DBL_MAX;
+ total_mm.num = count;
+
+ for (i = 0; i < count; ++i) {
+ double m = mm[i].max;
+
+ total_mm.sum += m;
+
+ if (m < total_mm.min)
+ total_mm.min = m;
+
+ if (m > total_mm.max)
+ total_mm.max = m;
+ }
+
+ return total_mm;
+}
+
+/*
+ * Function: create_comm_world
+ * Purpose: Create an MPI Comm world and store it in pio_comm_g, which
+ * is a global variable.
+ * Return: SUCCESS on success.
+ * FAIL otherwise.
+ * Programmer: Bill Wendling, 19. December 2001
+ * Modifications:
+ */
+static int
+create_comm_world(int num_procs, int *doing_pio)
+{
+ /* MPI variables */
+ int mrc; /* return values */
+ int color; /* for communicator creation */
+ int myrank, nprocs;
+
+ pio_comm_g = MPI_COMM_NULL;
+
+ /*
+ * Create a sub communicator for this PIO run. Easier to use the first N
+ * processes.
+ */
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+
+ if (num_procs > nprocs) {
+ fprintf(stderr,
+ "number of process(%d) must be <= number of processes in MPI_COMM_WORLD(%d)\n",
+ num_procs, nprocs);
+ goto error_done;
+ }
+
+ MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
+ color = (myrank < num_procs);
+ mrc = MPI_Comm_split(MPI_COMM_WORLD, color, myrank, &pio_comm_g);
+
+ if (mrc != MPI_SUCCESS) {
+ fprintf(stderr, "MPI_Comm_split failed\n");
+ goto error_done;
+ }
+
+ if (!color) {
+ /* not involved in this run */
+ mrc = destroy_comm_world();
+ goto done;
+ }
+
+ /* determine the MPI rank in the PIO communicator */
+ MPI_Comm_size(pio_comm_g, &pio_mpi_nprocs_g);
+ MPI_Comm_rank(pio_comm_g, &pio_mpi_rank_g);
+
+done:
+ *doing_pio = color;
+ return SUCCESS;
+
+error_done:
+ destroy_comm_world();
+ return FAIL;
+}
+
+/*
+ * Function: destroy_comm_world
+ * Purpose: Destroy the created MPI Comm world which is stored in the
+ * pio_comm_g global variable.
+ * Return: SUCCESS on success.
+ * FAIL otherwise.
+ * Programmer: Bill Wendling, 19. December 2001
+ * Modifications:
+ */
+static int
+destroy_comm_world(void)
+{
+ int mrc = SUCCESS; /* return code */
+
+ /* release MPI resources */
+ if (pio_comm_g != MPI_COMM_NULL)
+ mrc = (MPI_Comm_free(&pio_comm_g) == MPI_SUCCESS ? SUCCESS : FAIL);
+
+ return mrc;
+}
+
+/*
+ * Function: output_results
+ * Purpose: Print information about the time & bandwidth for a given
+ * minmax & # of iterations.
+ * Return: Nothing
+ * Programmer: Quincey Koziol, 9. May 2002
+ * Modifications:
+ */
+static void
+output_results(const struct options *opts, const char *name, minmax *table,
+ int table_size,off_t data_size)
+{
+ minmax total_mm;
+
+ total_mm = accumulate_minmax_stuff(table, table_size);
+
+ print_indent(3);
+ output_report("%s (%d iteration(s)):\n", name,table_size);
+
+ /* Note: The maximum throughput uses the minimum amount of time & vice versa */
+
+ print_indent(4);
+ output_report("Maximum Throughput: %6.2f MB/s", MB_PER_SEC(data_size,total_mm.min));
+ if(opts->print_times)
+ output_report(" (%7.3f s)\n", total_mm.min);
+ else
+ output_report("\n");
+
+ print_indent(4);
+ output_report("Average Throughput: %6.2f MB/s",
+ MB_PER_SEC(data_size,total_mm.sum / total_mm.num));
+ if(opts->print_times)
+ output_report(" (%7.3f s)\n", (total_mm.sum / total_mm.num));
+ else
+ output_report("\n");
+
+ print_indent(4);
+ output_report("Minimum Throughput: %6.2f MB/s", MB_PER_SEC(data_size,total_mm.max));
+ if(opts->print_times)
+ output_report(" (%7.3f s)\n", total_mm.max);
+ else
+ output_report("\n");
+
+}
+
+static void
+output_times(const struct options *opts, const char *name, minmax *table,
+ int table_size)
+{
+ minmax total_mm;
+
+ total_mm = accumulate_minmax_stuff(table, table_size);
+
+ print_indent(3);
+ output_report("%s (%d iteration(s)):\n", name,table_size);
+
+ /* Note: The maximum throughput uses the minimum amount of time & vice versa */
+
+ print_indent(4);
+ output_report("Minimum Accumulated Time using %d file(s): %7.5f s\n", opts->num_files,(total_mm.min));
+
+ print_indent(4);
+ output_report("Average Accumulated Time using %d file(s): %7.5f s\n", opts->num_files,(total_mm.sum / total_mm.num));
+
+ print_indent(4);
+ output_report("Maximum Accumulated Time using %d file(s): %7.5f s\n", opts->num_files,(total_mm.max));
+}
+
+/*
+ * Function: output_report
+ * Purpose: Print a line of the report. Only do so if I'm the 0 process.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 19. December 2001
+ * Modifications:
+ */
+static void
+output_report(const char *fmt, ...)
+{
+ int myrank;
+
+ MPI_Comm_rank(pio_comm_g, &myrank);
+
+ if (myrank == 0) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(output, fmt, ap);
+ va_end(ap);
+ }
+}
+
+/*
+ * Function: print_indent
+ * Purpose: Print spaces to indent a new line of text for pretty printing
+ * things.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 29. October 2001
+ * Modifications:
+ */
+static void
+print_indent(register int indent)
+{
+ int myrank;
+
+ MPI_Comm_rank(pio_comm_g, &myrank);
+
+ if (myrank == 0) {
+ indent *= TAB_SPACE;
+
+ for (; indent > 0; --indent)
+ fputc(' ', output);
+ }
+}
+
+static void
+recover_size_and_print(long long val, const char *end)
+{
+ if (val >= ONE_KB && (val % ONE_KB) == 0) {
+ if (val >= ONE_MB && (val % ONE_MB) == 0) {
+ if (val >= ONE_GB && (val % ONE_GB) == 0)
+ HDfprintf(output, "%" H5_PRINTF_LL_WIDTH "d""GB%s", val / ONE_GB, end);
+ else
+ HDfprintf(output, "%" H5_PRINTF_LL_WIDTH "d""MB%s", val / ONE_MB, end);
+ } else {
+ HDfprintf(output, "%" H5_PRINTF_LL_WIDTH "d""KB%s", val / ONE_KB, end);
+ }
+ } else {
+ HDfprintf(output, "%" H5_PRINTF_LL_WIDTH "d""%s", val, end);
+ }
+}
+
+static void
+print_io_api(long io_types)
+{
+ if (io_types & PIO_POSIX)
+ HDfprintf(output, "posix ");
+ if (io_types & PIO_MPI)
+ HDfprintf(output, "mpiio ");
+ if (io_types & PIO_HDF5)
+ HDfprintf(output, "phdf5 ");
+ HDfprintf(output, "\n");
+}
+
+static void
+report_parameters(struct options *opts)
+{
+ int rank = comm_world_rank_g;
+
+ print_version("HDF5 Library"); /* print library version */
+ HDfprintf(output, "rank %d: ==== Parameters ====\n", rank);
+
+ HDfprintf(output, "rank %d: IO API=", rank);
+ print_io_api(opts->io_types);
+
+ HDfprintf(output, "rank %d: Number of files=%ld\n", rank,
+ opts->num_files);
+ HDfprintf(output, "rank %d: Number of datasets=%ld\n", rank,
+ opts->num_dsets);
+ HDfprintf(output, "rank %d: Number of iterations=%d\n", rank,
+ opts->num_iters);
+ HDfprintf(output, "rank %d: Number of processes=%d:%d\n", rank,
+ opts->min_num_procs, opts->max_num_procs);
+
+ if (opts->dim2d){
+ HDfprintf(output, "rank %d: Number of bytes per process per dataset=", rank);
+ recover_size_and_print((long long)(opts->num_bpp * opts->num_bpp * opts->min_num_procs), ":");
+ recover_size_and_print((long long)(opts->num_bpp * opts->num_bpp * opts->max_num_procs), "\n");
+
+ HDfprintf(output, "rank %d: Size of dataset(s)=", rank);
+ recover_size_and_print((long long)(opts->num_bpp * opts->min_num_procs), "x");
+ recover_size_and_print((long long)(opts->num_bpp * opts->min_num_procs), ":");
+ recover_size_and_print((long long)(opts->num_bpp * opts->max_num_procs), "x");
+ recover_size_and_print((long long)(opts->num_bpp * opts->max_num_procs), "\n");
+
+ HDfprintf(output, "rank %d: File size=", rank);
+ recover_size_and_print((long long)(pow(opts->num_bpp * opts->min_num_procs,2)
+ * opts->num_dsets), ":");
+ recover_size_and_print((long long)(pow(opts->num_bpp * opts->max_num_procs,2)
+ * opts->num_dsets), "\n");
+
+ HDfprintf(output, "rank %d: Transfer buffer size=", rank);
+ if(opts->interleaved){
+ recover_size_and_print((long long)opts->min_xfer_size, "x");
+ recover_size_and_print((long long)opts->blk_size, ":");
+ recover_size_and_print((long long)opts->max_xfer_size, "x");
+ recover_size_and_print((long long)opts->blk_size, "\n");
+ }
+ else{
+ recover_size_and_print((long long)opts->blk_size, "x");
+ recover_size_and_print((long long)opts->min_xfer_size, ":");
+ recover_size_and_print((long long)opts->blk_size, "x");
+ recover_size_and_print((long long)opts->max_xfer_size, "\n");
+ }
+ HDfprintf(output, "rank %d: Block size=", rank);
+ recover_size_and_print((long long)opts->blk_size, "x");
+ recover_size_and_print((long long)opts->blk_size, "\n");
+ }
+ else{
+ HDfprintf(output, "rank %d: Number of bytes per process per dataset=", rank);
+ recover_size_and_print((long long)opts->num_bpp, "\n");
+
+ HDfprintf(output, "rank %d: Size of dataset(s)=", rank);
+ recover_size_and_print((long long)(opts->num_bpp * opts->min_num_procs), ":");
+ recover_size_and_print((long long)(opts->num_bpp * opts->max_num_procs), "\n");
+
+ HDfprintf(output, "rank %d: File size=", rank);
+ recover_size_and_print((long long)(opts->num_bpp * opts->min_num_procs
+ * opts->num_dsets), ":");
+ recover_size_and_print((long long)(opts->num_bpp * opts->max_num_procs
+ * opts->num_dsets), "\n");
+
+ HDfprintf(output, "rank %d: Transfer buffer size=", rank);
+ recover_size_and_print((long long)opts->min_xfer_size, ":");
+ recover_size_and_print((long long)opts->max_xfer_size, "\n");
+ HDfprintf(output, "rank %d: Block size=", rank);
+ recover_size_and_print((long long)opts->blk_size, "\n");
+ }
+
+ HDfprintf(output, "rank %d: Block Pattern in Dataset=", rank);
+ if(opts->interleaved)
+ HDfprintf(output, "Interleaved\n");
+ else
+ HDfprintf(output, "Contiguous\n");
+
+ HDfprintf(output, "rank %d: I/O Method for MPI and HDF5=", rank);
+ if(opts->collective)
+ HDfprintf(output, "Collective\n");
+ else
+ HDfprintf(output, "Independent\n");
+
+ HDfprintf(output, "rank %d: Geometry=", rank);
+ if(opts->dim2d)
+ HDfprintf(output, "2D\n");
+ else
+ HDfprintf(output, "1D\n");
+
+ HDfprintf(output, "rank %d: VFL used for HDF5 I/O=%s\n", rank, "MPI-IO driver");
+
+ HDfprintf(output, "rank %d: Data storage method in HDF5=", rank);
+ if(opts->h5_use_chunks)
+ HDfprintf(output, "Chunked\n");
+ else
+ HDfprintf(output, "Contiguous\n");
+
+ {
+ char *prefix = getenv("HDF5_PARAPREFIX");
+
+ HDfprintf(output, "rank %d: Env HDF5_PARAPREFIX=%s\n", rank,
+ (prefix ? prefix : "not set"));
+ }
+
+ HDfprintf(output, "rank %d: ", rank);
+ h5_dump_info_object(h5_io_info_g);
+
+ HDfprintf(output, "rank %d: ==== End of Parameters ====\n", rank);
+ HDfprintf(output, "\n");
+}
+
+/*
+ * Function: parse_command_line
+ * Purpose: Parse the command line options and return a STRUCT OPTIONS
+ * structure which will need to be freed by the calling function.
+ * Return: Pointer to an OPTIONS structure
+ * Programmer: Bill Wendling, 31. October 2001
+ * Modifications:
+ * Added 2D testing (Christian Chilan, 10. August 2005)
+ */
+static struct options *
+parse_command_line(int argc, char *argv[])
+{
+ register int opt;
+ struct options *cl_opts;
+
+ cl_opts = (struct options *)malloc(sizeof(struct options));
+
+ cl_opts->output_file = NULL;
+ cl_opts->io_types = 0; /* will set default after parsing options */
+ cl_opts->num_dsets = 1;
+ cl_opts->num_files = 1;
+ cl_opts->num_bpp = 0;
+ cl_opts->num_iters = 1;
+ cl_opts->max_num_procs = comm_world_nprocs_g;
+ cl_opts->min_num_procs = 1;
+ cl_opts->max_xfer_size = 0;
+ cl_opts->min_xfer_size = 0;
+ cl_opts->blk_size = 0;
+ cl_opts->interleaved = 0; /* Default to contiguous blocks in dataset */
+ cl_opts->collective = 0; /* Default to independent I/O access */
+ cl_opts->dim2d = 0; /* Default to 1D */
+ cl_opts->print_times = FALSE; /* Printing times is off by default */
+ cl_opts->print_raw = FALSE; /* Printing raw data throughput is off by default */
+ cl_opts->h5_alignment = 1; /* No alignment for HDF5 objects by default */
+ cl_opts->h5_threshold = 1; /* No threshold for aligning HDF5 objects by default */
+ cl_opts->h5_use_chunks = FALSE; /* Don't chunk the HDF5 dataset by default */
+ cl_opts->h5_write_only = FALSE; /* Do both read and write by default */
+ cl_opts->verify = FALSE; /* No Verify data correctness by default */
+
+ while ((opt = get_option(argc, (const char **)argv, s_opts, l_opts)) != EOF) {
+ switch ((char)opt) {
+ case 'a':
+ cl_opts->h5_alignment = parse_size_directive(opt_arg);
+ break;
+ case 'A':
+ {
+ const char *end = opt_arg;
+
+ while (end && *end != '\0') {
+ char buf[10];
+ int i;
+
+ memset(buf, '\0', sizeof(buf));
+
+ for (i = 0; *end != '\0' && *end != ','; ++end)
+ if (isalnum(*end) && i < 10)
+ buf[i++] = *end;
+
+ if (!HDstrcasecmp(buf, "phdf5")) {
+ cl_opts->io_types |= PIO_HDF5;
+ } else if (!HDstrcasecmp(buf, "mpiio")) {
+ cl_opts->io_types |= PIO_MPI;
+ } else if (!HDstrcasecmp(buf, "posix")) {
+ cl_opts->io_types |= PIO_POSIX;
+ } else {
+ fprintf(stderr, "pio_perf: invalid --api option %s\n",
+ buf);
+ exit(EXIT_FAILURE);
+ }
+
+ if (*end == '\0')
+ break;
+
+ end++;
+ }
+ }
+
+ break;
+#if 0
+ case 'b':
+ /* the future "binary" option */
+ break;
+#endif /* 0 */
+ case 'B':
+ cl_opts->blk_size = parse_size_directive(opt_arg);
+ break;
+ case 'c':
+ /* Turn on chunked HDF5 dataset creation */
+ cl_opts->h5_use_chunks = TRUE;
+ break;
+ case 'C':
+ cl_opts->collective = 1;
+ break;
+ case 'd':
+ cl_opts->num_dsets = atoi(opt_arg);
+ break;
+ case 'D':
+ {
+ const char *end = opt_arg;
+
+ while (end && *end != '\0') {
+ char buf[10];
+ int i;
+
+ memset(buf, '\0', sizeof(buf));
+
+ for (i = 0; *end != '\0' && *end != ','; ++end)
+ if (isalnum(*end) && i < 10)
+ buf[i++] = *end;
+
+ if (strlen(buf) > 1 || isdigit(buf[0])) {
+ size_t j;
+
+ for (j = 0; j < 10 && buf[j] != '\0'; ++j)
+ if (!isdigit(buf[j])) {
+ fprintf(stderr, "pio_perf: invalid --debug option %s\n",
+ buf);
+ exit(EXIT_FAILURE);
+ }
+
+ pio_debug_level = atoi(buf);
+
+ if (pio_debug_level > 4)
+ pio_debug_level = 4;
+ else if (pio_debug_level < 0)
+ pio_debug_level = 0;
+ } else {
+ switch (*buf) {
+ case 'r':
+ /* Turn on raw data throughput info */
+ cl_opts->print_raw = TRUE;
+ break;
+ case 't':
+ /* Turn on time printing */
+ cl_opts->print_times = TRUE;
+ break;
+ case 'v':
+ /* Turn on verify data correctness*/
+ cl_opts->verify = TRUE;
+ break;
+ default:
+ fprintf(stderr, "pio_perf: invalid --debug option %s\n", buf);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (*end == '\0')
+ break;
+
+ end++;
+ }
+ }
+
+ break;
+ case 'e':
+ cl_opts->num_bpp = parse_size_directive(opt_arg);
+ break;
+ case 'F':
+ cl_opts->num_files = atoi(opt_arg);
+ break;
+ case 'g':
+ cl_opts->dim2d = 1;
+ break;
+ case 'i':
+ cl_opts->num_iters = atoi(opt_arg);
+ break;
+ case 'I':
+ cl_opts->interleaved = 1;
+ break;
+ case 'o':
+ cl_opts->output_file = opt_arg;
+ break;
+ case 'p':
+ cl_opts->min_num_procs = atoi(opt_arg);
+ break;
+ case 'P':
+ cl_opts->max_num_procs = atoi(opt_arg);
+ break;
+ case 'T':
+ cl_opts->h5_threshold = parse_size_directive(opt_arg);
+ break;
+ case 'w':
+ cl_opts->h5_write_only = TRUE;
+ break;
+ case 'x':
+ cl_opts->min_xfer_size = parse_size_directive(opt_arg);
+ break;
+ case 'X':
+ cl_opts->max_xfer_size = parse_size_directive(opt_arg);
+ break;
+ case 'h':
+ case '?':
+ default:
+ usage(progname);
+ free(cl_opts);
+ return NULL;
+ }
+ }
+
+
+ if (cl_opts->num_bpp == 0){
+ if (cl_opts->dim2d == 0)
+ cl_opts->num_bpp = 256 * ONE_KB;
+ else
+ cl_opts->num_bpp = 8 * ONE_KB;
+ }
+
+ if (cl_opts->max_xfer_size == 0)
+ cl_opts->max_xfer_size = cl_opts->num_bpp;
+
+ if (cl_opts->min_xfer_size == 0)
+ cl_opts->min_xfer_size = (cl_opts->num_bpp)/2;
+
+ if (cl_opts->blk_size == 0)
+ cl_opts->blk_size = (cl_opts->num_bpp)/2;
+
+
+ /* set default if none specified yet */
+ if (!cl_opts->io_types)
+ cl_opts->io_types = PIO_HDF5 | PIO_MPI | PIO_POSIX; /* run all API */
+
+ /* verify parameters sanity. Adjust if needed. */
+ /* cap xfer_size with bytes per process */
+ if (!cl_opts->dim2d) {
+ if (cl_opts->min_xfer_size > cl_opts->num_bpp)
+ cl_opts->min_xfer_size = cl_opts->num_bpp;
+ if (cl_opts->max_xfer_size > cl_opts->num_bpp)
+ cl_opts->max_xfer_size = cl_opts->num_bpp;
+ }
+ if (cl_opts->min_xfer_size > cl_opts->max_xfer_size)
+ cl_opts->min_xfer_size = cl_opts->max_xfer_size;
+ if (cl_opts->blk_size > cl_opts->num_bpp )
+ cl_opts->blk_size = cl_opts->num_bpp;
+ /* check range of number of processes */
+ if (cl_opts->min_num_procs <= 0)
+ cl_opts->min_num_procs = 1;
+ if (cl_opts->max_num_procs <= 0)
+ cl_opts->max_num_procs = 1;
+ if (cl_opts->min_num_procs > cl_opts->max_num_procs)
+ cl_opts->min_num_procs = cl_opts->max_num_procs;
+ /* check iteration */
+ if (cl_opts->num_iters <= 0)
+ cl_opts->num_iters = 1;
+
+ return cl_opts;
+}
+
+/*
+ * Function: parse_size_directive
+ * Purpose: Parse the size directive passed on the commandline. The size
+ * directive is an integer followed by a size indicator:
+ *
+ * K, k - Kilobyte
+ * M, m - Megabyte
+ * G, g - Gigabyte
+ *
+ * Return: The size as a off_t because this is related to file size.
+ * If an unknown size indicator is used, then the program will
+ * exit with EXIT_FAILURE as the return value.
+ * Programmer: Bill Wendling, 18. December 2001
+ * Modifications:
+ */
+static off_t
+parse_size_directive(const char *size)
+{
+ off_t s;
+ char *endptr;
+
+ s = strtol(size, &endptr, 10);
+
+ if (endptr && *endptr) {
+ while (*endptr != '\0' && (*endptr == ' ' || *endptr == '\t'))
+ ++endptr;
+
+ switch (*endptr) {
+ case 'K':
+ case 'k':
+ s *= ONE_KB;
+ break;
+ case 'M':
+ case 'm':
+ s *= ONE_MB;
+ break;
+ case 'G':
+ case 'g':
+ s *= ONE_GB;
+ break;
+ default:
+ fprintf(stderr, "Illegal size specifier '%c'\n", *endptr);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ return s;
+}
+
+/*
+ * Function: usage
+ * Purpose: Print a usage message and then exit.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 31. October 2001
+ * Modifications:
+ * Added 2D testing (Christian Chilan, 10. August 2005)
+ */
+static void
+usage(const char *prog)
+{
+ int myrank;
+
+ MPI_Comm_rank(pio_comm_g, &myrank);
+
+ if (myrank == 0) {
+ print_version(prog);
+ printf("usage: %s [OPTIONS]\n", prog);
+ printf(" OPTIONS\n");
+ printf(" -h, --help Print a usage message and exit\n");
+ printf(" -a S, --align=S Alignment of objects in HDF5 file [default: 1]\n");
+ printf(" -A AL, --api=AL Which APIs to test [default: all of them]\n");
+#if 0
+ printf(" -b, --binary The elusive binary option\n");
+#endif /* 0 */
+ printf(" -B S, --block-size=S Block size within transfer buffer\n");
+ printf(" (see below for description)\n");
+ printf(" [default: half the number of bytes per process\n");
+ printf(" per dataset]\n");
+ printf(" -c, --chunk Create HDF5 datasets using chunked storage\n");
+ printf(" [default: contiguous storage]\n");
+ printf(" -C, --collective Use collective I/O for MPI and HDF5 APIs\n");
+ printf(" [default: independent I/O)\n");
+ printf(" -d N, --num-dsets=N Number of datasets per file [default: 1]\n");
+ printf(" -D DL, --debug=DL Indicate the debugging level\n");
+ printf(" [default: no debugging]\n");
+ printf(" -e S, --num-bytes=S Number of bytes per process per dataset\n");
+ printf(" (see below for description)\n");
+ printf(" [default: 256K for 1D, 8K for 2D]\n");
+ printf(" -F N, --num-files=N Number of files [default: 1]\n");
+ printf(" -g, --geometry Use 2D geometry [default: 1D geometry]\n");
+ printf(" -i N, --num-iterations=N Number of iterations to perform [default: 1]\n");
+ printf(" -I, --interleaved Interleaved access pattern\n");
+ printf(" (see below for example)\n");
+ printf(" [default: Contiguous access pattern]\n");
+ printf(" -o F, --output=F Output raw data into file F [default: none]\n");
+ printf(" -p N, --min-num-processes=N Minimum number of processes to use [default: 1]\n");
+ printf(" -P N, --max-num-processes=N Maximum number of processes to use\n");
+ printf(" [default: all MPI_COMM_WORLD processes ]\n");
+ printf(" -T S, --threshold=S Threshold for alignment of objects in HDF5 file\n");
+ printf(" [default: 1]\n");
+ printf(" -w, --write-only Perform write tests not the read tests\n");
+ printf(" -x S, --min-xfer-size=S Minimum transfer buffer size\n");
+ printf(" (see below for description)\n");
+ printf(" [default: half the number of bytes per process\n");
+ printf(" per dataset]\n");
+ printf(" -X S, --max-xfer-size=S Maximum transfer buffer size\n");
+ printf(" [default: the number of bytes per process per\n");
+ printf(" dataset]\n");
+ printf("\n");
+ printf(" F - is a filename.\n");
+ printf(" N - is an integer >=0.\n");
+ printf(" S - is a size specifier, an integer >=0 followed by a size indicator:\n");
+ printf(" K - Kilobyte (%d)\n", ONE_KB);
+ printf(" M - Megabyte (%d)\n", ONE_MB);
+ printf(" G - Gigabyte (%d)\n", ONE_GB);
+ printf("\n");
+ printf(" Example: '37M' is 37 megabytes or %d bytes\n", 37*ONE_MB);
+ printf("\n");
+ printf(" AL - is an API list. Valid values are:\n");
+ printf(" phdf5 - Parallel HDF5\n");
+ printf(" mpiio - MPI-I/O\n");
+ printf(" posix - POSIX\n");
+ printf("\n");
+ printf(" Example: --api=mpiio,phdf5\n");
+ printf("\n");
+ printf(" Dataset size:\n");
+ printf(" Depending on the selected geometry, each test dataset is either a linear\n");
+ printf(" array of size bytes-per-process * num-processes, or a square array of size\n");
+ printf(" (bytes-per-process * num-processes) x (bytes-per-process * num-processes).\n");
+ printf("\n");
+ printf(" Block size vs. Transfer buffer size:\n");
+ printf(" buffer-size controls the size of the memory buffer, which is broken into\n");
+ printf(" blocks and written to the file. Depending on the selected geometry, each\n");
+ printf(" block can be a linear array of size block-size or a square array of size\n");
+ printf(" block-size x block-size. The arrangement in which blocks are written is\n");
+ printf(" determined by the access pattern.\n");
+ printf("\n");
+ printf(" In 1D geometry, the transfer buffer is a linear array of size buffer-size.\n");
+ printf(" In 2D geometry, it is a rectangular array of size block-size x buffer-size\n");
+ printf(" or buffer-size x block-size if interleaved pattern is selected.\n");
+ printf("\n");
+ printf(" Interleaved and Contiguous patterns in 1D geometry:\n");
+ printf(" When contiguous access pattern is chosen, the dataset is evenly divided\n");
+ printf(" into num-processes regions and each process writes data to its own region.\n");
+ printf(" When interleaved blocks are written to a dataset, space for the first\n");
+ printf(" block of the first process is allocated in the dataset, then space is\n");
+ printf(" allocated for the first block of the second process, etc. until space is\n");
+ printf(" allocated for the first block of each process, then space is allocated for\n");
+ printf(" the second block of the first process, the second block of the second\n");
+ printf(" process, etc.\n");
+ printf("\n");
+ printf(" For example, with a 3 process run, 512KB bytes-per-process, 256KB transfer\n");
+ printf(" buffer size, and 64KB block size, each process must issue 2 transfer\n");
+ printf(" requests to complete access to the dataset.\n");
+ printf(" Contiguous blocks of the first transfer request are written like so:\n");
+ printf(" 1111----2222----3333----\n");
+ printf(" Interleaved blocks of the first transfer request are written like so:\n");
+ printf(" 123123123123------------\n");
+ printf(" The actual number of I/O operations involved in a transfer request\n");
+ printf(" depends on the access pattern and communication mode.\n");
+ printf(" When using independent I/O with interleaved pattern, each process\n");
+ printf(" performs 4 small non-contiguous I/O operations per transfer request.\n");
+ printf(" If collective I/O is turned on, the combined content of the buffers of\n");
+ printf(" the 3 processes will be written using one collective I/O operation\n");
+ printf(" per transfer request.\n");
+ printf("\n");
+ printf(" For information about access patterns in 2D geometry, please refer to the\n");
+ printf(" HDF5 Reference Manual.\n");
+ printf("\n");
+ printf(" DL - is a list of debugging flags. Valid values are:\n");
+ printf(" 1 - Minimal\n");
+ printf(" 2 - Not quite everything\n");
+ printf(" 3 - Everything\n");
+ printf(" 4 - The kitchen sink\n");
+ printf(" r - Raw data I/O throughput information\n");
+ printf(" t - Times as well as throughputs\n");
+ printf(" v - Verify data correctness\n");
+ printf("\n");
+ printf(" Example: --debug=2,r,t\n");
+ printf("\n");
+ printf(" Environment variables:\n");
+ printf(" HDF5_NOCLEANUP Do not remove data files if set [default remove]\n");
+ printf(" HDF5_MPI_INFO MPI INFO object key=value separated by ;\n");
+ printf(" HDF5_PARAPREFIX Paralllel data files prefix\n");
+ fflush(stdout);
+ }
+}
+
+#else /* H5_HAVE_PARALLEL */
+
+/*
+ * Function: main
+ * Purpose: Dummy main() function for if HDF5 was configured without
+ * parallel stuff.
+ * Return: EXIT_SUCCESS
+ * Programmer: Bill Wendling, 14. November 2001
+ * Modifications:
+ */
+int
+main(void)
+{
+ printf("No parallel IO performance because parallel is not configured\n");
+ return EXIT_SUCCESS;
+}
+
+#endif /* !H5_HAVE_PARALLEL */
diff --git a/tools/perform/pio_perf.h b/tools/perform/pio_perf.h
new file mode 100644
index 0000000..3295e2b
--- /dev/null
+++ b/tools/perform/pio_perf.h
@@ -0,0 +1,105 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef PIO_PERF_H__
+#define PIO_PERF_H__
+
+#ifndef STANDALONE
+#include "H5private.h"
+#include "h5test.h"
+#include "h5tools.h"
+#include "h5tools_utils.h"
+#else
+#include "pio_standalone.h"
+#endif
+#include "pio_timer.h"
+
+/* setup the dataset no fill option if this is v1.5 or more */
+#if H5_VERS_MAJOR > 1 || H5_VERS_MINOR > 4
+#define H5_HAVE_NOFILL 1
+#endif
+
+typedef enum iotype_ {
+ POSIXIO,
+ MPIO,
+ PHDF5
+ /*NUM_TYPES*/
+} iotype;
+
+typedef struct parameters_ {
+ iotype io_type; /* The type of IO test to perform */
+ int num_procs; /* Maximum number of processes to use */
+ long num_files; /* Number of files to create */
+ long num_dsets; /* Number of datasets to create */
+ off_t num_bytes; /* Number of bytes in each dset */
+ int num_iters; /* Number of times to loop doing the IO */
+ size_t buf_size; /* Buffer size */
+ size_t blk_size; /* Block size */
+ unsigned interleaved; /* Interleaved vs. contiguous blocks */
+ unsigned collective; /* Collective vs. independent I/O */
+ unsigned dim2d; /* 1D vs. 2D */
+ hsize_t h5_align; /* HDF5 object alignment */
+ hsize_t h5_thresh; /* HDF5 object alignment threshold */
+ int h5_use_chunks; /* Make HDF5 dataset chunked */
+ int h5_write_only; /* Perform the write tests only */
+ int verify; /* Verify data correctness */
+} parameters;
+
+typedef struct results_ {
+ herr_t ret_code;
+ pio_time *timers;
+} results;
+
+#ifndef SUCCESS
+#define SUCCESS 0
+#endif /* !SUCCESS */
+
+#ifndef FAIL
+#define FAIL -1
+#endif /* !FAIL */
+
+extern FILE *output; /* output file */
+extern pio_time *timer_g; /* timer: global for stub functions */
+extern int comm_world_rank_g; /* my rank in MPI_COMM_RANK */
+extern int comm_world_nprocs_g;/* num. of processes of MPI_COMM_WORLD */
+extern MPI_Comm pio_comm_g; /* Communicator to run the PIO */
+extern int pio_mpi_rank_g; /* MPI rank of pio_comm_g */
+extern int pio_mpi_nprocs_g; /* number of processes of pio_comm_g */
+extern int pio_debug_level; /* The debug level:
+ * 0 - Off
+ * 1 - Minimal
+ * 2 - Some more
+ * 3 - Maximal
+ * 4 - Even More Debugging (timer stuff)
+ */
+
+#define HDprint_rank(f) /* print rank in MPI_COMM_WORLD */ \
+ HDfprintf(f, "%d: ", comm_world_rank_g);
+#define HDprint_size(f) /* print size of MPI_COMM_WORLD */ \
+ HDfprintf(f, "%d", comm_world_nprocs_g);
+#define HDprint_rank_size(f) /* print rank/size of MPI_COMM_WORLD */ \
+ HDfprintf(f, "%d/%d: ", comm_world_rank_g, comm_world_nprocs_g);
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+extern results do_pio(parameters param);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* PIO_PERF_H__ */
diff --git a/tools/perform/pio_standalone.c b/tools/perform/pio_standalone.c
new file mode 100644
index 0000000..e404274
--- /dev/null
+++ b/tools/perform/pio_standalone.c
@@ -0,0 +1,282 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+/* This file contains the definition of functions required to build h5perf in
+ * STANDALONE mode.
+ * Created: Christian Chilan, 2005/5/18.
+ */
+
+#include "pio_perf.h"
+
+
+/** From h5tools_utils.c **/
+
+/* global variables */
+int nCols = 80;
+
+/* ``get_option'' variables */
+int opt_err = 1; /*get_option prints errors if this is on */
+int opt_ind = 1; /*token pointer */
+const char *opt_arg; /*flag argument (or value) */
+
+
+int
+get_option(int argc, const char **argv, const char *opts, const struct long_options *l_opts)
+{
+ static int sp = 1; /* character index in current token */
+ int opt_opt = '?'; /* option character passed back to user */
+
+ if (sp == 1) {
+ /* check for more flag-like tokens */
+ if (opt_ind >= argc || argv[opt_ind][0] != '-' || argv[opt_ind][1] == '\0') {
+ return EOF;
+ } else if (HDstrcmp(argv[opt_ind], "--") == 0) {
+ opt_ind++;
+ return EOF;
+ }
+ }
+
+ if (sp == 1 && argv[opt_ind][0] == '-' && argv[opt_ind][1] == '-') {
+ /* long command line option */
+ const char *arg = &argv[opt_ind][2];
+ int i;
+
+ for (i = 0; l_opts && l_opts[i].name; i++) {
+ size_t len = HDstrlen(l_opts[i].name);
+
+ if (HDstrncmp(arg, l_opts[i].name, len) == 0) {
+ /* we've found a matching long command line flag */
+ opt_opt = l_opts[i].shortval;
+
+ if (l_opts[i].has_arg != no_arg) {
+ if (arg[len] == '=') {
+ opt_arg = &arg[len + 1];
+ } else if (opt_ind < (argc - 1) && argv[opt_ind + 1][0] != '-') {
+ opt_arg = argv[++opt_ind];
+ } else if (l_opts[i].has_arg == require_arg) {
+ if (opt_err)
+ HDfprintf(stderr,
+ "%s: option required for \"--%s\" flag\n",
+ argv[0], arg);
+
+ opt_opt = '?';
+ }
+ } else {
+ if (arg[len] == '=') {
+ if (opt_err)
+ HDfprintf(stderr,
+ "%s: no option required for \"%s\" flag\n",
+ argv[0], arg);
+
+ opt_opt = '?';
+ }
+
+ opt_arg = NULL;
+ }
+
+ break;
+ }
+ }
+
+ if (l_opts[i].name == NULL) {
+ /* exhausted all of the l_opts we have and still didn't match */
+ if (opt_err)
+ HDfprintf(stderr, "%s: unknown option \"%s\"\n", argv[0], arg);
+
+ opt_opt = '?';
+ }
+
+ opt_ind++;
+ sp = 1;
+ } else {
+ register char *cp; /* pointer into current token */
+
+ /* short command line option */
+ opt_opt = argv[opt_ind][sp];
+
+ if (opt_opt == ':' || (cp = strchr(opts, opt_opt)) == 0) {
+
+ if (opt_err)
+ HDfprintf(stderr, "%s: unknown option \"%c\"\n",
+ argv[0], opt_opt);
+
+ /* if no chars left in this token, move to next token */
+ if (argv[opt_ind][++sp] == '\0') {
+ opt_ind++;
+ sp = 1;
+ }
+
+ return '?';
+ }
+
+ if (*++cp == ':') {
+ /* if a value is expected, get it */
+ if (argv[opt_ind][sp + 1] != '\0') {
+ /* flag value is rest of current token */
+ opt_arg = &argv[opt_ind++][sp + 1];
+ } else if (++opt_ind >= argc) {
+ if (opt_err)
+ HDfprintf(stderr,
+ "%s: value expected for option \"%c\"\n",
+ argv[0], opt_opt);
+
+ opt_opt = '?';
+ } else {
+ /* flag value is next token */
+ opt_arg = argv[opt_ind++];
+ }
+
+ sp = 1;
+ } else {
+ /* set up to look at next char in token, next time */
+ if (argv[opt_ind][++sp] == '\0') {
+ /* no more in current token, so setup next token */
+ opt_ind++;
+ sp = 1;
+ }
+
+ opt_arg = NULL;
+ }
+ }
+
+ /* return the current flag character found */
+ return opt_opt;
+}
+
+
+void
+print_version(const char *progname)
+{
+ printf("%s: Version %u.%u.%u%s%s\n",
+ progname, H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE,
+ H5_VERS_SUBRELEASE[0] ? "-" : "", H5_VERS_SUBRELEASE);
+}
+
+
+
+/** From h5test.c **/
+
+#ifdef H5_HAVE_PARALLEL
+MPI_Info h5_io_info_g=MPI_INFO_NULL;/* MPI INFO object for IO */
+#endif
+
+int
+h5_set_info_object(void)
+{
+ char *envp; /* environment pointer */
+ int ret_value=0;
+
+ /* handle any MPI INFO hints via $HDF5_MPI_INFO */
+ if ((envp = getenv("HDF5_MPI_INFO")) != NULL){
+ char *next, *valp;
+
+
+ valp = envp = next = HDstrdup(envp);
+
+ /* create an INFO object if not created yet */
+ if (h5_io_info_g == MPI_INFO_NULL)
+ MPI_Info_create(&h5_io_info_g);
+
+ do {
+ size_t len;
+ char *key_val, *endp, *namep;
+
+ if (*valp == ';')
+ valp++;
+
+ /* copy key/value pair into temporary buffer */
+ len = strcspn(valp, ";");
+ next = &valp[len];
+ key_val = calloc(1, len + 1);
+
+ /* increment the next pointer past the terminating semicolon */
+ if (*next == ';')
+ ++next;
+
+ namep = HDstrncpy(key_val, valp, len);
+
+ /* pass up any beginning whitespaces */
+ while (*namep && (*namep == ' ' || *namep == '\t'))
+ namep++;
+
+ /* eat up any ending white spaces */
+ endp = &namep[strlen(namep) - 1];
+
+ while (endp && (*endp == ' ' || *endp == '\t'))
+ *endp-- = '\0';
+
+ /* find the '=' */
+
+ valp = HDstrchr(namep, '=');
+
+ if (valp != NULL) { /* it's a valid key/value pairing */
+ char *tmp_val = valp + 1;
+
+ /* change '=' to \0, move valp down one */
+ *valp-- = '\0';
+
+ /* eat up ending whitespace on the "key" part */
+ while (*valp == ' ' || *valp == '\t')
+ *valp-- = '\0';
+
+ valp = tmp_val;
+
+ /* eat up beginning whitespace on the "value" part */
+ while (*valp == ' ' || *valp == '\t')
+ *valp++ = '\0';
+
+ /* actually set the darned thing */
+ if (MPI_SUCCESS != MPI_Info_set(h5_io_info_g, namep, valp)) {
+ printf("MPI_Info_set failed\n");
+ ret_value = -1;
+ }
+ }
+
+ valp = next;
+ HDfree(key_val);
+ } while (next && *next);
+
+ HDfree(envp);
+ }
+
+ return ret_value;
+}
+
+
+void
+h5_dump_info_object(MPI_Info info)
+{
+ char key[MPI_MAX_INFO_KEY+1];
+ char value[MPI_MAX_INFO_VAL+1];
+ int flag;
+ int i, nkeys;
+
+ printf("Dumping MPI Info Object(%d) (up to %d bytes per item):\n", (int)info,
+ MPI_MAX_INFO_VAL);
+ if (info==MPI_INFO_NULL){
+ printf("object is MPI_INFO_NULL\n");
+ }
+ else {
+ MPI_Info_get_nkeys(info, &nkeys);
+ printf("object has %d items\n", nkeys);
+ for (i=0; i<nkeys; i++){
+ MPI_Info_get_nthkey(info, i, key);
+ MPI_Info_get(info, key, MPI_MAX_INFO_VAL, value, &flag);
+ printf("%s=%s\n", key, value);
+ }
+
+ }
+}
diff --git a/tools/perform/pio_standalone.h b/tools/perform/pio_standalone.h
new file mode 100644
index 0000000..584a057
--- /dev/null
+++ b/tools/perform/pio_standalone.h
@@ -0,0 +1,157 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef PIO_STANDALONE_H__
+#define PIO_PERF_H__
+
+/* Header file for building h5perf by standalone mode.
+ * Created: Christian Chilan, 2005/5/18.
+ */
+
+/** From H5private.h **/
+
+#include "H5public.h" /* Include Public Definitions */
+
+
+/*
+ * Include ANSI-C header files.
+ */
+#ifdef H5_STDC_HEADERS
+# include <assert.h>
+# include <ctype.h>
+# include <errno.h>
+# include <fcntl.h>
+# include <float.h>
+# include <limits.h>
+# include <math.h>
+# include <signal.h>
+# include <stdarg.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+/*
+ * And now for a couple non-Posix functions... Watch out for systems that
+ * define these in terms of macros.
+ */
+#ifdef H5_HAVE_WIN32_API
+#define HDstrdup(S) _strdup(S)
+#else /* H5_HAVE_WIN32_API */
+
+#if !defined strdup && !defined H5_HAVE_STRDUP
+extern char *strdup(const char *s);
+#endif
+
+#define HDstrdup(S) strdup(S)
+
+#endif /* H5_HAVE_WIN32_API */
+
+H5_DLL int HDfprintf (FILE *stream, const char *fmt, ...);
+#define HDstrcmp(S,T) strcmp(S,T)
+#define HDstrlen(S) strlen(S)
+#define HDstrncmp(S,T,L) strncmp(S,T,L)
+#define HDstrncpy(X,Y,Z) strncpy(X,Y,Z)
+#define HDstrchr(S,C) strchr(S,C)
+#define HDfree(M) free(M)
+
+
+#ifdef _O_BINARY
+#define HDopen(S,F,M) open(S,F|_O_BINARY,M)
+#else
+#define HDopen(S,F,M) open(S,F,M)
+#endif
+#define HDclose(F) close(F)
+
+#ifdef H5_HAVE_WIN32_API
+#define HDlseek(F,O,W) _lseeki64(F,O,W)
+#else
+#define HDlseek(F,O,W) lseek(F,O,W)
+#endif
+
+#define HDwrite(F,M,Z) write(F,M,Z)
+
+#define HDread(F,M,Z) read(F,M,Z)
+
+#ifdef H5_HAVE_WIN32_API
+ #define HDstat(S,B) _stati64(S,B)
+#else
+#define HDstat(S,B) stat(S,B)
+#endif
+
+#ifdef H5_HAVE_WIN32_API
+#define HDfstat(F,B) _fstati64(F,B)
+typedef struct _stati64 h5_stat_t;
+typedef __int64 h5_stat_size_t;
+#else
+#define HDfstat(F,B) fstat(F,B)
+typedef struct stat h5_stat_t;
+typedef off_t h5_stat_size_t;
+#endif
+
+/*
+ * HDF Boolean type.
+ */
+#ifndef FALSE
+# define FALSE 0
+#endif
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+
+/** From h5test.h **/
+
+#ifdef H5_HAVE_PARALLEL
+extern MPI_Info h5_io_info_g; /* MPI INFO object for IO */
+#endif
+
+#ifdef H5_HAVE_PARALLEL
+H5TEST_DLL int h5_set_info_object(void);
+H5TEST_DLL void h5_dump_info_object(MPI_Info info);
+#endif
+
+
+
+/** From h5tools_utils.h **/
+
+extern int opt_err; /* getoption prints errors if this is on */
+extern int opt_ind; /* token pointer */
+extern const char *opt_arg; /* flag argument (or value) */
+
+
+enum {
+ no_arg = 0, /* doesn't take an argument */
+ require_arg, /* requires an argument */
+ optional_arg /* argument is optional */
+};
+
+
+typedef struct long_options {
+ const char *name; /* name of the long option */
+ int has_arg; /* whether we should look for an arg */
+ char shortval; /* the shortname equivalent of long arg
+ * this gets returned from get_option */
+} long_options;
+
+extern int get_option(int argc, const char **argv, const char *opt,
+ const struct long_options *l_opt);
+
+extern int nCols; /*max number of columns for outputting */
+
+/* Definitions of useful routines */
+extern void print_version(const char *progname);
+
+#endif
diff --git a/tools/perform/pio_timer.c b/tools/perform/pio_timer.c
new file mode 100644
index 0000000..aba219e
--- /dev/null
+++ b/tools/perform/pio_timer.c
@@ -0,0 +1,258 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose:
+ *
+ * This is a module of useful timing functions for performance testing.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "hdf5.h"
+
+#ifdef H5_HAVE_PARALLEL
+
+#include <mpi.h>
+
+#include "pio_perf.h"
+
+/*
+ * The number to divide the tv_usec field with to get a nice decimal to add to
+ * the number of seconds.
+ */
+#define MICROSECOND 1000000.0
+
+/* global variables */
+pio_time *timer_g; /* timer: global for stub functions */
+
+/*
+ * Function: sub_time
+ * Purpose: Struct two time values, and return the difference, in microseconds
+ *
+ * Note that the function assumes that a > b
+ * Programmer: Leon Arber, 1/27/06
+ */
+static double sub_time(struct timeval* a, struct timeval* b)
+{
+ return (((double)a->tv_sec +
+ ((double)a->tv_usec) / MICROSECOND) -
+ ((double)b->tv_sec +
+ ((double)b->tv_usec) / MICROSECOND));
+}
+
+
+/*
+ * Function: pio_time_new
+ * Purpose: Build us a brand, spankin', new performance time object.
+ * The object is a black box to the user. They just tell us
+ * what type of timer they want (MPI_TIMER for MPI_Wtime or
+ * SYS_TIMER for system time).
+ * Return: Pointer to pio_time object
+ * Programmer: Bill Wendling, 01. October 2001
+ * Modifications:
+ */
+pio_time *
+pio_time_new(clock_type type)
+{
+ pio_time *pt = (pio_time *)calloc(1, sizeof(struct pio_time_));
+
+ /* set global timer variable */
+ timer_g = pt;
+
+ pt->type = type;
+ return pt;
+}
+
+/*
+ * Function: pio_time_destroy
+ * Purpose: Remove the memory allocated for the pio_time object. Only
+ * need to call on a pointer allocated with the ``pio_time_new''
+ * function.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 01. October 2001
+ * Modifications:
+ */
+void
+pio_time_destroy(pio_time *pt)
+{
+ HDfree(pt);
+ /* reset the global timer pointer too. */
+ timer_g = NULL;
+}
+
+/*
+ * Function: set_timer_type
+ * Purpose: Set the type of the timer to either MPI_TIMER or SYS_TIMER.
+ * This really only needs to be called if you didn't construct a
+ * timer with the pio_timer_new function (shame!).
+ * Return: Nothing
+ * Programmer: Bill Wendling, 04. October 2001
+ * Modifications:
+ */
+void
+set_timer_type(pio_time *pt, clock_type type)
+{
+ pt->type = type;
+}
+
+/*
+ * Function: get_timer_type
+ * Purpose: Get the type of the timer.
+ * Return: MPI_TIMER or SYS_TIMER.
+ * Programmer: Bill Wendling, 04. October 2001
+ * Modifications:
+ */
+clock_type
+get_timer_type(pio_time *pt)
+{
+ return pt->type;
+}
+
+/*
+ * Function: set_time
+ * Purpose: Set the time in a ``pio_time'' object.
+ * Return: Pointer to the passed in ``pio_time'' object.
+ * Programmer: Bill Wendling, 01. October 2001
+ * Modifications:
+ */
+pio_time *
+set_time(pio_time *pt, timer_type t, int start_stop)
+{
+ if (pt) {
+ if (pt->type == MPI_TIMER) {
+ if (start_stop == TSTART) {
+ pt->mpi_timer[t] = MPI_Wtime();
+
+ /* When we start the timer for HDF5_FINE_WRITE_FIXED_DIMS or HDF5_FINE_READ_FIXED_DIMS
+ * we compute the time it took to only open the file */
+ if(t == HDF5_FINE_WRITE_FIXED_DIMS)
+ pt->total_time[HDF5_FILE_WRITE_OPEN] += pt->mpi_timer[t] - pt->mpi_timer[HDF5_GROSS_WRITE_FIXED_DIMS];
+ else if(t == HDF5_FINE_READ_FIXED_DIMS)
+ pt->total_time[HDF5_FILE_READ_OPEN] += pt->mpi_timer[t] - pt->mpi_timer[HDF5_GROSS_READ_FIXED_DIMS];
+
+ } else {
+ pt->total_time[t] += MPI_Wtime() - pt->mpi_timer[t];
+ pt->mpi_timer[t] = MPI_Wtime();
+
+ /* When we stop the timer for HDF5_GROSS_WRITE_FIXED_DIMS or HDF5_GROSS_READ_FIXED_DIMS
+ * we compute the time it took to close the file after the last read/write finished */
+ if(t == HDF5_GROSS_WRITE_FIXED_DIMS)
+ pt->total_time[HDF5_FILE_WRITE_CLOSE] += pt->mpi_timer[t] - pt->mpi_timer[HDF5_FINE_WRITE_FIXED_DIMS];
+ else if(t == HDF5_GROSS_READ_FIXED_DIMS)
+ pt->total_time[HDF5_FILE_READ_CLOSE] += pt->mpi_timer[t] - pt->mpi_timer[HDF5_FINE_READ_FIXED_DIMS];
+ }
+ } else {
+ if (start_stop == TSTART) {
+ HDgettimeofday(&pt->sys_timer[t], NULL);
+
+ /* When we start the timer for HDF5_FINE_WRITE_FIXED_DIMS or HDF5_FINE_READ_FIXED_DIMS
+ * we compute the time it took to only open the file */
+ if(t == HDF5_FINE_WRITE_FIXED_DIMS)
+ pt->total_time[HDF5_FILE_WRITE_OPEN] += sub_time(&(pt->sys_timer[t]), &(pt->sys_timer[HDF5_GROSS_WRITE_FIXED_DIMS]));
+ else if(t == HDF5_FINE_READ_FIXED_DIMS)
+ pt->total_time[HDF5_FILE_READ_OPEN] += sub_time(&(pt->sys_timer[t]), &(pt->sys_timer[HDF5_GROSS_READ_FIXED_DIMS]));
+
+
+ } else {
+ struct timeval sys_t;
+
+ HDgettimeofday(&sys_t, NULL);
+ pt->total_time[t] += sub_time(&sys_t, &(pt->sys_timer[t]));
+
+/* ((double)sys_t.tv_sec +
+ ((double)sys_t.tv_usec) / MICROSECOND) -
+ ((double)pt->sys_timer[t].tv_sec +
+ ((double)pt->sys_timer[t].tv_usec) / MICROSECOND);*/
+
+ /* When we stop the timer for HDF5_GROSS_WRITE_FIXED_DIMS or HDF5_GROSS_READ_FIXED_DIMS
+ * we compute the time it took to close the file after the last read/write finished */
+ if(t == HDF5_GROSS_WRITE_FIXED_DIMS)
+ pt->total_time[HDF5_FILE_WRITE_CLOSE] += sub_time(&(pt->sys_timer[t]), &(pt->sys_timer[HDF5_FINE_WRITE_FIXED_DIMS]));
+ else if(t == HDF5_GROSS_READ_FIXED_DIMS)
+ pt->total_time[HDF5_FILE_READ_CLOSE] += sub_time(&(pt->sys_timer[t]), &(pt->sys_timer[HDF5_FINE_READ_FIXED_DIMS]));
+
+ }
+ }
+
+ if (pio_debug_level >= 4) {
+ const char *msg;
+ int myrank;
+
+ MPI_Comm_rank(pio_comm_g, &myrank);
+
+ switch (t) {
+ case HDF5_FILE_OPENCLOSE:
+ msg = "File Open/Close";
+ break;
+ case HDF5_DATASET_CREATE:
+ msg = "Dataset Create";
+ break;
+ case HDF5_MPI_WRITE:
+ msg = "MPI Write";
+ break;
+ case HDF5_MPI_READ:
+ msg = "MPI Read";
+ break;
+ case HDF5_FINE_WRITE_FIXED_DIMS:
+ msg = "Fine Write";
+ break;
+ case HDF5_FINE_READ_FIXED_DIMS:
+ msg = "Fine Read";
+ break;
+ case HDF5_GROSS_WRITE_FIXED_DIMS:
+ msg = "Gross Write";
+ break;
+ case HDF5_GROSS_READ_FIXED_DIMS:
+ msg = "Gross Read";
+ break;
+ case HDF5_RAW_WRITE_FIXED_DIMS:
+ msg = "Raw Write";
+ break;
+ case HDF5_RAW_READ_FIXED_DIMS:
+ msg = "Raw Read";
+ break;
+ default:
+ msg = "Unknown Timer";
+ break;
+ }
+
+ fprintf(output, " Proc %d: %s %s: %.2f\n", myrank, msg,
+ (start_stop == TSTART ? "Start" : "Stop"),
+ pt->total_time[t]);
+ }
+ }
+
+ return pt;
+}
+
+/*
+ * Function: get_time
+ * Purpose: Get the time from a ``pio_time'' object.
+ * Return: The number of seconds as a DOUBLE.
+ * Programmer: Bill Wendling, 01. October 2001
+ * Modifications:
+ */
+double
+get_time(pio_time *pt, timer_type t)
+{
+ return pt->total_time[t];
+}
+
+#endif /* H5_HAVE_PARALLEL */
+#ifdef STANDALONE
+#include "pio_standalone.c"
+#endif
diff --git a/tools/perform/pio_timer.h b/tools/perform/pio_timer.h
new file mode 100644
index 0000000..a5ee6d7
--- /dev/null
+++ b/tools/perform/pio_timer.h
@@ -0,0 +1,82 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef PIO_TIMER__
+#define PIO_TIMER__
+
+#include "hdf5.h"
+
+#if defined(H5_TIME_WITH_SYS_TIME)
+# include <sys/time.h>
+# include <time.h>
+#elif defined(H5_HAVE_SYS_TIME_H)
+# include <sys/time.h>
+#else
+# include <time.h>
+#endif
+
+/* The different types of timers we can have */
+typedef enum timer_type_ {
+ HDF5_FILE_OPENCLOSE,
+ HDF5_DATASET_CREATE,
+ HDF5_MPI_WRITE,
+ HDF5_MPI_READ,
+ HDF5_FILE_READ_OPEN,
+ HDF5_FILE_READ_CLOSE,
+ HDF5_FILE_WRITE_OPEN,
+ HDF5_FILE_WRITE_CLOSE,
+ HDF5_FINE_WRITE_FIXED_DIMS,
+ HDF5_FINE_READ_FIXED_DIMS,
+ HDF5_GROSS_WRITE_FIXED_DIMS,
+ HDF5_GROSS_READ_FIXED_DIMS,
+ HDF5_RAW_WRITE_FIXED_DIMS,
+ HDF5_RAW_READ_FIXED_DIMS,
+ NUM_TIMERS
+} timer_type;
+
+typedef enum clock_type_ {
+ MPI_TIMER = 0, /* Use MPI timer to measure time */
+ SYS_TIMER = 1 /* Use system clock to measure time */
+} clock_type;
+
+/* Miscellaneous identifiers */
+enum {
+ TSTART, /* Start a specified timer */
+ TSTOP /* Stop a specified timer */
+};
+
+/* The performance time structure */
+typedef struct pio_time_ {
+ clock_type type;
+ double total_time[NUM_TIMERS];
+ double mpi_timer[NUM_TIMERS];
+ struct timeval sys_timer[NUM_TIMERS];
+} pio_time;
+
+/* External function declarations */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+extern pio_time *pio_time_new(clock_type t);
+extern void pio_time_destroy(pio_time *pt);
+extern void set_timer_type(pio_time *pt, clock_type type);
+extern clock_type get_timer_type(pio_time *pt);
+extern pio_time *set_time(pio_time *pt, timer_type t, int start_stop);
+extern double get_time(pio_time *pt, timer_type t);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* PIO_TIMER__ */
diff --git a/tools/perform/sio_engine.c b/tools/perform/sio_engine.c
new file mode 100644
index 0000000..07e6b16c
--- /dev/null
+++ b/tools/perform/sio_engine.c
@@ -0,0 +1,1310 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Author: Christian Chilan, April 2008
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#ifdef H5_HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <errno.h>
+
+#include "hdf5.h"
+
+#include "sio_perf.h"
+#include "sio_timer.h"
+
+/* Macro definitions */
+
+/* sizes of various items. these sizes won't change during program execution */
+#define ELMT_H5_TYPE H5T_NATIVE_UCHAR
+
+#define GOTOERROR(errcode) { ret_code = errcode; goto done; }
+#define ERRMSG(mesg) { \
+ fprintf(stderr, "*** Assertion failed (%s) at line %4d in %s\n", \
+ mesg, (int)__LINE__, __FILE__); \
+}
+
+/* verify: if val is false (0), print mesg. */
+#define VRFY(val, mesg) do { \
+ if (!val) { \
+ ERRMSG(mesg); \
+ GOTOERROR(FAIL); \
+ } \
+} while(0)
+
+/* POSIX I/O macros */
+#define POSIXCREATE(fn) HDopen(fn, O_CREAT|O_TRUNC|O_RDWR, 0600)
+#define POSIXOPEN(fn, F) HDopen(fn, F, 0600)
+#define POSIXCLOSE(F) HDclose(F)
+#define POSIXSEEK(F,L) HDlseek(F, L, SEEK_SET)
+#define POSIXWRITE(F,B,S) HDwrite(F,B,S)
+#define POSIXREAD(F,B,S) HDread(F,B,S)
+
+enum {
+ SIO_CREATE = 1,
+ SIO_WRITE = 2,
+ SIO_READ = 4
+};
+
+/* Global variables */
+static int clean_file_g = -1; /*whether to cleanup temporary test */
+/*files. -1 is not defined; */
+/*0 is no cleanup; 1 is do cleanup */
+
+/* the different types of file descriptors we can expect */
+typedef union _file_descr {
+ int posixfd; /* POSIX file handle*/
+ hid_t h5fd; /* HDF5 file */
+} file_descr;
+
+/* local functions */
+static char *sio_create_filename(iotype iot, const char *base_name,
+ char *fullname, size_t size, parameters *param);
+static herr_t do_write(results *res, file_descr *fd, parameters *parms, void *buffer);
+static herr_t do_read(results *res, file_descr *fd, parameters *parms, void *buffer);
+static herr_t dset_write(int local_dim, file_descr *fd, parameters *parms, void *buffer);
+static herr_t posix_buffer_write(int local_dim, file_descr *fd, parameters *parms, void *buffer);
+static herr_t dset_read(int localrank, file_descr *fd, parameters *parms, void *buffer, const char *buffer2);
+static herr_t posix_buffer_read(int local_dim, file_descr *fd, parameters *parms, void *buffer);
+static herr_t do_fopen(parameters *param, char *fname, file_descr *fd /*out*/,
+ int flags);
+hid_t set_vfd(parameters *param);
+static herr_t do_fclose(iotype iot, file_descr *fd);
+static void do_cleanupfile(iotype iot, char *fname);
+
+/* global variables */
+static off_t offset[MAX_DIMS]; /* dataset size in bytes */
+static size_t buf_offset[MAX_DIMS]; /* dataset size in bytes */
+static int order[MAX_DIMS]; /* dimension access order */
+static size_t linear_buf_size; /* linear buffer size */
+static int cont_dim; /* lowest dimension for contiguous POSIX
+ access */
+static size_t cont_size; /* size of contiguous POSIX access */
+static hid_t fapl; /* file access list */
+static unsigned char *buf_p; /* buffer pointer */
+static const char *multi_letters = "msbrglo"; /* string for multi driver */
+
+/* HDF5 global variables */
+static hsize_t h5count[MAX_DIMS]; /*selection count */
+static hssize_t h5offset[MAX_DIMS]; /* Selection offset within dataspace */
+static hid_t h5dset_space_id = -1; /*dataset space ID */
+static hid_t h5mem_space_id = -1; /*memory dataspace ID */
+static hid_t h5ds_id = -1; /*dataset handle */
+static hid_t h5dcpl = -1; /* Dataset creation property list */
+static hid_t h5dxpl = -1; /* Dataset transfer property list */
+
+/*
+ * Function: do_sio
+ * Purpose: SIO Engine where IO are executed.
+ * Return: results
+ * Programmer: Christian Chilan, April, 2008
+ * Modifications:
+ */
+ results
+do_sio(parameters param)
+{
+ char *buffer = NULL; /*data buffer pointer */
+ size_t buf_size[MAX_DIMS]; /* general buffer size in bytes */
+ file_descr fd; /* file handles */
+ iotype iot; /* API type */
+ char base_name[256]; /* test file base name */
+ /* return codes */
+ herr_t ret_code = 0; /*return code */
+ results res;
+
+ char fname[FILENAME_MAX]; /* test file name */
+ int i;
+ /* HDF5 variables */
+ herr_t hrc; /*HDF5 return code */
+
+ /* Sanity check parameters */
+
+ /* IO type */
+ iot = param.io_type;
+
+ switch (iot) {
+ case POSIXIO:
+ fd.posixfd = -1;
+ res.timers = sio_time_new();
+ break;
+ case HDF5:
+ fd.h5fd = -1;
+ res.timers = sio_time_new();
+ break;
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)iot);
+ GOTOERROR(FAIL);
+ }
+
+ linear_buf_size = 1;
+
+ for (i=0; i<param.rank; i++){
+ buf_size[i] = param.buf_size[i];
+ order[i] = param.order[i];
+ linear_buf_size *= buf_size[i];
+ buf_offset[i] = 0;
+ offset[i] = 0;
+
+ /* Validate transfer buffer size */
+ if (param.buf_size[i]<=0) {
+ HDfprintf(stderr,
+ "Transfer buffer size[%d] (%zu) must be > 0\n", i,buf_size[i]);
+ GOTOERROR(FAIL);
+ }
+
+ if ((param.dset_size[i]%param.buf_size[i])!=0) {
+ HDfprintf(stderr,
+ "Dataset size[%d] (%" H5_PRINTF_LL_WIDTH "d) must be a multiple of the "
+ "trasfer buffer size[%d] (%zu)\n",param.rank,
+ (long long)param.dset_size[i], param.rank, param.buf_size[i]);
+ GOTOERROR(FAIL);
+ }
+
+ }
+
+ /* Allocate transfer buffer */
+ if ((buffer = malloc(linear_buf_size)) == NULL){
+ HDfprintf(stderr, "malloc for transfer buffer size (%zu) failed\n", linear_buf_size);
+ GOTOERROR(FAIL);
+ }
+
+ if (sio_debug_level >= 4)
+
+ /* output all of the times for all iterations */
+ fprintf(output, "Timer details:\n");
+
+ /*
+ * Write performance measurement
+ */
+ /* Open file for write */
+
+ HDstrcpy(base_name, "#sio_tmp");
+ sio_create_filename(iot, base_name, fname, sizeof(fname), &param);
+
+ if (sio_debug_level > 0)
+ HDfprintf(output, "data filename=%s\n",
+ fname);
+
+ set_time(res.timers, HDF5_GROSS_WRITE_FIXED_DIMS, TSTART);
+ hrc = do_fopen(&param, fname, &fd, SIO_CREATE | SIO_WRITE);
+ VRFY((hrc == SUCCESS), "do_fopen failed");
+
+ set_time(res.timers, HDF5_FINE_WRITE_FIXED_DIMS, TSTART);
+ hrc = do_write(&res, &fd, &param, buffer);
+ set_time(res.timers, HDF5_FINE_WRITE_FIXED_DIMS, TSTOP);
+ VRFY((hrc == SUCCESS), "do_write failed");
+
+ /* Close file for write */
+ hrc = do_fclose(iot, &fd);
+ set_time(res.timers, HDF5_GROSS_WRITE_FIXED_DIMS, TSTOP);
+ VRFY((hrc == SUCCESS), "do_fclose failed");
+
+ if (!param.h5_write_only) {
+ /*
+ * Read performance measurement
+ */
+
+ /* Open file for read */
+ set_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS, TSTART);
+ hrc = do_fopen(&param, fname, &fd, SIO_READ);
+ VRFY((hrc == SUCCESS), "do_fopen failed");
+
+ set_time(res.timers, HDF5_FINE_READ_FIXED_DIMS, TSTART);
+ hrc = do_read(&res, &fd, &param, buffer);
+ set_time(res.timers, HDF5_FINE_READ_FIXED_DIMS, TSTOP);
+ VRFY((hrc == SUCCESS), "do_read failed");
+
+ /* Close file for read */
+ hrc = do_fclose(iot, &fd);
+
+ set_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS, TSTOP);
+ VRFY((hrc == SUCCESS), "do_fclose failed");
+ }
+
+ do_cleanupfile(iot, fname);
+
+done:
+ /* clean up */
+ /* release HDF5 objects */
+
+ /* close any opened files */
+ /* no remove(fname) because that should have happened normally. */
+ switch (iot) {
+ case POSIXIO:
+ if (fd.posixfd != -1)
+ hrc = do_fclose(iot, &fd);
+ break;
+ case HDF5:
+ if (fd.h5fd != -1)
+ hrc = do_fclose(iot, &fd);
+ break;
+ default:
+ /* unknown request */
+ HDassert(0 && "Unknown IO type");
+ break;
+ }
+
+ /* release generic resources */
+ if (buffer)
+ free(buffer);
+
+ res.ret_code = ret_code;
+ return res;
+}
+
+/*
+ * Function: sio_create_filename
+ * Purpose: Create a new filename to write to. Determine the correct
+ * suffix to append to the filename by the type of I/O we're
+ * doing. Also, place in the /tmp/{$USER,$LOGIN} directory if
+ * USER or LOGIN are specified in the environment.
+ * Return: Pointer to filename or NULL
+ * Programmer: Bill Wendling, 21. November 2001
+ * Modifications: Support for file drivers. Christian Chilan, April, 2008
+ */
+ static char *
+sio_create_filename(iotype iot, const char *base_name, char *fullname, size_t size, parameters *param)
+{
+ const char *prefix, *suffix="";
+ char *ptr, last = '\0';
+ size_t i, j;
+ vfdtype vfd;
+ vfd = param->vfd;
+
+ if (!base_name || !fullname || size < 1)
+ return NULL;
+
+ memset(fullname, 0, size);
+
+ switch (iot) {
+ case POSIXIO:
+ suffix = ".posix";
+ break;
+ case HDF5:
+ suffix = ".h5";
+ if (vfd == family)
+ suffix = "%05d.h5";
+ else if (vfd == multi)
+ suffix = NULL;
+ break;
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)iot);
+ HDassert(0 && "Unknown IO type");
+ break;
+ }
+
+ /* First use the environment variable and then try the constant */
+ prefix = HDgetenv("HDF5_PREFIX");
+
+#ifdef HDF5_PREFIX
+ if (!prefix)
+ prefix = HDF5_PREFIX;
+#endif /* HDF5_PREFIX */
+
+ /* Prepend the prefix value to the base name */
+ if (prefix && *prefix) {
+ /* If the prefix specifies the HDF5_PREFIX directory, then
+ * default to using the "/tmp/$USER" or "/tmp/$LOGIN"
+ * directory instead. */
+ register char *user, *login, *subdir;
+
+ user = HDgetenv("USER");
+ login = HDgetenv("LOGIN");
+ subdir = (user ? user : login);
+
+ if (subdir) {
+ for (i = 0; i < size-1 && prefix[i]; i++)
+ fullname[i] = prefix[i];
+
+ fullname[i++] = '/';
+
+ for (j = 0; i < size && subdir[j]; i++, j++)
+ fullname[i] = subdir[j];
+ } else {
+ /* We didn't append the prefix yet */
+ HDstrncpy(fullname, prefix, size);
+ fullname[size - 1] = '\0';
+ }
+
+ if ((HDstrlen(fullname) + HDstrlen(base_name) + 1) < size) {
+ /* Append the base_name with a slash first. Multiple slashes are
+ * handled below. */
+ h5_stat_t buf;
+
+ if (HDstat(fullname, &buf) < 0)
+ /* The directory doesn't exist just yet */
+ if (HDmkdir(fullname, 0755) < 0 && errno != EEXIST) {
+ /* We couldn't make the "/tmp/${USER,LOGIN}" subdirectory.
+ * Default to PREFIX's original prefix value. */
+ HDstrcpy(fullname, prefix);
+ }
+
+ HDstrcat(fullname, "/");
+ HDstrcat(fullname, base_name);
+ } else {
+ /* Buffer is too small */
+ return NULL;
+ }
+ } else if (strlen(base_name) >= size) {
+ /* Buffer is too small */
+ return NULL;
+ } else {
+ HDstrcpy(fullname, base_name);
+ }
+
+ /* Append a suffix */
+ if (suffix) {
+ if (HDstrlen(fullname) + HDstrlen(suffix) >= size)
+ return NULL;
+
+ HDstrcat(fullname, suffix);
+ }
+
+ /* Remove any double slashes in the filename */
+ for (ptr = fullname, i = j = 0; ptr && (i < size); i++, ptr++) {
+ if (*ptr != '/' || last != '/')
+ fullname[j++] = *ptr;
+
+ last = *ptr;
+ }
+
+ return fullname;
+}
+
+/*
+ * Function: do_write
+ * Purpose: Write the required amount of data to the file.
+ * Return: SUCCESS or FAIL
+ * Programmer: Christian Chilan, April, 2008
+ * Modifications:
+ */
+static herr_t
+do_write(results *res, file_descr *fd, parameters *parms, void *buffer)
+{
+ int ret_code = SUCCESS;
+ char dname[64];
+ long i;
+ /* HDF5 variables */
+ herr_t hrc; /*HDF5 return code */
+ hsize_t h5dims[MAX_DIMS]; /*dataset dim sizes */
+ hsize_t h5chunk[MAX_DIMS]; /*dataset dim sizes */
+ hsize_t h5block[MAX_DIMS]; /*dataspace selection */
+ hsize_t h5stride[MAX_DIMS]; /*selection stride */
+ hsize_t h5start[MAX_DIMS]; /*selection start */
+ hsize_t h5maxdims[MAX_DIMS];
+ int rank; /*rank of dataset */
+ /* Prepare buffer for verifying data */
+/* if (parms->verify)
+ memset(buffer,1,linear_buf_size); */
+
+ buf_p=(unsigned char *)buffer;
+
+ for (i=0; i < linear_buf_size; i++)
+ buf_p[i]=i%128;
+
+ rank = parms->rank;
+
+ for (i=0; i<rank; i++) {
+ h5offset[i] = offset[i] = 0;
+ }
+
+ /* I/O Access specific setup */
+ switch (parms->io_type) {
+ case POSIXIO:
+
+ /* determine lowest dimension for contiguous POSIX access */
+ cont_dim = rank;
+
+ for (i=rank-1; i>=0; i--) {
+ if (parms->buf_size[i]==parms->dset_size[i])
+ cont_dim = i;
+ else
+ break;
+ }
+
+ /* determine size of the contiguous POSIX access */
+ cont_size = (!cont_dim)? 1 : parms->buf_size[cont_dim-1];
+ for (i=cont_dim; i<rank; i++)
+ cont_size *= parms->buf_size[i];
+
+ break;
+
+ case HDF5: /* HDF5 setup */
+
+ for (i=0; i < rank; i++){
+ h5dims[i] = parms->dset_size[i];
+ h5start[i] = 0;
+ h5stride[i] = 1;
+ h5block[i] = 1;
+ h5count[i] = parms->buf_size[i];
+ h5chunk[i] = parms->chk_size[i];
+ h5maxdims[i] = H5S_UNLIMITED;
+
+ }
+
+ if (parms->h5_use_chunks && parms->h5_extendable) {
+ h5dset_space_id = H5Screate_simple(rank, h5count, h5maxdims);
+ VRFY((h5dset_space_id >= 0), "H5Screate_simple");
+ }
+ else {
+ h5dset_space_id = H5Screate_simple(rank, h5dims, NULL);
+ VRFY((h5dset_space_id >= 0), "H5Screate_simple");
+ }
+
+ hrc = H5Sselect_hyperslab(h5dset_space_id, H5S_SELECT_SET,
+ h5start, h5stride, h5count, h5block);
+ VRFY((hrc >= 0), "H5Sselect_hyperslab");
+
+ /* Create the memory dataspace that corresponds to the xfer buffer */
+ h5mem_space_id = H5Screate_simple(rank, h5count, NULL);
+ VRFY((h5mem_space_id >= 0), "H5Screate_simple");
+
+ /* Create the dataset transfer property list */
+ h5dxpl = H5Pcreate(H5P_DATASET_XFER);
+ if (h5dxpl < 0) {
+ fprintf(stderr, "HDF5 Property List Create failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ break;
+
+ default:
+ HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)parms->io_type);
+ GOTOERROR(FAIL);
+ break;
+ } /* end switch */
+
+
+ /* create dataset */
+ switch (parms->io_type) {
+ case POSIXIO:
+ break;
+
+ case HDF5:
+ h5dcpl = H5Pcreate(H5P_DATASET_CREATE);
+
+ if (h5dcpl < 0) {
+ fprintf(stderr, "HDF5 Property List Create failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ if(parms->h5_use_chunks) {
+ /* Set the chunk size to be the same as the buffer size */
+ hrc = H5Pset_chunk(h5dcpl, rank, h5chunk);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Property List Set failed\n");
+ GOTOERROR(FAIL);
+ } /* end if */
+ } /* end if */
+
+ sprintf(dname, "Dataset_%ld", (unsigned long)parms->num_bytes);
+ h5ds_id = H5Dcreate2(fd->h5fd, dname, ELMT_H5_TYPE,
+ h5dset_space_id, H5P_DEFAULT, h5dcpl, H5P_DEFAULT);
+
+ if (h5ds_id < 0) {
+ HDfprintf(stderr, "HDF5 Dataset Create failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ hrc = H5Pclose(h5dcpl);
+ /* verifying the close of the dcpl */
+ if (hrc < 0) {
+ HDfprintf(stderr, "HDF5 Property List Close failed\n");
+ GOTOERROR(FAIL);
+ }
+ break;
+
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)parms->io_type);
+ GOTOERROR(FAIL);
+ break;
+ }
+
+ /* Start "raw data" write timer */
+ set_time(res->timers, HDF5_RAW_WRITE_FIXED_DIMS, TSTART);
+
+ /* Perform write */
+ hrc = dset_write(rank-1, fd, parms, buffer);
+
+ if (hrc < 0) {
+ fprintf(stderr, "Error in dataset write\n");
+ GOTOERROR(FAIL);
+ }
+
+
+ /* Stop "raw data" write timer */
+ set_time(res->timers, HDF5_RAW_WRITE_FIXED_DIMS, TSTOP);
+
+ /* Calculate write time */
+
+ /* Close dataset. Only HDF5 needs to do an explicit close. */
+ if (parms->io_type == HDF5) {
+ hrc = H5Dclose(h5ds_id);
+
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Dataset Close failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ h5ds_id = -1;
+ } /* end if */
+
+done:
+
+ /* release HDF5 objects */
+ if (h5dset_space_id != -1) {
+ hrc = H5Sclose(h5dset_space_id);
+ if (hrc < 0){
+ fprintf(stderr, "HDF5 Dataset Space Close failed\n");
+ ret_code = FAIL;
+ } else {
+ h5dset_space_id = -1;
+ }
+ }
+
+ if (h5mem_space_id != -1) {
+ hrc = H5Sclose(h5mem_space_id);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Memory Space Close failed\n");
+ ret_code = FAIL;
+ } else {
+ h5mem_space_id = -1;
+ }
+ }
+
+ if (h5dxpl != -1) {
+ hrc = H5Pclose(h5dxpl);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Dataset Transfer Property List Close failed\n");
+ ret_code = FAIL;
+ } else {
+ h5dxpl = -1;
+ }
+ }
+
+ return ret_code;
+}
+
+/*
+ * Function: dset_write
+ * Purpose: Write buffer into the dataset.
+ * Return: SUCCESS or FAIL
+ * Programmer: Christian Chilan, April, 2008
+ * Modifications:
+ */
+
+static herr_t dset_write(int local_dim, file_descr *fd, parameters *parms, void *buffer)
+{
+ int cur_dim = order[local_dim]-1;
+ int ret_code = SUCCESS;
+ int k;
+ hsize_t dims[MAX_DIMS], maxdims[MAX_DIMS];
+ long i,j;
+ herr_t hrc;
+
+ /* iterates according to the dimensions in order array */
+ for (i=0; i < parms->dset_size[cur_dim]; i += parms->buf_size[cur_dim]){
+
+ h5offset[cur_dim] = offset[cur_dim] = i;
+
+ if (local_dim > 0){
+
+ dset_write(local_dim-1, fd, parms, buffer);
+
+ }else{
+
+ switch (parms->io_type) {
+
+ case POSIXIO:
+ /* initialize POSIX offset in the buffer */
+ for (j=0; j < parms->rank; j++) {
+ buf_offset[j]=0;
+ }
+ buf_p = (unsigned char *)buffer;
+ /* write POSIX buffer */
+ posix_buffer_write(0, fd, parms, buffer);
+ break;
+
+ case HDF5:
+ /* if dimensions are extendable, extend them as needed during
+ access */
+ if (parms->h5_use_chunks && parms->h5_extendable) {
+
+ hrc=H5Sget_simple_extent_dims(h5dset_space_id,dims,maxdims);
+ VRFY((hrc >= 0), "H5Sget_simple_extent_dims");
+
+ for (k=0; k < parms->rank; k++){
+
+ if (dims[k] <= h5offset[k]) {
+ dims[k] = dims[k]+h5count[k];
+ hrc=H5Sset_extent_simple(h5dset_space_id,parms->rank,dims,maxdims);
+ VRFY((hrc >= 0), "H5Sset_extent_simple");
+ hrc=H5Dset_extent(h5ds_id,dims);
+ VRFY((hrc >= 0), "H5Dextend");
+ }
+ }
+ }
+ /* applies offset */
+ hrc = H5Soffset_simple(h5dset_space_id, h5offset);
+ VRFY((hrc >= 0), "H5Soffset_simple");
+
+ /* Write the buffer out */
+ hrc=H5Sget_simple_extent_dims(h5dset_space_id,dims,maxdims);
+ hrc = H5Dwrite(h5ds_id, ELMT_H5_TYPE, h5mem_space_id,
+ h5dset_space_id, h5dxpl, buffer);
+ VRFY((hrc >= 0), "H5Dwrite");
+
+ break;
+
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)parms->io_type);
+ HDassert(0 && "Unknown IO type");
+ break;
+ } /* switch (parms->io_type) */
+ }
+ }
+done:
+ return ret_code;
+}
+
+/*
+ * Function: posix_buffer_write
+ * Purpose: Write buffer into the POSIX file considering contiguity.
+ * Return: SUCCESS or FAIL
+ * Programmer: Christian Chilan, April, 2008
+ * Modifications:
+ */
+
+static herr_t posix_buffer_write(int local_dim, file_descr *fd, parameters *parms, void *buffer)
+{
+ int dtype_size = 1;
+ int ret_code = SUCCESS;
+ long i;
+ size_t d_offset;
+ size_t linear_dset_offset = 0;
+ int j, rc;
+
+ /* if dimension is not contiguous, call recursively */
+ if (local_dim < parms->rank-1 && local_dim != cont_dim) {
+
+ for (i=0; i < parms->buf_size[local_dim]; i += dtype_size) {
+ buf_offset[local_dim] = i;
+ posix_buffer_write(local_dim+1, fd, parms, buffer);
+
+ /* if next dimension is cont_dim, it will fill out the buffer
+ traversing the entire dimension local_dim without the need
+ of performing iteration */
+ if (local_dim+1==cont_dim)
+ break;
+ }
+ /* otherwise, perform contiguous POSIX access */
+ } else {
+
+ buf_offset[local_dim] = 0;
+
+ /* determine offset in the buffer */
+ for (i=0; i < parms->rank; i++){
+ d_offset=1;
+
+ for (j=i+1; j < parms->rank; j++)
+ d_offset *= parms->dset_size[j];
+
+ linear_dset_offset += (offset[i]+buf_offset[i])*d_offset;
+ }
+
+ /* only care if seek returns error */
+ rc = POSIXSEEK(fd->posixfd, linear_dset_offset) < 0 ? -1 : 0;
+ VRFY((rc==0), "POSIXSEEK");
+ /* check if all bytes are written */
+ rc = ((ssize_t)cont_size ==
+ POSIXWRITE(fd->posixfd, buf_p, cont_size));
+ VRFY((rc != 0), "POSIXWRITE");
+
+ /* Advance location in buffer */
+ buf_p += cont_size;
+
+ }
+done:
+ return ret_code;
+}
+
+/*
+ * Function: do_read
+ * Purpose: Read the required amount of data to the file.
+ * Return: SUCCESS or FAIL
+ * Programmer: Christian Chilan, April, 2008
+ * Modifications:
+ */
+static herr_t
+do_read(results *res, file_descr *fd, parameters *parms, void *buffer)
+{
+ char *buffer2 = NULL; /* Buffer for data verification */
+ int ret_code = SUCCESS;
+ char dname[64];
+ long i;
+ /* HDF5 variables */
+ herr_t hrc; /*HDF5 return code */
+ hsize_t h5dims[MAX_DIMS]; /*dataset dim sizes */
+ hsize_t h5block[MAX_DIMS]; /*dataspace selection */
+ hsize_t h5stride[MAX_DIMS]; /*selection stride */
+ hsize_t h5start[MAX_DIMS]; /*selection start */
+ int rank;
+
+ /* Allocate data verification buffer */
+ if(NULL == (buffer2 = (char *)malloc(linear_buf_size))) {
+ HDfprintf(stderr, "malloc for data verification buffer size (%Zu) failed\n", linear_buf_size);
+ GOTOERROR(FAIL);
+ } /* end if */
+
+ /* Prepare buffer for verifying data */
+ for(i = 0; i < linear_buf_size; i++)
+ buffer2[i] = i % 128;
+
+ rank = parms->rank;
+ for(i = 0; i < rank; i++)
+ h5offset[i] = offset[i] = 0;
+
+ /* I/O Access specific setup */
+ switch (parms->io_type) {
+ case POSIXIO:
+ cont_dim = rank;
+
+ for (i=rank-1; i>=0; i--) {
+ if (parms->buf_size[i]==parms->dset_size[i])
+ cont_dim = i;
+ else
+ break;
+ }
+ cont_size = (!cont_dim)? 1 : parms->buf_size[cont_dim-1];
+ for (i=cont_dim; i<rank; i++)
+ cont_size *= parms->buf_size[i];
+
+ break;
+
+ case HDF5: /* HDF5 setup */
+ for (i=0; i < rank; i++){
+ h5dims[i] = parms->dset_size[i];
+ h5start[i] = 0;
+ h5stride[i] = 1;
+ h5block[i] = 1;
+ h5count[i] = parms->buf_size[i];
+ }
+
+ h5dset_space_id = H5Screate_simple(rank, h5dims, NULL);
+ VRFY((h5dset_space_id >= 0), "H5Screate_simple");
+
+ hrc = H5Sselect_hyperslab(h5dset_space_id, H5S_SELECT_SET,
+ h5start, h5stride, h5count, h5block);
+ VRFY((hrc >= 0), "H5Sselect_hyperslab");
+
+ /* Create the memory dataspace that corresponds to the xfer buffer */
+ h5mem_space_id = H5Screate_simple(rank, h5count, NULL);
+ VRFY((h5mem_space_id >= 0), "H5Screate_simple");
+
+ /* Create the dataset transfer property list */
+ h5dxpl = H5Pcreate(H5P_DATASET_XFER);
+ if (h5dxpl < 0) {
+ fprintf(stderr, "HDF5 Property List Create failed\n");
+ GOTOERROR(FAIL);
+ }
+ break;
+
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)parms->io_type);
+ GOTOERROR(FAIL);
+ break;
+ } /* end switch */
+
+
+ /* create dataset */
+ switch (parms->io_type) {
+ case POSIXIO:
+ break;
+
+ case HDF5:
+ sprintf(dname, "Dataset_%ld", (long)parms->num_bytes);
+ h5ds_id = H5Dopen2(fd->h5fd, dname, H5P_DEFAULT);
+ if (h5ds_id < 0) {
+ HDfprintf(stderr, "HDF5 Dataset open failed\n");
+ GOTOERROR(FAIL);
+ }
+ break;
+
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)parms->io_type);
+ GOTOERROR(FAIL);
+ break;
+ } /* end switch */
+
+ /* Start "raw data" read timer */
+ set_time(res->timers, HDF5_RAW_READ_FIXED_DIMS, TSTART);
+ hrc = dset_read(rank-1, fd, parms, buffer, buffer2);
+
+ if (hrc < 0) {
+ fprintf(stderr, "Error in dataset read\n");
+ GOTOERROR(FAIL);
+ }
+
+ /* Stop "raw data" read timer */
+ set_time(res->timers, HDF5_RAW_READ_FIXED_DIMS, TSTOP);
+
+ /* Calculate read time */
+
+ /* Close dataset. Only HDF5 needs to do an explicit close. */
+ if (parms->io_type == HDF5) {
+ hrc = H5Dclose(h5ds_id);
+
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Dataset Close failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ h5ds_id = -1;
+ } /* end if */
+
+done:
+
+ /* release HDF5 objects */
+ if (h5dset_space_id != -1) {
+ hrc = H5Sclose(h5dset_space_id);
+ if (hrc < 0){
+ fprintf(stderr, "HDF5 Dataset Space Close failed\n");
+ ret_code = FAIL;
+ } else {
+ h5dset_space_id = -1;
+ }
+ }
+
+ if (h5mem_space_id != -1) {
+ hrc = H5Sclose(h5mem_space_id);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Memory Space Close failed\n");
+ ret_code = FAIL;
+ } else {
+ h5mem_space_id = -1;
+ }
+ }
+
+ if (h5dxpl != -1) {
+ hrc = H5Pclose(h5dxpl);
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 Dataset Transfer Property List Close failed\n");
+ ret_code = FAIL;
+ } else {
+ h5dxpl = -1;
+ }
+ }
+
+ /* release generic resources */
+ if(buffer2)
+ free(buffer2);
+
+ return ret_code;
+}
+
+/*
+ * Function: dset_read
+ * Purpose: Read buffer into the dataset.
+ * Return: SUCCESS or FAIL
+ * Programmer: Christian Chilan, April, 2008
+ * Modifications:
+ */
+
+static herr_t dset_read(int local_dim, file_descr *fd, parameters *parms,
+ void *buffer, const char *buffer2)
+{
+ int cur_dim = order[local_dim]-1;
+ int ret_code = SUCCESS;
+ long i,j;
+ herr_t hrc;
+
+ /* iterate on the current dimension */
+ for (i=0; i < parms->dset_size[cur_dim]; i += parms->buf_size[cur_dim]){
+
+ h5offset[cur_dim] = offset[cur_dim] = i;
+
+ /* if traverse in order array is incomplete, recurse */
+ if (local_dim > 0){
+
+ ret_code = dset_read(local_dim-1, fd, parms, buffer, buffer2);
+
+ /* otherwise, write buffer into dataset */
+ }else{
+
+ switch (parms->io_type) {
+
+ case POSIXIO:
+ for (j=0; j<parms->rank; j++) {
+ buf_offset[j] = 0;
+ }
+ buf_p = (unsigned char*)buffer;
+ posix_buffer_read(0, fd, parms, buffer);
+ break;
+
+ case HDF5:
+ hrc = H5Soffset_simple(h5dset_space_id, h5offset);
+ VRFY((hrc >= 0), "H5Soffset_simple");
+ /* Read the buffer out */
+ hrc = H5Dread(h5ds_id, ELMT_H5_TYPE, h5mem_space_id,
+ h5dset_space_id, h5dxpl, buffer);
+ VRFY((hrc >= 0), "H5Dread");
+#if 0
+ for (j=0; j<linear_buf_size; j++) {
+ buf_p = (unsigned char*)buffer;
+ if (buf_p[j]!=buffer2[j])
+ printf("Inconsistent data in %d\n", j);
+ }
+#endif
+ break;
+
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)parms->io_type);
+ HDassert(0 && "Unknown IO type");
+ break;
+ } /* switch (parms->io_type) */
+ }
+ }
+done:
+ return ret_code;
+}
+
+/*
+ * Function: posix_buffer_read
+ * Purpose: Read buffer into the POSIX file considering contiguity.
+ * Return: SUCCESS or FAIL
+ * Programmer: Christian Chilan, April, 2008
+ * Modifications:
+ */
+
+static herr_t posix_buffer_read(int local_dim, file_descr *fd, parameters *parms, void *buffer)
+{
+ int dtype_size = 1;
+ int ret_code = SUCCESS;
+ long i;
+ size_t d_offset;
+ size_t linear_dset_offset = 0;
+ int j, rc;
+
+ /* if local dimension is not contiguous, recurse */
+ if (local_dim < parms->rank-1 && local_dim != cont_dim) {
+
+ for (i=0; i < parms->buf_size[local_dim]; i += dtype_size) {
+ buf_offset[local_dim] = i;
+ ret_code = posix_buffer_read(local_dim+1, fd, parms, buffer);
+ if (local_dim+1==cont_dim)
+ break;
+ }
+ /* otherwise, perform contiguous POSIX access */
+ } else {
+
+ buf_offset[local_dim] = 0;
+ /* determine offset in buffer */
+ for (i=0; i<parms->rank; i++){
+ d_offset=1;
+
+ for (j=i+1; j<parms->rank; j++)
+ d_offset *= parms->dset_size[j];
+
+ linear_dset_offset += (offset[i]+buf_offset[i])*d_offset;
+ }
+
+ /* only care if seek returns error */
+ rc = POSIXSEEK(fd->posixfd, linear_dset_offset) < 0 ? -1 : 0;
+ VRFY((rc==0), "POSIXSEEK");
+ /* check if all bytes are read */
+ rc = ((ssize_t)cont_size ==
+ POSIXREAD(fd->posixfd, buf_p, cont_size));
+ VRFY((rc != 0), "POSIXREAD");
+
+ /* Advance location in buffer */
+ buf_p += cont_size;
+
+ }
+done:
+ return ret_code;
+}
+
+
+/*
+ * Function: do_fopen
+ * Purpose: Open the specified file.
+ * Return: SUCCESS or FAIL
+ * Programmer: Albert Cheng, Bill Wendling, 2001/12/13
+ * Modifications: Support for file drivers, Christian Chilan, April, 2008
+ */
+ static herr_t
+do_fopen(parameters *param, char *fname, file_descr *fd /*out*/, int flags)
+{
+ int ret_code = SUCCESS;
+
+ switch (param->io_type) {
+ case POSIXIO:
+ if (flags & (SIO_CREATE | SIO_WRITE))
+ fd->posixfd = POSIXCREATE(fname);
+ else
+ fd->posixfd = POSIXOPEN(fname, O_RDONLY);
+
+ if (fd->posixfd < 0 ) {
+ HDfprintf(stderr, "POSIX File Open failed(%s)\n", fname);
+ GOTOERROR(FAIL);
+ }
+
+ break;
+
+ case HDF5:
+
+ fapl = set_vfd(param);
+
+ if (fapl < 0) {
+ fprintf(stderr, "HDF5 Property List Create failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ /* create the parallel file */
+ if (flags & (SIO_CREATE | SIO_WRITE)) {
+ fd->h5fd = H5Fcreate(fname, H5F_ACC_TRUNC, H5P_DEFAULT, fapl);
+ } else {
+ fd->h5fd = H5Fopen(fname, H5F_ACC_RDONLY, fapl);
+ }
+
+
+ if (fd->h5fd < 0) {
+ fprintf(stderr, "HDF5 File Create failed(%s)\n", fname);
+ GOTOERROR(FAIL);
+ }
+ break;
+
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)param->io_type);
+ GOTOERROR(FAIL);
+ break;
+ }
+
+done:
+ return ret_code;
+}
+
+/*
+ * Function: set_vfd
+ * Purpose: Sets file driver.
+ * Return: SUCCESS or FAIL
+ * Programmer: Christian Chilan, April, 2008
+ * Modifications:
+ */
+
+hid_t
+set_vfd(parameters *param)
+{
+ hid_t my_fapl = -1;
+ vfdtype vfd;
+
+ vfd = param->vfd;
+
+ if ((my_fapl=H5Pcreate(H5P_FILE_ACCESS))<0) return -1;
+
+ if (vfd == sec2) {
+ /* Unix read() and write() system calls */
+ if (H5Pset_fapl_sec2(my_fapl)<0) return -1;
+ } else if (vfd == stdio) {
+ /* Standard C fread() and fwrite() system calls */
+ if (H5Pset_fapl_stdio(my_fapl)<0) return -1;
+ } else if (vfd == core) {
+ /* In-core temporary file with 1MB increment */
+ if (H5Pset_fapl_core(my_fapl, (size_t)1024*1024, TRUE)<0) return -1;
+ } else if (vfd == split) {
+ /* Split meta data and raw data each using default driver */
+ if (H5Pset_fapl_split(my_fapl,
+ "-m.h5", H5P_DEFAULT,
+ "-r.h5", H5P_DEFAULT)<0)
+ return -1;
+ } else if (vfd == multi) {
+ /* Multi-file driver, general case of the split driver */
+ H5FD_mem_t memb_map[H5FD_MEM_NTYPES];
+ hid_t memb_fapl[H5FD_MEM_NTYPES];
+ const char *memb_name[H5FD_MEM_NTYPES];
+ char sv[H5FD_MEM_NTYPES][1024];
+ haddr_t memb_addr[H5FD_MEM_NTYPES];
+ H5FD_mem_t mt;
+
+ HDmemset(memb_map, 0, sizeof memb_map);
+ HDmemset(memb_fapl, 0, sizeof memb_fapl);
+ HDmemset(memb_name, 0, sizeof memb_name);
+ HDmemset(memb_addr, 0, sizeof memb_addr);
+
+ HDassert(HDstrlen(multi_letters)==H5FD_MEM_NTYPES);
+ for (mt=H5FD_MEM_DEFAULT; mt<H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t,mt)) {
+ memb_fapl[mt] = H5P_DEFAULT;
+ sprintf(sv[mt], "%%s-%c.h5", multi_letters[mt]);
+ memb_name[mt] = sv[mt];
+ memb_addr[mt] = MAX(mt-1,0)*(HADDR_MAX/10);
+ }
+
+ if (H5Pset_fapl_multi(my_fapl, memb_map, memb_fapl, memb_name,
+ memb_addr, FALSE)<0) {
+ return -1;
+ }
+ } else if (vfd == family) {
+ hsize_t fam_size = 1*1024*1024; /*100 MB*/
+
+ /* Family of files, each 1MB and using the default driver */
+ /* if ((val=HDstrtok(NULL, " \t\n\r")))
+ fam_size = (hsize_t)(HDstrtod(val, NULL) * 1024*1024); */
+ if (H5Pset_fapl_family(my_fapl, fam_size, H5P_DEFAULT)<0)
+ return -1;
+ } else if (vfd == direct) {
+#ifdef H5_HAVE_DIRECT
+ /* Linux direct read() and write() system calls. Set memory boundary, file block size,
+ * and copy buffer size to the default values. */
+ if (H5Pset_fapl_direct(my_fapl, 1024, 4096, 8*4096)<0) return -1;
+#endif
+ } else {
+ /* Unknown driver */
+ return -1;
+ }
+
+ return my_fapl;
+}
+
+/*
+ * Function: do_fclose
+ * Purpose: Close the specified file descriptor.
+ * Return: SUCCESS or FAIL
+ * Programmer: Albert Cheng, Bill Wendling, 2001/12/13
+ * Modifications:
+ */
+ static herr_t
+do_fclose(iotype iot, file_descr *fd /*out*/)
+{
+ herr_t ret_code = SUCCESS, hrc;
+ int rc = 0;
+
+ switch (iot) {
+ case POSIXIO:
+ rc = POSIXCLOSE(fd->posixfd);
+
+ if (rc != 0){
+ fprintf(stderr, "POSIX File Close failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ fd->posixfd = -1;
+ break;
+
+ case HDF5:
+ hrc = H5Fclose(fd->h5fd);
+
+ if (hrc < 0) {
+ fprintf(stderr, "HDF5 File Close failed\n");
+ GOTOERROR(FAIL);
+ }
+
+ fd->h5fd = -1;
+ break;
+
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)iot);
+ GOTOERROR(FAIL);
+ break;
+ }
+
+done:
+ return ret_code;
+}
+
+
+/*
+ * Function: do_cleanupfile
+ * Purpose: Cleanup temporary file unless HDF5_NOCLEANUP is set.
+ * Return: void
+ * Programmer: Albert Cheng 2001/12/12
+ * Modifications: Support for file drivers. Christian Chilan, April, 2008
+ */
+ static void
+do_cleanupfile(iotype iot, char *filename)
+{
+ char temp[2048];
+ int j;
+ hid_t driver;
+
+ if (clean_file_g == -1)
+ clean_file_g = (HDgetenv("HDF5_NOCLEANUP")==NULL) ? 1 : 0;
+
+ if (clean_file_g){
+
+ switch (iot) {
+ case POSIXIO:
+ HDremove(filename);
+ break;
+
+ case HDF5:
+ driver = H5Pget_driver(fapl);
+
+ if (driver == H5FD_FAMILY) {
+ for (j = 0; /*void*/; j++) {
+ HDsnprintf(temp, sizeof temp, filename, j);
+
+ if (HDaccess(temp, F_OK) < 0)
+ break;
+
+ HDremove(temp);
+ }
+ } else if (driver == H5FD_CORE) {
+ hbool_t backing; /* Whether the core file has backing store */
+
+ H5Pget_fapl_core(fapl,NULL,&backing);
+
+ /* If the file was stored to disk with bacing store, remove it */
+ if(backing)
+ HDremove(filename);
+
+ } else if (driver == H5FD_MULTI) {
+ H5FD_mem_t mt;
+ assert(HDstrlen(multi_letters)==H5FD_MEM_NTYPES);
+
+ for (mt = H5FD_MEM_DEFAULT; mt < H5FD_MEM_NTYPES; H5_INC_ENUM(H5FD_mem_t,mt)) {
+ HDsnprintf(temp, sizeof temp, "%s-%c.h5",
+ filename, multi_letters[mt]);
+ HDremove(temp); /*don't care if it fails*/
+ }
+ } else {
+ HDremove(filename);
+ }
+ H5Pclose(fapl);
+ break;
+
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)iot);
+ HDassert(0 && "Unknown IO type");
+ break;
+ }
+ }
+}
+
diff --git a/tools/perform/sio_perf.c b/tools/perform/sio_perf.c
new file mode 100644
index 0000000..26cec6d
--- /dev/null
+++ b/tools/perform/sio_perf.c
@@ -0,0 +1,1409 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Serial HDF5 Performance Testing Code
+ * --------------------------------------
+ *
+ * Portable code to test performance on the different platforms we support.
+ * This is what the report should look like:
+ *
+ * nprocs = Max#Procs
+ * IO API = POSIXIO
+ * # Files = 1, # of dsets = 1000, Elements per dset = 37000
+ * Write Results = x MB/s
+ * Read Results = x MB/s
+ * # Files = 1, # of dsets = 3000, Elements per dset = 37000
+ * Write Results = x MB/s
+ * Read Results = x MB/s
+ *
+ * . . .
+ *
+ *
+ * IO API = HDF5
+ * # Files = 1, # of dsets = 1000, Elements per dset = 37000
+ * Write Results = x MB/s
+ * Read Results = x MB/s
+ * # Files = 1, # of dsets = 3000, Elements per dset = 37000
+ * Write Results = x MB/s
+ * Read Results = x MB/s
+ *
+ * . . .
+ *
+ *
+ * . . .
+ *
+ */
+
+/* system header files */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "hdf5.h"
+
+
+/* our header files */
+#include "sio_perf.h"
+
+/* useful macros */
+#define TAB_SPACE 4
+
+#define ONE_KB 1024
+#define ONE_MB (ONE_KB * ONE_KB)
+#define ONE_GB (ONE_MB * ONE_KB)
+
+#define SIO_POSIX 0x1
+#define SIO_HDF5 0x4
+
+/* report 0.0 in case t is zero too */
+#define MB_PER_SEC(bytes,t) (((t)==0.0) ? 0.0 : ((((double)bytes) / ONE_MB) / (t)))
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* TRUE */
+#ifndef FALSE
+#define FALSE (!TRUE)
+#endif /* FALSE */
+
+/* global variables */
+FILE *output; /* output file */
+int sio_debug_level = 0;/* The debug level:
+ * 0 - Off
+ * 1 - Minimal
+ * 2 - Some more
+ * 3 - Maximal
+ * 4 - Maximal & then some
+ */
+
+/* local variables */
+static const char *progname = "h5perf_serial";
+
+/*
+ * Command-line options: The user can specify short or long-named
+ * parameters. The long-named ones can be partially spelled. When
+ * adding more, make sure that they don't clash with each other.
+ */
+
+/*
+ * It seems that only the options that accept additional information
+ * such as dataset size (-e) require the colon next to it.
+ */
+#if 1
+static const char *s_opts = "a:A:B:c:Cd:D:e:F:ghi:Imno:p:P:r:stT:v:wx:X:";
+#else
+static const char *s_opts = "a:A:bB:c:Cd:D:e:F:ghi:Imno:p:P:r:stT:wx:X:";
+#endif /* 1 */
+static struct long_options l_opts[] = {
+ { "align", require_arg, 'a' },
+ { "alig", require_arg, 'a' },
+ { "ali", require_arg, 'a' },
+ { "al", require_arg, 'a' },
+ { "api", require_arg, 'A' },
+ { "ap", require_arg, 'A' },
+#if 0
+ /* a sighting of the elusive binary option */
+ { "binary", no_arg, 'b' },
+ { "binar", no_arg, 'b' },
+ { "bina", no_arg, 'b' },
+ { "bin", no_arg, 'b' },
+ { "bi", no_arg, 'b' },
+#endif /* 0 */
+ { "block-size", require_arg, 'B' },
+ { "block-siz", require_arg, 'B' },
+ { "block-si", require_arg, 'B' },
+ { "block-s", require_arg, 'B' },
+ { "block-", require_arg, 'B' },
+ { "block", require_arg, 'B' },
+ { "bloc", require_arg, 'B' },
+ { "blo", require_arg, 'B' },
+ { "bl", require_arg, 'B' },
+ { "chunk", no_arg, 'c' },
+ { "chun", no_arg, 'c' },
+ { "chu", no_arg, 'c' },
+ { "ch", no_arg, 'c' },
+ { "collective", no_arg, 'C' },
+ { "collectiv", no_arg, 'C' },
+ { "collecti", no_arg, 'C' },
+ { "collect", no_arg, 'C' },
+ { "collec", no_arg, 'C' },
+ { "colle", no_arg, 'C' },
+ { "coll", no_arg, 'C' },
+ { "col", no_arg, 'C' },
+ { "co", no_arg, 'C' },
+ { "debug", require_arg, 'D' },
+ { "debu", require_arg, 'D' },
+ { "deb", require_arg, 'D' },
+ { "de", require_arg, 'D' },
+ { "file-driver", require_arg, 'v' },
+ { "file-drive", require_arg, 'v' },
+ { "file-driv", require_arg, 'v' },
+ { "file-dri", require_arg, 'v' },
+ { "file-dr", require_arg, 'v' },
+ { "file-d", require_arg, 'v' },
+ { "file-", require_arg, 'v' },
+ { "file", require_arg, 'v' },
+ { "fil", require_arg, 'v' },
+ { "fi", require_arg, 'v' },
+ { "geometry", no_arg, 'g' },
+ { "geometr", no_arg, 'g' },
+ { "geomet", no_arg, 'g' },
+ { "geome", no_arg, 'g' },
+ { "geom", no_arg, 'g' },
+ { "geo", no_arg, 'g' },
+ { "ge", no_arg, 'g' },
+ { "help", no_arg, 'h' },
+ { "hel", no_arg, 'h' },
+ { "he", no_arg, 'h' },
+ { "interleaved", require_arg, 'I' },
+ { "interleave", require_arg, 'I' },
+ { "interleav", require_arg, 'I' },
+ { "interlea", require_arg, 'I' },
+ { "interle", require_arg, 'I' },
+ { "interl", require_arg, 'I' },
+ { "inter", require_arg, 'I' },
+ { "inte", require_arg, 'I' },
+ { "int", require_arg, 'I' },
+ { "in", require_arg, 'I' },
+ { "max-num-processes", require_arg, 'P' },
+ { "max-num-processe", require_arg, 'P' },
+ { "max-num-process", require_arg, 'P' },
+ { "max-num-proces", require_arg, 'P' },
+ { "max-num-proce", require_arg, 'P' },
+ { "max-num-proc", require_arg, 'P' },
+ { "max-num-pro", require_arg, 'P' },
+ { "max-num-pr", require_arg, 'P' },
+ { "max-num-p", require_arg, 'P' },
+ { "min-num-processes", require_arg, 'p' },
+ { "min-num-processe", require_arg, 'p' },
+ { "min-num-process", require_arg, 'p' },
+ { "min-num-proces", require_arg, 'p' },
+ { "min-num-proce", require_arg, 'p' },
+ { "min-num-proc", require_arg, 'p' },
+ { "min-num-pro", require_arg, 'p' },
+ { "min-num-pr", require_arg, 'p' },
+ { "min-num-p", require_arg, 'p' },
+ { "max-xfer-size", require_arg, 'X' },
+ { "max-xfer-siz", require_arg, 'X' },
+ { "max-xfer-si", require_arg, 'X' },
+ { "max-xfer-s", require_arg, 'X' },
+ { "max-xfer", require_arg, 'X' },
+ { "max-xfe", require_arg, 'X' },
+ { "max-xf", require_arg, 'X' },
+ { "max-x", require_arg, 'X' },
+ { "min-xfer-size", require_arg, 'x' },
+ { "min-xfer-siz", require_arg, 'x' },
+ { "min-xfer-si", require_arg, 'x' },
+ { "min-xfer-s", require_arg, 'x' },
+ { "min-xfer", require_arg, 'x' },
+ { "min-xfe", require_arg, 'x' },
+ { "min-xf", require_arg, 'x' },
+ { "min-x", require_arg, 'x' },
+ { "num-bytes", require_arg, 'e' },
+ { "num-byte", require_arg, 'e' },
+ { "num-byt", require_arg, 'e' },
+ { "num-by", require_arg, 'e' },
+ { "num-b", require_arg, 'e' },
+ { "num-dsets", require_arg, 'd' },
+ { "num-dset", require_arg, 'd' },
+ { "num-dse", require_arg, 'd' },
+ { "num-ds", require_arg, 'd' },
+ { "num-d", require_arg, 'd' },
+ { "num-files", require_arg, 'F' },
+ { "num-file", require_arg, 'F' },
+ { "num-fil", require_arg, 'F' },
+ { "num-fi", require_arg, 'F' },
+ { "num-f", require_arg, 'F' },
+ { "num-iterations", require_arg, 'i' },
+ { "num-iteration", require_arg, 'i' },
+ { "num-iteratio", require_arg, 'i' },
+ { "num-iterati", require_arg, 'i' },
+ { "num-iterat", require_arg, 'i' },
+ { "num-itera", require_arg, 'i' },
+ { "num-iter", require_arg, 'i' },
+ { "num-ite", require_arg, 'i' },
+ { "num-it", require_arg, 'i' },
+ { "num-i", require_arg, 'i' },
+ { "order", require_arg, 'r' },
+ { "orde", require_arg, 'r' },
+ { "ord", require_arg, 'r' },
+ { "or", require_arg, 'r' },
+ { "output", require_arg, 'o' },
+ { "outpu", require_arg, 'o' },
+ { "outp", require_arg, 'o' },
+ { "out", require_arg, 'o' },
+ { "ou", require_arg, 'o' },
+ { "extendable", no_arg, 't' },
+ { "extendabl", no_arg, 't' },
+ { "extendab", no_arg, 't' },
+ { "extenda", no_arg, 't' },
+ { "extend", no_arg, 't' },
+ { "exten", no_arg, 't' },
+ { "exte", no_arg, 't' },
+ { "ext", no_arg, 't' },
+ { "ex", no_arg, 't' },
+ { "threshold", require_arg, 'T' },
+ { "threshol", require_arg, 'T' },
+ { "thresho", require_arg, 'T' },
+ { "thresh", require_arg, 'T' },
+ { "thres", require_arg, 'T' },
+ { "thre", require_arg, 'T' },
+ { "thr", require_arg, 'T' },
+ { "th", require_arg, 'T' },
+ { "write-only", require_arg, 'w' },
+ { "write-onl", require_arg, 'w' },
+ { "write-on", require_arg, 'w' },
+ { "write-o", require_arg, 'w' },
+ { "write", require_arg, 'w' },
+ { "writ", require_arg, 'w' },
+ { "wri", require_arg, 'w' },
+ { "wr", require_arg, 'w' },
+ { NULL, 0, '\0' }
+};
+
+struct options {
+ long io_types; /* bitmask of which I/O types to test */
+ const char *output_file; /* file to print report to */
+ long num_dsets; /* number of datasets */
+ long num_files; /* number of files */
+ off_t num_bpp; /* number of bytes per proc per dset */
+ int num_iters; /* number of iterations */
+ off_t dset_size[MAX_DIMS]; /* Dataset size */
+ size_t buf_size[MAX_DIMS]; /* Buffer size */
+ size_t chk_size[MAX_DIMS]; /* Chunk size */
+ int order[MAX_DIMS]; /* Dimension access order */
+ int dset_rank; /* Rank */
+ int buf_rank; /* Rank */
+ int order_rank; /* Rank */
+ int chk_rank; /* Rank */
+ int print_times; /* print times as well as throughputs */
+ int print_raw; /* print raw data throughput info */
+ off_t h5_alignment; /* alignment in HDF5 file */
+ off_t h5_threshold; /* threshold for alignment in HDF5 file */
+ int h5_use_chunks; /* Make HDF5 dataset chunked */
+ int h5_write_only; /* Perform the write tests only */
+ int h5_extendable; /* Perform the write tests only */
+ int verify; /* Verify data correctness */
+ vfdtype vfd; /* File driver */
+
+};
+
+typedef struct _minmax {
+ double min;
+ double max;
+ double sum;
+ int num;
+} minmax;
+
+/* local functions */
+static off_t parse_size_directive(const char *size);
+static struct options *parse_command_line(int argc, char *argv[]);
+static void run_test_loop(struct options *options);
+static int run_test(iotype iot, parameters parms, struct options *opts);
+static void output_all_info(minmax *mm, int count, int indent_level);
+static void get_minmax(minmax *mm, double val);
+static minmax accumulate_minmax_stuff(minmax *mm, int count);
+static void output_results(const struct options *options, const char *name,
+ minmax *table, int table_size, off_t data_size);
+static void output_report(const char *fmt, ...);
+static void print_indent(register int indent);
+static void usage(const char *prog);
+static void report_parameters(struct options *opts);
+
+/*
+ * Function: main
+ * Purpose: Start things up.
+ * Return: EXIT_SUCCESS or EXIT_FAILURE
+ * Programmer: Bill Wendling, 30. October 2001
+ * Modifications:
+ */
+int
+main(int argc, char **argv)
+{
+ int exit_value = EXIT_SUCCESS;
+ struct options *opts = NULL;
+
+#ifndef STANDALONE
+ /* Initialize h5tools lib */
+ h5tools_init();
+#endif
+
+ output = stdout;
+
+ opts = parse_command_line(argc, argv);
+
+ if (!opts) {
+ exit_value = EXIT_FAILURE;
+ goto finish;
+ }
+
+ if (opts->output_file) {
+ if ((output = HDfopen(opts->output_file, "w")) == NULL) {
+ fprintf(stderr, "%s: cannot open output file\n", progname);
+ perror(opts->output_file);
+ goto finish;
+ }
+ }
+
+ report_parameters(opts);
+
+ run_test_loop(opts);
+
+finish:
+ free(opts);
+ return exit_value;
+}
+
+/*
+ * Function: run_test_loop
+ * Purpose: Run the I/O tests. Write the results to OUTPUT.
+ *
+ * - The slowest changing part of the test is the number of
+ * processors to use. For each loop iteration, we divide that
+ * number by 2 and rerun the test.
+ *
+ * - The second slowest is what type of IO API to perform. We have
+ * three choices: POSIXIO, and HDF5.
+ *
+ * - Then we change the size of the buffer. This information is
+ * inferred from the number of datasets to create and the number
+ * of integers to put into each dataset. The backend code figures
+ * this out.
+ *
+ * Return: Nothing
+ * Programmer: Bill Wendling, 30. October 2001
+ * Modifications:
+ * Added multidimensional testing (Christian Chilan, April, 2008)
+ */
+static void
+run_test_loop(struct options *opts)
+{
+ parameters parms;
+ int i;
+ size_t buf_bytes;
+ /* load options into parameter structure */
+ parms.num_files = opts->num_files;
+ parms.num_dsets = opts->num_dsets;
+ parms.num_iters = opts->num_iters;
+ parms.rank = opts->dset_rank;
+ parms.h5_align = opts->h5_alignment;
+ parms.h5_thresh = opts->h5_threshold;
+ parms.h5_use_chunks = opts->h5_use_chunks;
+ parms.h5_extendable = opts->h5_extendable;
+ parms.h5_write_only = opts->h5_write_only;
+ parms.verify = opts->verify;
+ parms.vfd = opts->vfd;
+
+ /* load multidimensional options */
+ parms.num_bytes = 1;
+ buf_bytes = 1;
+ for (i=0; i<parms.rank; i++){
+ parms.buf_size[i] = opts->buf_size[i];
+ parms.dset_size[i] = opts->dset_size[i];
+ parms.chk_size[i] = opts->chk_size[i];
+ parms.order[i] = opts->order[i];
+ parms.num_bytes *= opts->dset_size[i];
+ buf_bytes *= opts->buf_size[i];
+ }
+
+ /* print size information */
+ output_report("Transfer Buffer Size (bytes): %d\n", buf_bytes);
+ output_report("File Size(MB): %.2f\n",((double)parms.num_bytes) / ONE_MB);
+
+ print_indent(0);
+ if (opts->io_types & SIO_POSIX)
+ run_test(POSIXIO, parms, opts);
+
+ print_indent(0);
+ if (opts->io_types & SIO_HDF5)
+ run_test(HDF5, parms, opts);
+}
+
+/*
+ * Function: run_test
+ * Purpose: Inner loop call to actually run the I/O test.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 18. December 2001
+ * Modifications:
+ */
+static int
+run_test(iotype iot, parameters parms, struct options *opts)
+{
+ results res;
+ register int i, ret_value = SUCCESS;
+ off_t raw_size;
+ minmax *write_sys_mm_table=NULL;
+ minmax *write_mm_table=NULL;
+ minmax *write_gross_mm_table=NULL;
+ minmax *write_raw_mm_table=NULL;
+ minmax *read_sys_mm_table=NULL;
+ minmax *read_mm_table=NULL;
+ minmax *read_gross_mm_table=NULL;
+ minmax *read_raw_mm_table=NULL;
+ minmax write_sys_mm = {0.0, 0.0, 0.0, 0};
+ minmax write_mm = {0.0, 0.0, 0.0, 0};
+ minmax write_gross_mm = {0.0, 0.0, 0.0, 0};
+ minmax write_raw_mm = {0.0, 0.0, 0.0, 0};
+ minmax read_sys_mm = {0.0, 0.0, 0.0, 0};
+ minmax read_mm = {0.0, 0.0, 0.0, 0};
+ minmax read_gross_mm = {0.0, 0.0, 0.0, 0};
+ minmax read_raw_mm = {0.0, 0.0, 0.0, 0};
+
+ raw_size = (off_t)parms.num_bytes;
+ parms.io_type = iot;
+ print_indent(2);
+ output_report("IO API = ");
+
+ switch (iot) {
+ case POSIXIO:
+ output_report("POSIX\n");
+ break;
+ case HDF5:
+ output_report("HDF5\n");
+ break;
+ default:
+ /* unknown request */
+ HDfprintf(stderr, "Unknown IO type request (%d)\n", (int)iot);
+ HDassert(0 && "Unknown IO tpe");
+ break;
+ }
+
+ /* allocate space for tables minmax and that it is sufficient */
+ /* to initialize all elements to zeros by calloc. */
+ write_sys_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ write_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ write_gross_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ write_raw_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+
+ if (!parms.h5_write_only) {
+ read_sys_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ read_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ read_gross_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ read_raw_mm_table = calloc((size_t)parms.num_iters , sizeof(minmax));
+ }
+
+ /* Do IO iteration times, collecting statistics each time */
+ for (i = 0; i < parms.num_iters; ++i) {
+ double t;
+ res = do_sio(parms);
+
+ /* gather all of the "sys write" times */
+ t = get_time(res.timers, HDF5_MPI_WRITE);
+ get_minmax(&write_sys_mm, t);
+
+ write_sys_mm_table[i] = write_sys_mm;
+
+ /* gather all of the "write" times */
+ t = get_time(res.timers, HDF5_FINE_WRITE_FIXED_DIMS);
+ get_minmax(&write_mm, t);
+
+ write_mm_table[i] = write_mm;
+
+ /* gather all of the "write" times from open to close */
+ t = get_time(res.timers, HDF5_GROSS_WRITE_FIXED_DIMS);
+ get_minmax(&write_gross_mm, t);
+
+ write_gross_mm_table[i] = write_gross_mm;
+
+ /* gather all of the raw "write" times */
+ t = get_time(res.timers, HDF5_RAW_WRITE_FIXED_DIMS);
+ get_minmax(&write_raw_mm, t);
+
+ write_raw_mm_table[i] = write_raw_mm;
+
+ if (!parms.h5_write_only) {
+ /* gather all of the "mpi read" times */
+ t = get_time(res.timers, HDF5_MPI_READ);
+ get_minmax(&read_sys_mm, t);
+
+ read_sys_mm_table[i] = read_sys_mm;
+
+ /* gather all of the "read" times */
+ t = get_time(res.timers, HDF5_FINE_READ_FIXED_DIMS);
+ get_minmax(&read_mm, t);
+
+ read_mm_table[i] = read_mm;
+
+ /* gather all of the "read" times from open to close */
+ t = get_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS);
+ get_minmax(&read_gross_mm, t);
+
+ read_gross_mm_table[i] = read_gross_mm;
+
+ /* gather all of the raw "read" times */
+ t = get_time(res.timers, HDF5_RAW_READ_FIXED_DIMS);
+ get_minmax(&read_raw_mm, t);
+
+ read_raw_mm_table[i] = read_gross_mm;
+ }
+ sio_time_destroy(res.timers);
+ }
+
+ /*
+ * Show various statistics
+ */
+ /* Write statistics */
+ /* Print the raw data throughput if desired */
+ if (opts->print_raw) {
+ /* accumulate and output the max, min, and average "raw write" times */
+ if (sio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Raw Data Write details:\n");
+ output_all_info(write_raw_mm_table, parms.num_iters, 4);
+ }
+
+ output_results(opts,"Raw Data Write",write_raw_mm_table,parms.num_iters,raw_size);
+ } /* end if */
+
+ /* show sys write statics */
+#if 0
+ if (sio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("MPI Write details:\n");
+ output_all_info(write_sys_mm_table, parms.num_iters, 4);
+ }
+#endif
+ /* We don't currently output the MPI write results */
+
+ /* accumulate and output the max, min, and average "write" times */
+ if (sio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Write details:\n");
+ output_all_info(write_mm_table, parms.num_iters, 4);
+ }
+
+ output_results(opts,"Write",write_mm_table,parms.num_iters,raw_size);
+
+ /* accumulate and output the max, min, and average "gross write" times */
+ if (sio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Write Open-Close details:\n");
+ output_all_info(write_gross_mm_table, parms.num_iters, 4);
+ }
+
+ output_results(opts,"Write Open-Close",write_gross_mm_table,parms.num_iters,raw_size);
+
+ if (!parms.h5_write_only) {
+ /* Read statistics */
+ /* Print the raw data throughput if desired */
+ if (opts->print_raw) {
+ /* accumulate and output the max, min, and average "raw read" times */
+ if (sio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Raw Data Read details:\n");
+ output_all_info(read_raw_mm_table, parms.num_iters, 4);
+ }
+
+ output_results(opts, "Raw Data Read", read_raw_mm_table,
+ parms.num_iters, raw_size);
+ } /* end if */
+
+ /* show mpi read statics */
+#if 0
+ if (sio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("MPI Read details:\n");
+ output_all_info(read_sys_mm_table, parms.num_iters, 4);
+ }
+#endif
+ /* We don't currently output the MPI read results */
+
+ /* accumulate and output the max, min, and average "read" times */
+ if (sio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Read details:\n");
+ output_all_info(read_mm_table, parms.num_iters, 4);
+ }
+
+ output_results(opts, "Read", read_mm_table, parms.num_iters, raw_size);
+
+ /* accumulate and output the max, min, and average "gross read" times */
+ if (sio_debug_level >= 3) {
+ /* output all of the times for all iterations */
+ print_indent(3);
+ output_report("Read Open-Close details:\n");
+ output_all_info(read_gross_mm_table, parms.num_iters, 4);
+ }
+
+ output_results(opts, "Read Open-Close", read_gross_mm_table,
+ parms.num_iters, raw_size);
+ }
+
+ /* clean up our mess */
+ free(write_sys_mm_table);
+ free(write_mm_table);
+ free(write_gross_mm_table);
+ free(write_raw_mm_table);
+
+ if (!parms.h5_write_only) {
+ free(read_sys_mm_table);
+ free(read_mm_table);
+ free(read_gross_mm_table);
+ free(read_raw_mm_table);
+ }
+
+ return ret_value;
+}
+
+/*
+ * Function: output_all_info
+ * Purpose:
+ * Return: Nothing
+ * Programmer: Bill Wendling, 29. January 2002
+ * Modifications:
+ */
+static void
+output_all_info(minmax *mm, int count, int indent_level)
+{
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ print_indent(indent_level);
+ output_report("Iteration %d:\n", i + 1);
+ print_indent(indent_level + 1);
+ output_report("Minimum Time: %.2fs\n", mm[i].min);
+ print_indent(indent_level + 1);
+ output_report("Maximum Time: %.2fs\n", mm[i].max);
+ }
+}
+
+/*
+ * Function: get_minmax
+ * Purpose: Gather all the min, max and total of val.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 21. December 2001
+ * Modifications:
+ * Use MPI_Allreduce to do it. -akc, 2002/01/11
+ */
+
+static void
+get_minmax(minmax *mm, double val)
+{
+ mm->max = val;
+ mm->min = val;
+ mm->sum = val;
+}
+
+/*
+ * Function: accumulate_minmax_stuff
+ * Purpose: Accumulate the minimum, maximum, and average of the times
+ * across all processes.
+ * Return: TOTAL_MM - the total of all of these.
+ * Programmer: Bill Wendling, 21. December 2001
+ * Modifications:
+ * Changed to use seconds instead of MB/s - QAK, 5/9/02
+ */
+static minmax
+accumulate_minmax_stuff(minmax *mm, int count)
+{
+ int i;
+ minmax total_mm;
+
+ total_mm.sum = 0.0;
+ total_mm.max = -DBL_MAX;
+ total_mm.min = DBL_MAX;
+ total_mm.num = count;
+
+ for (i = 0; i < count; ++i) {
+ double m = mm[i].max;
+
+ total_mm.sum += m;
+
+ if (m < total_mm.min)
+ total_mm.min = m;
+
+ if (m > total_mm.max)
+ total_mm.max = m;
+ }
+
+ return total_mm;
+}
+
+
+/*
+ * Function: output_results
+ * Purpose: Print information about the time & bandwidth for a given
+ * minmax & # of iterations.
+ * Return: Nothing
+ * Programmer: Quincey Koziol, 9. May 2002
+ * Modifications:
+ */
+static void
+output_results(const struct options *opts, const char *name, minmax *table,
+ int table_size,off_t data_size)
+{
+ minmax total_mm;
+
+ total_mm = accumulate_minmax_stuff(table, table_size);
+
+ print_indent(3);
+ output_report("%s (%d iteration(s)):\n", name,table_size);
+
+ /* Note: The maximum throughput uses the minimum amount of time & vice versa */
+
+ print_indent(4);
+ output_report("Maximum Throughput: %6.2f MB/s", MB_PER_SEC(data_size,total_mm.min));
+ if(opts->print_times)
+ output_report(" (%7.3f s)\n", total_mm.min);
+ else
+ output_report("\n");
+
+ print_indent(4);
+ output_report("Average Throughput: %6.2f MB/s",
+ MB_PER_SEC(data_size,total_mm.sum / total_mm.num));
+ if(opts->print_times)
+ output_report(" (%7.3f s)\n", (total_mm.sum / total_mm.num));
+ else
+ output_report("\n");
+
+ print_indent(4);
+ output_report("Minimum Throughput: %6.2f MB/s", MB_PER_SEC(data_size,total_mm.max));
+ if(opts->print_times)
+ output_report(" (%7.3f s)\n", total_mm.max);
+ else
+ output_report("\n");
+}
+
+/*
+ * Function: output_report
+ * Purpose: Print a line of the report. Only do so if I'm the 0 process.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 19. December 2001
+ * Modifications:
+ */
+static void
+output_report(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(output, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Function: print_indent
+ * Purpose: Print spaces to indent a new line of text for pretty printing
+ * things.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 29. October 2001
+ * Modifications:
+ */
+static void
+print_indent(register int indent)
+{
+ indent *= TAB_SPACE;
+
+ for (; indent > 0; --indent)
+ fputc(' ', output);
+}
+
+static void
+recover_size_and_print(long long val, const char *end)
+{
+ if (val >= ONE_KB && (val % ONE_KB) == 0) {
+ if (val >= ONE_MB && (val % ONE_MB) == 0) {
+ if (val >= ONE_GB && (val % ONE_GB) == 0)
+ HDfprintf(output, "%" H5_PRINTF_LL_WIDTH "d""GB%s", val / ONE_GB, end);
+ else
+ HDfprintf(output, "%" H5_PRINTF_LL_WIDTH "d""MB%s", val / ONE_MB, end);
+ } else {
+ HDfprintf(output, "%" H5_PRINTF_LL_WIDTH "d""KB%s", val / ONE_KB, end);
+ }
+ } else {
+ HDfprintf(output, "%" H5_PRINTF_LL_WIDTH "d""%s", val, end);
+ }
+}
+
+static void
+print_io_api(long io_types)
+{
+ if (io_types & SIO_POSIX)
+ HDfprintf(output, "posix ");
+ if (io_types & SIO_HDF5)
+ HDfprintf(output, "hdf5 ");
+ HDfprintf(output, "\n");
+}
+
+static void
+report_parameters(struct options *opts)
+{
+ int i, rank;
+ rank = opts->dset_rank;
+
+ print_version("HDF5 Library"); /* print library version */
+ HDfprintf(output, "==== Parameters ====\n");
+
+ HDfprintf(output, "IO API=");
+ print_io_api(opts->io_types);
+
+ HDfprintf(output, "Number of iterations=%d\n",
+ opts->num_iters);
+
+ HDfprintf(output, "Dataset size=");
+
+ for (i=0; i<rank; i++)
+ recover_size_and_print((long long)opts->dset_size[i], " ");
+ HDfprintf(output, "\n");
+
+
+ HDfprintf(output, "Transfer buffer size=");
+ for (i=0; i<rank; i++)
+ recover_size_and_print((long long)opts->buf_size[i], " ");
+ HDfprintf(output, "\n");
+
+ HDfprintf(output, "Dimension access order=");
+ for (i=0; i<rank; i++)
+ recover_size_and_print((long long)opts->order[i], " ");
+ HDfprintf(output, "\n");
+
+ if (opts->io_types & SIO_HDF5) {
+
+ HDfprintf(output, "HDF5 data storage method=");
+
+ if (opts->h5_use_chunks){
+
+ HDfprintf(output, "Chunked\n");
+ HDfprintf(output, "HDF5 chunk size=");
+ for (i=0; i<rank; i++)
+ recover_size_and_print((long long)opts->chk_size[i], " ");
+ HDfprintf(output, "\n");
+
+ HDfprintf(output, "HDF5 dataset dimensions=");
+ if (opts->h5_extendable) {
+ HDfprintf(output, "Extendable\n");
+ }
+ else {
+ HDfprintf(output, "Fixed\n");
+ }
+ }
+ else {
+ HDfprintf(output, "Contiguous\n");
+ }
+
+ HDfprintf(output, "HDF5 file driver=");
+ if (opts->vfd==sec2) {
+ HDfprintf(output, "sec2\n");
+ } else if (opts->vfd==stdio) {
+ HDfprintf(output, "stdio\n");
+ } else if (opts->vfd==core) {
+ HDfprintf(output, "core\n");
+ } else if (opts->vfd==split) {
+ HDfprintf(output, "split\n");
+ } else if (opts->vfd==multi) {
+ HDfprintf(output, "multi\n");
+ } else if (opts->vfd==family) {
+ HDfprintf(output, "family\n");
+ } else if (opts->vfd==direct) {
+ HDfprintf(output, "direct\n");
+ }
+ }
+
+ {
+ char *prefix = HDgetenv("HDF5_PREFIX");
+
+ HDfprintf(output, "Env HDF5_PREFIX=%s\n",
+ (prefix ? prefix : "not set"));
+ }
+
+ HDfprintf(output, "==== End of Parameters ====\n");
+ HDfprintf(output, "\n");
+}
+
+/*
+ * Function: parse_command_line
+ * Purpose: Parse the command line options and return a STRUCT OPTIONS
+ * structure which will need to be freed by the calling function.
+ * Return: Pointer to an OPTIONS structure
+ * Programmer: Bill Wendling, 31. October 2001
+ * Modifications:
+ * Added multidimensional testing (Christian Chilan, April, 2008)
+ */
+static struct options *
+parse_command_line(int argc, char *argv[])
+{
+ register int opt;
+ struct options *cl_opts;
+ int i, default_rank, actual_rank, ranks[4];
+ cl_opts = (struct options *)malloc(sizeof(struct options));
+
+ cl_opts->output_file = NULL;
+ cl_opts->io_types = 0; /* will set default after parsing options */
+ cl_opts->num_iters = 1;
+
+ default_rank = 2;
+
+ cl_opts->dset_rank = 0;
+ cl_opts->buf_rank = 0;
+ cl_opts->chk_rank = 0;
+ cl_opts->order_rank = 0;
+
+ for (i=0; i<MAX_DIMS; i++){
+ cl_opts->buf_size[i]=(i+1)*10;
+ cl_opts->dset_size[i]=(i+1)*100;
+ cl_opts->chk_size[i]=(i+1)*10;
+ cl_opts->order[i]=i+1;
+ }
+
+ cl_opts->vfd = sec2;
+
+ cl_opts->print_times = FALSE; /* Printing times is off by default */
+ cl_opts->print_raw = FALSE; /* Printing raw data throughput is off by default */
+ cl_opts->h5_alignment = 1; /* No alignment for HDF5 objects by default */
+ cl_opts->h5_threshold = 1; /* No threshold for aligning HDF5 objects by default */
+ cl_opts->h5_use_chunks = FALSE; /* Don't chunk the HDF5 dataset by default */
+ cl_opts->h5_write_only = FALSE; /* Do both read and write by default */
+ cl_opts->h5_extendable = FALSE; /* Use extendable dataset */
+ cl_opts->verify = FALSE; /* No Verify data correctness by default */
+
+ while ((opt = get_option(argc, (const char **)argv, s_opts, l_opts)) != EOF) {
+ switch ((char)opt) {
+ case 'a':
+ cl_opts->h5_alignment = parse_size_directive(opt_arg);
+ break;
+ case 'A':
+ {
+ const char *end = opt_arg;
+ while (end && *end != '\0') {
+ char buf[10];
+
+ memset(buf, '\0', sizeof(buf));
+
+ for (i = 0; *end != '\0' && *end != ','; ++end)
+ if (isalnum(*end) && i < 10)
+ buf[i++] = *end;
+
+ if (!HDstrcasecmp(buf, "hdf5")) {
+ cl_opts->io_types |= SIO_HDF5;
+ } else if (!HDstrcasecmp(buf, "posix")) {
+ cl_opts->io_types |= SIO_POSIX;
+ } else {
+ fprintf(stderr, "sio_perf: invalid --api option %s\n",
+ buf);
+ exit(EXIT_FAILURE);
+ }
+
+ if (*end == '\0')
+ break;
+
+ end++;
+ }
+ }
+
+ break;
+#if 0
+ case 'b':
+ /* the future "binary" option */
+ break;
+#endif /* 0 */
+ case 'c':
+ /* Turn on chunked HDF5 dataset creation */
+ cl_opts->h5_use_chunks = 1;
+ {
+ const char *end = opt_arg;
+ int j = 0;
+
+ while (end && *end != '\0') {
+ char buf[10];
+
+ memset(buf, '\0', sizeof(buf));
+
+ for (i = 0; *end != '\0' && *end != ','; ++end)
+ if (isalnum(*end) && i < 10)
+ buf[i++] = *end;
+
+ cl_opts->chk_size[j] = parse_size_directive(buf);
+
+ j++;
+
+ if (*end == '\0')
+ break;
+
+ end++;
+ }
+ cl_opts->chk_rank = j;
+ }
+
+ break;
+
+
+ case 'D':
+ {
+ const char *end = opt_arg;
+
+ while (end && *end != '\0') {
+ char buf[10];
+
+ memset(buf, '\0', sizeof(buf));
+
+ for (i = 0; *end != '\0' && *end != ','; ++end)
+ if (isalnum(*end) && i < 10)
+ buf[i++] = *end;
+
+ if (strlen(buf) > 1 || isdigit(buf[0])) {
+ size_t j;
+
+ for (j = 0; j < 10 && buf[j] != '\0'; ++j)
+ if (!isdigit(buf[j])) {
+ fprintf(stderr, "sio_perf: invalid --debug option %s\n",
+ buf);
+ exit(EXIT_FAILURE);
+ }
+
+ sio_debug_level = atoi(buf);
+
+ if (sio_debug_level > 4)
+ sio_debug_level = 4;
+ else if (sio_debug_level < 0)
+ sio_debug_level = 0;
+ } else {
+ switch (*buf) {
+ case 'r':
+ /* Turn on raw data throughput info */
+ cl_opts->print_raw = TRUE;
+ break;
+ case 't':
+ /* Turn on time printing */
+ cl_opts->print_times = TRUE;
+ break;
+ case 'v':
+ /* Turn on verify data correctness*/
+ cl_opts->verify = TRUE;
+ break;
+ default:
+ fprintf(stderr, "sio_perf: invalid --debug option %s\n", buf);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (*end == '\0')
+ break;
+
+ end++;
+ }
+ }
+
+ break;
+ case 'e':
+ {
+ const char *end = opt_arg;
+ int j = 0;
+
+ while (end && *end != '\0') {
+ char buf[10];
+
+ memset(buf, '\0', sizeof(buf));
+
+ for (i = 0; *end != '\0' && *end != ','; ++end)
+ if (isalnum(*end) && i < 10)
+ buf[i++] = *end;
+
+ cl_opts->dset_size[j] = parse_size_directive(buf);
+
+ j++;
+
+ if (*end == '\0')
+ break;
+
+ end++;
+ }
+ cl_opts->dset_rank = j;
+ }
+
+ break;
+
+ case 'i':
+ cl_opts->num_iters = atoi(opt_arg);
+ break;
+ case 'o':
+ cl_opts->output_file = opt_arg;
+ break;
+ case 'T':
+ cl_opts->h5_threshold = parse_size_directive(opt_arg);
+ break;
+ case 'v':
+ if (!HDstrcasecmp(opt_arg, "sec2")) {
+ cl_opts->vfd=sec2;
+ } else if (!HDstrcasecmp(opt_arg, "stdio")) {
+ cl_opts->vfd=stdio;
+ } else if (!HDstrcasecmp(opt_arg, "core")) {
+ cl_opts->vfd=core;
+ } else if (!HDstrcasecmp(opt_arg, "split")) {
+ cl_opts->vfd=split;
+ } else if (!HDstrcasecmp(opt_arg, "multi")) {
+ cl_opts->vfd=multi;
+ } else if (!HDstrcasecmp(opt_arg, "family")) {
+ cl_opts->vfd=family;
+ } else if (!HDstrcasecmp(opt_arg, "direct")) {
+ cl_opts->vfd=direct;
+ } else {
+ fprintf(stderr, "sio_perf: invalid --api option %s\n",
+ opt_arg);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'w':
+ cl_opts->h5_write_only = TRUE;
+ break;
+ case 't':
+ cl_opts->h5_extendable = TRUE;
+ break;
+ case 'x':
+ {
+ const char *end = opt_arg;
+ int j = 0;
+
+ while (end && *end != '\0') {
+ char buf[10];
+
+ memset(buf, '\0', sizeof(buf));
+
+ for (i = 0; *end != '\0' && *end != ','; ++end)
+ if (isalnum(*end) && i < 10)
+ buf[i++] = *end;
+
+ cl_opts->buf_size[j] = parse_size_directive(buf);
+
+ j++;
+
+ if (*end == '\0')
+ break;
+
+ end++;
+ }
+ cl_opts->buf_rank = j;
+ }
+
+ break;
+
+ case 'r':
+ {
+ const char *end = opt_arg;
+ int j = 0;
+
+ while (end && *end != '\0') {
+ char buf[10];
+
+ memset(buf, '\0', sizeof(buf));
+
+ for (i = 0; *end != '\0' && *end != ','; ++end)
+ if (isalnum(*end) && i < 10)
+ buf[i++] = *end;
+
+ cl_opts->order[j] = parse_size_directive(buf);
+
+ j++;
+
+ if (*end == '\0')
+ break;
+
+ end++;
+ }
+
+ cl_opts->order_rank = j;
+ }
+
+ break;
+
+ case 'h':
+ case '?':
+ default:
+ usage(progname);
+ free(cl_opts);
+ return NULL;
+ }
+ }
+
+ /* perform rank consistency analysis */
+ actual_rank = 0;
+
+ ranks[0] = cl_opts->dset_rank;
+ ranks[1] = cl_opts->buf_rank;
+ ranks[2] = cl_opts->order_rank;
+ ranks[3] = cl_opts->chk_rank;
+
+ for (i=0; i<4; i++) {
+ if (ranks[i]>0) {
+ if (!actual_rank) {
+ actual_rank = ranks[i];
+ }
+ else {
+ if (actual_rank != ranks[i])
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+
+ if (!actual_rank)
+ actual_rank = default_rank;
+
+ cl_opts->dset_rank = actual_rank;
+ cl_opts->buf_rank = actual_rank;
+ cl_opts->order_rank = actual_rank;
+ cl_opts->chk_rank = actual_rank;
+
+ for (i=0; i<actual_rank; i++) {
+ if (cl_opts->order[i] > actual_rank) {
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* set default if none specified yet */
+ if (!cl_opts->io_types)
+ cl_opts->io_types = SIO_HDF5 | SIO_POSIX; /* run all API */
+
+ /* verify parameters sanity. Adjust if needed. */
+ /* cap xfer_size with bytes per process */
+ if (cl_opts->num_iters <= 0)
+ cl_opts->num_iters = 1;
+
+ return cl_opts;
+}
+
+/*
+ * Function: parse_size_directive
+ * Purpose: Parse the size directive passed on the commandline. The size
+ * directive is an integer followed by a size indicator:
+ *
+ * K, k - Kilobyte
+ * M, m - Megabyte
+ * G, g - Gigabyte
+ *
+ * Return: The size as a off_t because this is related to file size.
+ * If an unknown size indicator is used, then the program will
+ * exit with EXIT_FAILURE as the return value.
+ * Programmer: Bill Wendling, 18. December 2001
+ * Modifications:
+ */
+
+static off_t
+parse_size_directive(const char *size)
+{
+ off_t s;
+ char *endptr;
+
+ s = strtol(size, &endptr, 10);
+
+ if (endptr && *endptr) {
+ while (*endptr != '\0' && (*endptr == ' ' || *endptr == '\t'))
+ ++endptr;
+
+ switch (*endptr) {
+ case 'K':
+ case 'k':
+ s *= ONE_KB;
+ break;
+ case 'M':
+ case 'm':
+ s *= ONE_MB;
+ break;
+ case 'G':
+ case 'g':
+ s *= ONE_GB;
+ break;
+ default:
+ fprintf(stderr, "Illegal size specifier '%c'\n", *endptr);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ return s;
+}
+
+/*
+ * Function: usage
+ * Purpose: Print a usage message and then exit.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 31. October 2001
+ * Modifications:
+ */
+static void
+usage(const char *prog)
+{
+ print_version(prog);
+ printf("usage: %s [OPTIONS]\n", prog);
+ printf(" OPTIONS\n");
+ printf(" -h Print an usage message and exit\n");
+ printf(" -A AL Which APIs to test\n");
+ printf(" [default: all of them]\n");
+ printf(" -c SL Selects chunked storage and defines chunks dimensions\n");
+ printf(" and sizes\n");
+ printf(" [default: Off]\n");
+ printf(" -e SL Dimensions and sizes of dataset\n");
+ printf(" [default: 100,200]\n");
+ printf(" -i N Number of iterations to perform\n");
+ printf(" [default: 1]\n");
+ printf(" -r NL Dimension access order (see below for description)\n");
+ printf(" [default: 1,2]\n");
+ printf(" -t Selects extendable dimensions for HDF5 dataset\n");
+ printf(" [default: Off]\n");
+ printf(" -v VFD Selects file driver for HDF5 access\n");
+ printf(" [default: sec2]\n");
+ printf(" -w Perform write tests, not the read tests\n");
+ printf(" [default: Off]\n");
+ printf(" -x SL Dimensions and sizes of the transfer buffer\n");
+ printf(" [default: 10,20]\n");
+ printf("\n");
+ printf(" N - is an integer > 0.\n");
+ printf("\n");
+ printf(" S - is a size specifier, an integer > 0 followed by a size indicator:\n");
+ printf(" K - Kilobyte (%d)\n", ONE_KB);
+ printf(" M - Megabyte (%d)\n", ONE_MB);
+ printf(" G - Gigabyte (%d)\n", ONE_GB);
+ printf("\n");
+ printf(" Example: '37M' is 37 megabytes or %d bytes\n", 37*ONE_MB);
+ printf("\n");
+ printf(" AL - is an API list. Valid values are:\n");
+ printf(" hdf5 - HDF5\n");
+ printf(" posix - POSIX\n");
+ printf("\n");
+ printf(" Example: -A posix,hdf5\n");
+ printf("\n");
+ printf(" NL - is list of integers (N) separated by commas.\n");
+ printf("\n");
+ printf(" Example: 1,2,3\n");
+ printf("\n");
+ printf(" SL - is list of size specifiers (S) separated by commas.\n");
+ printf("\n");
+ printf(" Example: 2K,2K,3K\n");
+ printf("\n");
+ printf(" The example defines an object (dataset, tranfer buffer) with three\n");
+ printf(" dimensions. Be aware that as the number of dimensions increases, the\n");
+ printf(" the total size of the object increases exponentially.\n");
+ printf("\n");
+ printf(" VFD - is an HDF5 file driver specifier. Valid values are:\n");
+ printf(" sec2, stdio, core, split, multi, family, direct\n");
+ printf("\n");
+ printf(" Dimension access order:\n");
+ printf(" Data access starts at the cardinal origin of the dataset using the\n");
+ printf(" transfer buffer. The next access occurs on a dataset region next to\n");
+ printf(" the previous one. For a multidimensional dataset, there are several\n");
+ printf(" directions as to where to proceed. This can be specified in the dimension\n");
+ printf(" access order. For example, -r 1,2 states that the tool should traverse\n");
+ printf(" dimension 1 first, and then dimension 2.\n");
+ printf("\n");
+ printf(" Environment variables:\n");
+ printf(" HDF5_NOCLEANUP Do not remove data files if set [default remove]\n");
+ printf(" HDF5_PREFIX Data file prefix\n");
+ printf("\n");
+ fflush(stdout);
+}
+
diff --git a/tools/perform/sio_perf.h b/tools/perform/sio_perf.h
new file mode 100644
index 0000000..b40fed3
--- /dev/null
+++ b/tools/perform/sio_perf.h
@@ -0,0 +1,104 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef SIO_PERF_H__
+#define SIO_PERF_H__
+
+#include "sio_timer.h"
+#ifndef STANDALONE
+#include "H5private.h"
+#include "h5test.h"
+#include "h5tools.h"
+#include "h5tools_utils.h"
+#else
+#include "sio_standalone.h"
+#endif
+
+/* setup the dataset no fill option if this is v1.5 or more */
+#if H5_VERS_MAJOR > 1 || H5_VERS_MINOR > 4
+#define H5_HAVE_NOFILL 1
+#endif
+
+#define MAX_DIMS 32
+
+typedef enum iotype_ {
+ POSIXIO,
+ HDF5
+ /*NUM_TYPES*/
+} iotype;
+
+typedef enum vfdtype_ {
+ sec2,
+ stdio,
+ core,
+ split,
+ multi,
+ family,
+ direct
+ /*NUM_TYPES*/
+} vfdtype;
+
+typedef struct parameters_ {
+ iotype io_type; /* The type of IO test to perform */
+ vfdtype vfd;
+ long num_files; /* Number of files to create */
+ long num_dsets; /* Number of datasets to create */
+ off_t num_bytes; /* Number of bytes in each dset */
+ int num_iters; /* Number of times to loop doing the IO */
+ int rank; /* Rank of dataset */
+ off_t dset_size[MAX_DIMS]; /* Dataset size */
+ size_t buf_size[MAX_DIMS]; /* Buffer size */
+ size_t chk_size[MAX_DIMS]; /* Chunk size */
+ int order[MAX_DIMS]; /* Buffer size */
+ hsize_t h5_align; /* HDF5 object alignment */
+ hsize_t h5_thresh; /* HDF5 object alignment threshold */
+ int h5_use_chunks; /* Make HDF5 dataset chunked */
+ int h5_extendable; /* Make HDF5 dataset chunked */
+ int h5_write_only; /* Perform the write tests only */
+ int verify; /* Verify data correctness */
+} parameters;
+
+typedef struct results_ {
+ herr_t ret_code;
+ sio_time *timers;
+} results;
+
+#ifndef SUCCESS
+#define SUCCESS 0
+#endif /* !SUCCESS */
+
+#ifndef FAIL
+#define FAIL -1
+#endif /* !FAIL */
+
+extern FILE *output; /* output file */
+extern sio_time *timer_g; /* timer: global for stub functions */
+extern int sio_debug_level; /* The debug level:
+ * 0 - Off
+ * 1 - Minimal
+ * 2 - Some more
+ * 3 - Maximal
+ * 4 - Even More Debugging (timer stuff)
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+extern results do_sio(parameters param);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* PIO_PERF_H__ */
diff --git a/tools/perform/sio_standalone.c b/tools/perform/sio_standalone.c
new file mode 100644
index 0000000..d92ed30
--- /dev/null
+++ b/tools/perform/sio_standalone.c
@@ -0,0 +1,285 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+/* This file contains the definition of functions required to build h5perf in
+ * STANDALONE mode.
+ * Created: Christian Chilan, 2005/5/18.
+ */
+
+#include "sio_perf.h"
+
+
+/** From h5tools_utils.c **/
+
+/* global variables */
+int nCols = 80;
+
+/* ``get_option'' variables */
+int opt_err = 1; /*get_option prints errors if this is on */
+int opt_ind = 1; /*token pointer */
+const char *opt_arg; /*flag argument (or value) */
+
+
+int
+get_option(int argc, const char **argv, const char *opts, const struct long_options *l_opts)
+{
+ static int sp = 1; /* character index in current token */
+ int opt_opt = '?'; /* option character passed back to user */
+
+ if (sp == 1) {
+ /* check for more flag-like tokens */
+ if (opt_ind >= argc || argv[opt_ind][0] != '-' || argv[opt_ind][1] == '\0') {
+ return EOF;
+ } else if (HDstrcmp(argv[opt_ind], "--") == 0) {
+ opt_ind++;
+ return EOF;
+ }
+ }
+
+ if (sp == 1 && argv[opt_ind][0] == '-' && argv[opt_ind][1] == '-') {
+ /* long command line option */
+ const char *arg = &argv[opt_ind][2];
+ int i;
+
+ for (i = 0; l_opts && l_opts[i].name; i++) {
+ size_t len = HDstrlen(l_opts[i].name);
+
+ if (HDstrncmp(arg, l_opts[i].name, len) == 0) {
+ /* we've found a matching long command line flag */
+ opt_opt = l_opts[i].shortval;
+
+ if (l_opts[i].has_arg != no_arg) {
+ if (arg[len] == '=') {
+ opt_arg = &arg[len + 1];
+ } else if (opt_ind < (argc - 1) && argv[opt_ind + 1][0] != '-') {
+ opt_arg = argv[++opt_ind];
+ } else if (l_opts[i].has_arg == require_arg) {
+ if (opt_err)
+ HDfprintf(stderr,
+ "%s: option required for \"--%s\" flag\n",
+ argv[0], arg);
+
+ opt_opt = '?';
+ }
+ } else {
+ if (arg[len] == '=') {
+ if (opt_err)
+ HDfprintf(stderr,
+ "%s: no option required for \"%s\" flag\n",
+ argv[0], arg);
+
+ opt_opt = '?';
+ }
+
+ opt_arg = NULL;
+ }
+
+ break;
+ }
+ }
+
+ if (l_opts[i].name == NULL) {
+ /* exhausted all of the l_opts we have and still didn't match */
+ if (opt_err)
+ HDfprintf(stderr, "%s: unknown option \"%s\"\n", argv[0], arg);
+
+ opt_opt = '?';
+ }
+
+ opt_ind++;
+ sp = 1;
+ } else {
+ register char *cp; /* pointer into current token */
+
+ /* short command line option */
+ opt_opt = argv[opt_ind][sp];
+
+ if (opt_opt == ':' || (cp = strchr(opts, opt_opt)) == 0) {
+
+ if (opt_err)
+ HDfprintf(stderr, "%s: unknown option \"%c\"\n",
+ argv[0], opt_opt);
+
+ /* if no chars left in this token, move to next token */
+ if (argv[opt_ind][++sp] == '\0') {
+ opt_ind++;
+ sp = 1;
+ }
+
+ return '?';
+ }
+
+ if (*++cp == ':') {
+ /* if a value is expected, get it */
+ if (argv[opt_ind][sp + 1] != '\0') {
+ /* flag value is rest of current token */
+ opt_arg = &argv[opt_ind++][sp + 1];
+ } else if (++opt_ind >= argc) {
+ if (opt_err)
+ HDfprintf(stderr,
+ "%s: value expected for option \"%c\"\n",
+ argv[0], opt_opt);
+
+ opt_opt = '?';
+ } else {
+ /* flag value is next token */
+ opt_arg = argv[opt_ind++];
+ }
+
+ sp = 1;
+ } else {
+ /* set up to look at next char in token, next time */
+ if (argv[opt_ind][++sp] == '\0') {
+ /* no more in current token, so setup next token */
+ opt_ind++;
+ sp = 1;
+ }
+
+ opt_arg = NULL;
+ }
+ }
+
+ /* return the current flag character found */
+ return opt_opt;
+}
+
+
+void
+print_version(const char *progname)
+{
+ printf("%s: Version %u.%u.%u%s%s\n",
+ progname, H5_VERS_MAJOR, H5_VERS_MINOR, H5_VERS_RELEASE,
+ H5_VERS_SUBRELEASE[0] ? "-" : "", H5_VERS_SUBRELEASE);
+}
+
+
+
+/** From h5test.c **/
+
+#ifdef H5_HAVE_PARALLEL
+MPI_Info h5_io_info_g=MPI_INFO_NULL;/* MPI INFO object for IO */
+#endif
+
+#if 0
+int
+h5_set_info_object(void)
+{
+ char *envp; /* environment pointer */
+ int ret_value=0;
+
+ /* handle any MPI INFO hints via $HDF5_MPI_INFO */
+ if ((envp = getenv("HDF5_MPI_INFO")) != NULL){
+ char *next, *valp;
+
+
+ valp = envp = next = HDstrdup(envp);
+
+ /* create an INFO object if not created yet */
+ if (h5_io_info_g == MPI_INFO_NULL)
+ MPI_Info_create(&h5_io_info_g);
+
+ do {
+ size_t len;
+ char *key_val, *endp, *namep;
+
+ if (*valp == ';')
+ valp++;
+
+ /* copy key/value pair into temporary buffer */
+ len = strcspn(valp, ";");
+ next = &valp[len];
+ key_val = calloc(1, len + 1);
+
+ /* increment the next pointer past the terminating semicolon */
+ if (*next == ';')
+ ++next;
+
+ namep = HDstrncpy(key_val, valp, len);
+
+ /* pass up any beginning whitespaces */
+ while (*namep && (*namep == ' ' || *namep == '\t'))
+ namep++;
+
+ /* eat up any ending white spaces */
+ endp = &namep[strlen(namep) - 1];
+
+ while (endp && (*endp == ' ' || *endp == '\t'))
+ *endp-- = '\0';
+
+ /* find the '=' */
+
+ valp = HDstrchr(namep, '=');
+
+ if (valp != NULL) { /* it's a valid key/value pairing */
+ char *tmp_val = valp + 1;
+
+ /* change '=' to \0, move valp down one */
+ *valp-- = '\0';
+
+ /* eat up ending whitespace on the "key" part */
+ while (*valp == ' ' || *valp == '\t')
+ *valp-- = '\0';
+
+ valp = tmp_val;
+
+ /* eat up beginning whitespace on the "value" part */
+ while (*valp == ' ' || *valp == '\t')
+ *valp++ = '\0';
+
+ /* actually set the darned thing */
+ if (MPI_SUCCESS != MPI_Info_set(h5_io_info_g, namep, valp)) {
+ printf("MPI_Info_set failed\n");
+ ret_value = -1;
+ }
+ }
+
+ valp = next;
+ HDfree(key_val);
+ } while (next && *next);
+
+ HDfree(envp);
+ }
+
+ return ret_value;
+}
+
+
+void
+h5_dump_info_object(MPI_Info info)
+{
+ char key[MPI_MAX_INFO_KEY+1];
+ char value[MPI_MAX_INFO_VAL+1];
+ int flag;
+ int i, nkeys;
+
+ printf("Dumping MPI Info Object(%d) (up to %d bytes per item):\n", (int)info,
+ MPI_MAX_INFO_VAL);
+ if (info==MPI_INFO_NULL){
+ printf("object is MPI_INFO_NULL\n");
+ }
+ else {
+ MPI_Info_get_nkeys(info, &nkeys);
+ printf("object has %d items\n", nkeys);
+ for (i=0; i<nkeys; i++){
+ MPI_Info_get_nthkey(info, i, key);
+ MPI_Info_get(info, key, MPI_MAX_INFO_VAL, value, &flag);
+ printf("%s=%s\n", key, value);
+ }
+
+ }
+}
+
+#endif
+
diff --git a/tools/perform/sio_standalone.h b/tools/perform/sio_standalone.h
new file mode 100644
index 0000000..b2f8220
--- /dev/null
+++ b/tools/perform/sio_standalone.h
@@ -0,0 +1,528 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef SIO_STANDALONE_H__
+#define SIO_PERF_H__
+
+/* Header file for building h5perf by standalone mode.
+ * Created: Christian Chilan, 2005/5/18.
+ */
+
+/** From H5private.h **/
+
+#include "H5public.h" /* Include Public Definitions */
+
+
+/*
+ * Include ANSI-C header files.
+ */
+#ifdef H5_STDC_HEADERS
+# include <assert.h>
+# include <ctype.h>
+# include <errno.h>
+# include <fcntl.h>
+# include <float.h>
+# include <limits.h>
+# include <math.h>
+# include <signal.h>
+# include <stdarg.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+/* maximum of two, three, or four values */
+#undef MAX
+#define MAX(a,b) (((a)>(b)) ? (a) : (b))
+#define MAX2(a,b) MAX(a,b)
+#define MAX3(a,b,c) MAX(a,MAX(b,c))
+#define MAX4(a,b,c,d) MAX(MAX(a,b),MAX(c,d))
+
+/*
+ * A macro to portably increment enumerated types.
+ */
+#ifndef H5_INC_ENUM
+# define H5_INC_ENUM(TYPE,VAR) (VAR)=((TYPE)((VAR)+1))
+#endif
+
+/*
+ * Redefine all the POSIX functions. We should never see a POSIX
+ * function (or any other non-HDF5 function) in the source!
+ */
+#define HDabort() abort()
+#define HDabs(X) abs(X)
+#ifdef H5_HAVE_WIN32_API
+#define HDaccess(F,M) _access(F, M)
+#define R_OK 4 /* Test for read permission. */
+#define W_OK 2 /* Test for write permission. */
+#define X_OK 1 /* Test for execute permission. */
+#define F_OK 0 /* Test for existence. */
+#else /* H5_HAVE_WIN32_API */
+#define HDaccess(F,M) access(F, M)
+#endif /* H5_HAVE_WIN32_API */
+#define HDacos(X) acos(X)
+#ifdef H5_HAVE_ALARM
+#define HDalarm(N) alarm(N)
+#else /* H5_HAVE_ALARM */
+#define HDalarm(N) (0)
+#endif /* H5_HAVE_ALARM */
+#define HDasctime(T) asctime(T)
+#define HDasin(X) asin(X)
+#define HDasprintf asprintf /*varargs*/
+#define HDassert(X) assert(X)
+#define HDatan(X) atan(X)
+#define HDatan2(X,Y) atan2(X,Y)
+#define HDatexit(F) atexit(F)
+#define HDatof(S) atof(S)
+#define HDatoi(S) atoi(S)
+#define HDatol(S) atol(S)
+#define HDBSDgettimeofday(S,P) BSDgettimeofday(S,P)
+#define HDbsearch(K,B,N,Z,F) bsearch(K,B,N,Z,F)
+#define HDcalloc(N,Z) calloc(N,Z)
+#define HDceil(X) ceil(X)
+#define HDcfgetispeed(T) cfgetispeed(T)
+#define HDcfgetospeed(T) cfgetospeed(T)
+#define HDcfsetispeed(T,S) cfsetispeed(T,S)
+#define HDcfsetospeed(T,S) cfsetospeed(T,S)
+#define HDchdir(S) chdir(S)
+#define HDchmod(S,M) chmod(S,M)
+#define HDchown(S,O,G) chown(S,O,G)
+#define HDclearerr(F) clearerr(F)
+#define HDclock() clock()
+#define HDclose(F) close(F)
+#define HDclosedir(D) closedir(D)
+#define HDcos(X) cos(X)
+#define HDcosh(X) cosh(X)
+#define HDcreat(S,M) creat(S,M)
+#define HDctermid(S) ctermid(S)
+#define HDctime(T) ctime(T)
+#define HDcuserid(S) cuserid(S)
+#ifdef H5_HAVE_DIFFTIME
+#define HDdifftime(X,Y) difftime(X,Y)
+#else
+#define HDdifftime(X,Y) ((double)(X)-(double)(Y))
+#endif
+#define HDdiv(X,Y) div(X,Y)
+#define HDdup(F) dup(F)
+#define HDdup2(F,I) dup2(F,I)
+/* execl() variable arguments */
+/* execle() variable arguments */
+/* execlp() variable arguments */
+#define HDexecv(S,AV) execv(S,AV)
+#define HDexecve(S,AV,E) execve(S,AV,E)
+#define HDexecvp(S,AV) execvp(S,AV)
+#define HDexit(N) exit(N)
+#define HD_exit(N) _exit(N)
+#define HDexp(X) exp(X)
+#define HDfabs(X) fabs(X)
+/* use ABS() because fabsf() fabsl() are not common yet. */
+#define HDfabsf(X) ABS(X)
+#define HDfabsl(X) ABS(X)
+#define HDfclose(F) fclose(F)
+/* fcntl() variable arguments */
+#define HDfdopen(N,S) fdopen(N,S)
+#define HDfeof(F) feof(F)
+#define HDferror(F) ferror(F)
+#define HDfflush(F) fflush(F)
+#define HDfgetc(F) fgetc(F)
+#define HDfgetpos(F,P) fgetpos(F,P)
+#define HDfgets(S,N,F) fgets(S,N,F)
+#ifdef H5_HAVE_WIN32_API
+#define HDfileno(F) _fileno(F)
+#else /* H5_HAVE_WIN32_API */
+#define HDfileno(F) fileno(F)
+#endif /* H5_HAVE_WIN32_API */
+#define HDfloor(X) floor(X)
+#define HDfmod(X,Y) fmod(X,Y)
+#define HDfopen(S,M) fopen(S,M)
+#define HDfork() fork()
+#define HDfpathconf(F,N) fpathconf(F,N)
+H5_DLL int HDfprintf (FILE *stream, const char *fmt, ...);
+#define HDfputc(C,F) fputc(C,F)
+#define HDfputs(S,F) fputs(S,F)
+#define HDfread(M,Z,N,F) fread(M,Z,N,F)
+#define HDfree(M) free(M)
+#define HDfreopen(S,M,F) freopen(S,M,F)
+#define HDfrexp(X,N) frexp(X,N)
+/* Check for Cray-specific 'frexpf()' and 'frexpl()' routines */
+#ifdef H5_HAVE_FREXPF
+#define HDfrexpf(X,N) frexpf(X,N)
+#else /* H5_HAVE_FREXPF */
+#define HDfrexpf(X,N) frexp(X,N)
+#endif /* H5_HAVE_FREXPF */
+#ifdef H5_HAVE_FREXPL
+#define HDfrexpl(X,N) frexpl(X,N)
+#else /* H5_HAVE_FREXPL */
+#define HDfrexpl(X,N) frexp(X,N)
+#endif /* H5_HAVE_FREXPL */
+/* fscanf() variable arguments */
+#ifdef H5_HAVE_FSEEKO
+ #define HDfseek(F,O,W) fseeko(F,O,W)
+#else
+ #define HDfseek(F,O,W) fseek(F,O,W)
+#endif
+#define HDfsetpos(F,P) fsetpos(F,P)
+/* definitions related to the file stat utilities.
+ * Windows have its own function names.
+ * For Unix, if off_t is not 64bit big, try use the pseudo-standard
+ * xxx64 versions if available.
+ */
+#ifdef H5_HAVE_WIN32_API
+ #define HDfstat(F,B) _fstati64(F,B)
+ #define HDlstat(S,B) _lstati64(S,B)
+ #define HDstat(S,B) _stati64(S,B)
+ typedef struct _stati64 h5_stat_t;
+ typedef __int64 h5_stat_size_t;
+#elif H5_SIZEOF_OFF_T!=8 && H5_SIZEOF_OFF64_T==8 && defined(H5_HAVE_STAT64)
+ #define HDfstat(F,B) fstat64(F,B)
+ #define HDlstat(S,B) lstat64(S,B)
+ #define HDstat(S,B) stat64(S,B)
+ typedef struct stat64 h5_stat_t;
+ typedef off64_t h5_stat_size_t;
+#else
+ #define HDfstat(F,B) fstat(F,B)
+ #define HDlstat(S,B) lstat(S,B)
+ #define HDstat(S,B) stat(S,B)
+ typedef struct stat h5_stat_t;
+ typedef off_t h5_stat_size_t;
+#endif
+
+#define HDftell(F) ftell(F)
+#define HDftruncate(F,L) ftruncate(F,L)
+#define HDfwrite(M,Z,N,F) fwrite(M,Z,N,F)
+#define HDgetc(F) getc(F)
+#define HDgetchar() getchar()
+#define HDgetcwd(S,Z) getcwd(S,Z)
+#define HDgetegid() getegid()
+#define HDgetenv(S) getenv(S)
+#define HDgeteuid() geteuid()
+#define HDgetgid() getgid()
+#define HDgetgrgid(G) getgrgid(G)
+#define HDgetgrnam(S) getgrnam(S)
+#define HDgetgroups(Z,G) getgroups(Z,G)
+#ifdef H5_HAVE_VISUAL_STUDIO
+#define HDgetlogin() Wgetlogin()
+#else /* H5_HAVE_VISUAL_STUDIO */
+#define HDgetlogin() getlogin()
+#endif /* H5_HAVE_VISUAL_STUDIO */
+#define HDgetpgrp() getpgrp()
+#define HDgetpid() getpid()
+#define HDgetppid() getppid()
+#define HDgetpwnam(S) getpwnam(S)
+#define HDgetpwuid(U) getpwuid(U)
+#define HDgetrusage(X,S) getrusage(X,S)
+#define HDgets(S) gets(S)
+#ifdef H5_HAVE_VISUAL_STUDIO
+ H5_DLL int Wgettimeofday(struct timeval *tv, struct timezone *tz);
+#define HDgettimeofday(V,Z) Wgettimeofday(V,Z)
+#else /* H5_HAVE_VISUAL_STUDIO */
+#define HDgettimeofday(S,P) gettimeofday(S,P)
+#endif /* H5_HAVE_VISUAL_STUDIO */
+#define HDgetuid() getuid()
+#define HDgmtime(T) gmtime(T)
+#define HDisalnum(C) isalnum((int)(C)) /*cast for solaris warning*/
+#define HDisalpha(C) isalpha((int)(C)) /*cast for solaris warning*/
+#define HDisatty(F) isatty(F)
+#define HDiscntrl(C) iscntrl((int)(C)) /*cast for solaris warning*/
+#define HDisdigit(C) isdigit((int)(C)) /*cast for solaris warning*/
+#define HDisgraph(C) isgraph((int)(C)) /*cast for solaris warning*/
+#define HDislower(C) islower((int)(C)) /*cast for solaris warning*/
+#define HDisprint(C) isprint((int)(C)) /*cast for solaris warning*/
+#define HDispunct(C) ispunct((int)(C)) /*cast for solaris warning*/
+#define HDisspace(C) isspace((int)(C)) /*cast for solaris warning*/
+#define HDisupper(C) isupper((int)(C)) /*cast for solaris warning*/
+#define HDisxdigit(C) isxdigit((int)(C)) /*cast for solaris warning*/
+#define HDkill(P,S) kill(P,S)
+#define HDlabs(X) labs(X)
+#define HDldexp(X,N) ldexp(X,N)
+#define HDldiv(X,Y) ldiv(X,Y)
+#define HDlink(OLD,NEW) link(OLD,NEW)
+#define HDlocaleconv() localeconv()
+#define HDlocaltime(T) localtime(T)
+#define HDlog(X) log(X)
+#define HDlog10(X) log10(X)
+#define HDlongjmp(J,N) longjmp(J,N)
+#ifdef H5_HAVE_WIN32_API
+ #define HDlseek(F,O,W) _lseeki64(F,O,W)
+#else
+ #ifdef H5_HAVE_LSEEK64
+ #define HDlseek(F,O,W) lseek64(F,O,W)
+ #else
+ #define HDlseek(F,O,W) lseek(F,O,W)
+ #endif
+#endif
+#define HDmalloc(Z) malloc(Z)
+#define HDposix_memalign(P,A,Z) posix_memalign(P,A,Z)
+#define HDmblen(S,N) mblen(S,N)
+#define HDmbstowcs(P,S,Z) mbstowcs(P,S,Z)
+#define HDmbtowc(P,S,Z) mbtowc(P,S,Z)
+#define HDmemchr(S,C,Z) memchr(S,C,Z)
+#define HDmemcmp(X,Y,Z) memcmp(X,Y,Z)
+/*
+ * The (char*) casts are required for the DEC when optimizations are turned
+ * on and the source and/or destination are not aligned.
+ */
+#define HDmemcpy(X,Y,Z) memcpy((char*)(X),(const char*)(Y),Z)
+#define HDmemmove(X,Y,Z) memmove((char*)(X),(const char*)(Y),Z)
+/*
+ * The (void*) cast just avoids a compiler warning in H5_HAVE_VISUAL_STUDIO
+ */
+#ifdef H5_HAVE_VISUAL_STUDIO
+#define HDmemset(X,C,Z) memset((void*)(X),C,Z)
+#else /* H5_HAVE_VISUAL_STUDIO */
+#define HDmemset(X,C,Z) memset(X,C,Z)
+#endif /* H5_HAVE_VISUAL_STUDIO */
+#ifdef H5_HAVE_WIN32_API
+#define HDmkdir(S,M) _mkdir(S)
+#else /* H5_HAVE_WIN32_API */
+#define HDmkdir(S,M) mkdir(S,M)
+#endif /* H5_HAVE_WIN32_API */
+#define HDmkfifo(S,M) mkfifo(S,M)
+#define HDmktime(T) mktime(T)
+#define HDmodf(X,Y) modf(X,Y)
+#ifdef _O_BINARY
+#define HDopen(S,F,M) open(S,F|_O_BINARY,M)
+#else
+#define HDopen(S,F,M) open(S,F,M)
+#endif
+#define HDopendir(S) opendir(S)
+#define HDpathconf(S,N) pathconf(S,N)
+#define HDpause() pause()
+#define HDperror(S) perror(S)
+#define HDpipe(F) pipe(F)
+#define HDpow(X,Y) pow(X,Y)
+/* printf() variable arguments */
+#define HDputc(C,F) putc(C,F)
+#define HDputchar(C) putchar(C)
+#define HDputs(S) puts(S)
+#define HDqsort(M,N,Z,F) qsort(M,N,Z,F)
+#define HDraise(N) raise(N)
+
+#ifdef H5_HAVE_RAND_R
+#define HDrandom() HDrand()
+H5_DLL int HDrand(void);
+#elif H5_HAVE_RANDOM
+#define HDrand() random()
+#define HDrandom() random()
+#else
+#define HDrand() rand()
+#define HDrandom() rand()
+#endif
+
+#define HDread(F,M,Z) read(F,M,Z)
+#define HDreaddir(D) readdir(D)
+#define HDrealloc(M,Z) realloc(M,Z)
+#ifdef H5_VMS
+#ifdef __cplusplus
+extern "C" {
+#endif
+int HDremove_all(const char * fname);
+#ifdef __cplusplus
+}
+#endif
+#define HDremove(S) HDremove_all(S)
+#else
+#define HDremove(S) remove(S)
+#endif /*H5_VMS*/
+#define HDrename(OLD,NEW) rename(OLD,NEW)
+#define HDrewind(F) rewind(F)
+#define HDrewinddir(D) rewinddir(D)
+#define HDrmdir(S) rmdir(S)
+/* scanf() variable arguments */
+#define HDsetbuf(F,S) setbuf(F,S)
+#define HDsetgid(G) setgid(G)
+#define HDsetjmp(J) setjmp(J)
+#define HDsetlocale(N,S) setlocale(N,S)
+#define HDsetpgid(P,PG) setpgid(P,PG)
+#define HDsetsid() setsid()
+#define HDsetuid(U) setuid(U)
+/* Windows does not permit setting the buffer size to values
+ less than 2. */
+#ifndef H5_HAVE_WIN32_API
+#define HDsetvbuf(F,S,M,Z) setvbuf(F,S,M,Z)
+#else
+#define HDsetvbuf(F,S,M,Z) setvbuf(F,S,M,(Z>1?Z:2))
+#endif
+#define HDsigaddset(S,N) sigaddset(S,N)
+#define HDsigdelset(S,N) sigdelset(S,N)
+#define HDsigemptyset(S) sigemptyset(S)
+#define HDsigfillset(S) sigfillset(S)
+#define HDsigismember(S,N) sigismember(S,N)
+#define HDsiglongjmp(J,N) siglongjmp(J,N)
+#define HDsignal(N,F) signal(N,F)
+#define HDsigpending(S) sigpending(S)
+#define HDsigprocmask(H,S,O) sigprocmask(H,S,O)
+#define HDsigsetjmp(J,N) sigsetjmp(J,N)
+#define HDsigsuspend(S) sigsuspend(S)
+#define HDsin(X) sin(X)
+#define HDsinh(X) sinh(X)
+#define HDsleep(N) sleep(N)
+#ifdef H5_HAVE_WIN32_API
+H5_DLL int c99_snprintf(char* str, size_t size, const char* format, ...);
+#define HDsnprintf c99_snprintf /*varargs*/
+#else
+#define HDsnprintf snprintf /*varargs*/
+#endif
+/* sprintf() variable arguments */
+#define HDsqrt(X) sqrt(X)
+#ifdef H5_HAVE_RAND_R
+H5_DLL void HDsrand(unsigned int seed);
+#define HDsrandom(S) HDsrand(S)
+#elif H5_HAVE_RANDOM
+#define HDsrand(S) srandom(S)
+#define HDsrandom(S) srandom(S)
+#else
+#define HDsrand(S) srand(S)
+#define HDsrandom(S) srand(S)
+#endif
+/* sscanf() variable arguments */
+
+#ifdef H5_HAVE_WIN32_API
+#define HDstrcasecmp(A,B) _stricmp(A,B)
+#else
+#define HDstrcasecmp(X,Y) strcasecmp(X,Y)
+#endif
+#define HDstrcat(X,Y) strcat(X,Y)
+#define HDstrchr(S,C) strchr(S,C)
+#define HDstrcmp(X,Y) strcmp(X,Y)
+#define HDstrcoll(X,Y) strcoll(X,Y)
+#define HDstrcpy(X,Y) strcpy(X,Y)
+#define HDstrcspn(X,Y) strcspn(X,Y)
+#define HDstrerror(N) strerror(N)
+#define HDstrftime(S,Z,F,T) strftime(S,Z,F,T)
+#define HDstrlen(S) strlen(S)
+#define HDstrncat(X,Y,Z) strncat(X,Y,Z)
+#define HDstrncmp(X,Y,Z) strncmp(X,Y,Z)
+#define HDstrncpy(X,Y,Z) strncpy(X,Y,Z)
+#define HDstrpbrk(X,Y) strpbrk(X,Y)
+#define HDstrrchr(S,C) strrchr(S,C)
+#define HDstrspn(X,Y) strspn(X,Y)
+#define HDstrstr(X,Y) strstr(X,Y)
+#define HDstrtod(S,R) strtod(S,R)
+#define HDstrtok(X,Y) strtok(X,Y)
+#define HDstrtol(S,R,N) strtol(S,R,N)
+H5_DLL int64_t HDstrtoll (const char *s, const char **rest, int base);
+#define HDstrtoul(S,R,N) strtoul(S,R,N)
+#define HDstrxfrm(X,Y,Z) strxfrm(X,Y,Z)
+#define HDsysconf(N) sysconf(N)
+#define HDsystem(S) system(S)
+#define HDtan(X) tan(X)
+#define HDtanh(X) tanh(X)
+#define HDtcdrain(F) tcdrain(F)
+#define HDtcflow(F,A) tcflow(F,A)
+#define HDtcflush(F,N) tcflush(F,N)
+#define HDtcgetattr(F,T) tcgetattr(F,T)
+#define HDtcgetpgrp(F) tcgetpgrp(F)
+#define HDtcsendbreak(F,N) tcsendbreak(F,N)
+#define HDtcsetattr(F,O,T) tcsetattr(F,O,T)
+#define HDtcsetpgrp(F,N) tcsetpgrp(F,N)
+#define HDtime(T) time(T)
+#define HDtimes(T) times(T)
+#define HDtmpfile() tmpfile()
+#define HDtmpnam(S) tmpnam(S)
+#define HDtolower(C) tolower(C)
+#define HDtoupper(C) toupper(C)
+#define HDttyname(F) ttyname(F)
+#define HDtzset() tzset()
+#define HDumask(N) umask(N)
+#define HDuname(S) uname(S)
+#define HDungetc(C,F) ungetc(C,F)
+#ifdef H5_HAVE_WIN32_API
+#define HDunlink(S) _unlink(S)
+#else
+#define HDunlink(S) unlink(S)
+#endif
+#define HDutime(S,T) utime(S,T)
+#define HDva_arg(A,T) va_arg(A,T)
+#define HDva_end(A) va_end(A)
+#define HDva_start(A,P) va_start(A,P)
+#define HDvasprintf(RET,FMT,A) vasprintf(RET,FMT,A)
+#define HDvfprintf(F,FMT,A) vfprintf(F,FMT,A)
+#define HDvprintf(FMT,A) vprintf(FMT,A)
+#define HDvsprintf(S,FMT,A) vsprintf(S,FMT,A)
+#ifdef H5_HAVE_WIN32_API
+H5_DLL int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap);
+#define HDvsnprintf c99_vsnprintf
+#else
+# define HDvsnprintf(S,N,FMT,A) vsnprintf(S,N,FMT,A)
+#endif
+#define HDwait(W) wait(W)
+#define HDwaitpid(P,W,O) waitpid(P,W,O)
+#define HDwcstombs(S,P,Z) wcstombs(S,P,Z)
+#define HDwctomb(S,C) wctomb(S,C)
+#define HDwrite(F,M,Z) write(F,M,Z)
+
+/*
+ * And now for a couple non-Posix functions... Watch out for systems that
+ * define these in terms of macros.
+ */
+#ifdef H5_HAVE_WIN32_API
+#define HDstrdup(S) _strdup(S)
+#else /* H5_HAVE_WIN32_API */
+
+#if !defined strdup && !defined H5_HAVE_STRDUP
+extern char *strdup(const char *s);
+#endif
+
+#define HDstrdup(S) strdup(S)
+
+#endif /* H5_HAVE_WIN32_API */
+
+/*
+ * HDF Boolean type.
+ */
+#ifndef FALSE
+# define FALSE 0
+#endif
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+/** From h5test.h **/
+
+#ifdef H5_HAVE_PARALLEL
+extern MPI_Info h5_io_info_g; /* MPI INFO object for IO */
+#endif
+
+#ifdef H5_HAVE_PARALLEL
+H5TEST_DLL int h5_set_info_object(void);
+H5TEST_DLL void h5_dump_info_object(MPI_Info info);
+#endif
+
+
+
+/** From h5tools_utils.h **/
+
+extern int opt_err; /* getoption prints errors if this is on */
+extern int opt_ind; /* token pointer */
+extern const char *opt_arg; /* flag argument (or value) */
+
+
+enum {
+ no_arg = 0, /* doesn't take an argument */
+ require_arg, /* requires an argument */
+ optional_arg /* argument is optional */
+};
+
+
+typedef struct long_options {
+ const char *name; /* name of the long option */
+ int has_arg; /* whether we should look for an arg */
+ char shortval; /* the shortname equivalent of long arg
+ * this gets returned from get_option */
+} long_options;
+
+extern int get_option(int argc, const char **argv, const char *opt,
+ const struct long_options *l_opt);
+#endif
diff --git a/tools/perform/sio_timer.c b/tools/perform/sio_timer.c
new file mode 100644
index 0000000..4e42ee6
--- /dev/null
+++ b/tools/perform/sio_timer.c
@@ -0,0 +1,197 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Purpose:
+ *
+ * This is a module of useful timing functions for performance testing.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sio_timer.h"
+
+
+#include "sio_perf.h"
+
+/*
+ * The number to divide the tv_usec field with to get a nice decimal to add to
+ * the number of seconds.
+ */
+#define MICROSECOND 1000000.0
+
+/* global variables */
+sio_time *timer_g; /* timer: global for stub functions */
+
+/*
+ * Function: sub_time
+ * Purpose: Struct two time values, and return the difference, in microseconds
+ *
+ * Note that the function assumes that a > b
+ * Programmer: Leon Arber, 1/27/06
+ */
+static double sub_time(struct timeval* a, struct timeval* b)
+{
+ return (((double)a->tv_sec +
+ ((double)a->tv_usec) / MICROSECOND) -
+ ((double)b->tv_sec +
+ ((double)b->tv_usec) / MICROSECOND));
+}
+
+
+/*
+ * Function: sio_time_new
+ * Purpose: Build us a brand, spankin', new performance time object.
+ * The object is a black box to the user.
+ * Return: Pointer to sio_time object
+ * Programmer: Bill Wendling, 01. October 2001
+ * Modifications:
+ */
+sio_time *
+sio_time_new(void)
+{
+ sio_time *pt = (sio_time *)calloc(1, sizeof(struct sio_time_));
+
+ /* set global timer variable */
+ timer_g = pt;
+
+ return pt;
+}
+
+/*
+ * Function: sio_time_destroy
+ * Purpose: Remove the memory allocated for the sio_time object. Only
+ * need to call on a pointer allocated with the ``sio_time_new''
+ * function.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 01. October 2001
+ * Modifications:
+ */
+void
+sio_time_destroy(sio_time *pt)
+{
+ HDfree(pt);
+ /* reset the global timer pointer too. */
+ timer_g = NULL;
+}
+
+
+
+/*
+ * Function: set_time
+ * Purpose: Set the time in a ``sio_time'' object.
+ * Return: Pointer to the passed in ``sio_time'' object.
+ * Programmer: Bill Wendling, 01. October 2001
+ * Modifications:
+ */
+sio_time *
+set_time(sio_time *pt, timer_type t, int start_stop)
+{
+ if (pt) {
+ if (start_stop == TSTART) {
+ HDgettimeofday(&pt->sys_timer[t], NULL);
+
+ /* When we start the timer for HDF5_FINE_WRITE_FIXED_DIMS or HDF5_FINE_READ_FIXED_DIMS
+ * we compute the time it took to only open the file */
+ if(t == HDF5_FINE_WRITE_FIXED_DIMS)
+ pt->total_time[HDF5_FILE_WRITE_OPEN] += sub_time(&(pt->sys_timer[t]), &(pt->sys_timer[HDF5_GROSS_WRITE_FIXED_DIMS]));
+ else if(t == HDF5_FINE_READ_FIXED_DIMS)
+ pt->total_time[HDF5_FILE_READ_OPEN] += sub_time(&(pt->sys_timer[t]), &(pt->sys_timer[HDF5_GROSS_READ_FIXED_DIMS]));
+
+
+ } else {
+ struct timeval sys_t;
+
+ HDgettimeofday(&sys_t, NULL);
+ pt->total_time[t] += sub_time(&sys_t, &(pt->sys_timer[t]));
+
+/* ((double)sys_t.tv_sec +
+ ((double)sys_t.tv_usec) / MICROSECOND) -
+ ((double)pt->sys_timer[t].tv_sec +
+ ((double)pt->sys_timer[t].tv_usec) / MICROSECOND);*/
+
+ /* When we stop the timer for HDF5_GROSS_WRITE_FIXED_DIMS or HDF5_GROSS_READ_FIXED_DIMS
+ * we compute the time it took to close the file after the last read/write finished */
+ if(t == HDF5_GROSS_WRITE_FIXED_DIMS)
+ pt->total_time[HDF5_FILE_WRITE_CLOSE] += sub_time(&(pt->sys_timer[t]), &(pt->sys_timer[HDF5_FINE_WRITE_FIXED_DIMS]));
+ else if(t == HDF5_GROSS_READ_FIXED_DIMS)
+ pt->total_time[HDF5_FILE_READ_CLOSE] += sub_time(&(pt->sys_timer[t]), &(pt->sys_timer[HDF5_FINE_READ_FIXED_DIMS]));
+
+ }
+
+ if (sio_debug_level >= 4) {
+ const char *msg;
+
+ switch (t) {
+ case HDF5_FILE_OPENCLOSE:
+ msg = "File Open/Close";
+ break;
+ case HDF5_DATASET_CREATE:
+ msg = "Dataset Create";
+ break;
+ case HDF5_MPI_WRITE:
+ msg = "MPI Write";
+ break;
+ case HDF5_MPI_READ:
+ msg = "MPI Read";
+ break;
+ case HDF5_FINE_WRITE_FIXED_DIMS:
+ msg = "Fine Write";
+ break;
+ case HDF5_FINE_READ_FIXED_DIMS:
+ msg = "Fine Read";
+ break;
+ case HDF5_GROSS_WRITE_FIXED_DIMS:
+ msg = "Gross Write";
+ break;
+ case HDF5_GROSS_READ_FIXED_DIMS:
+ msg = "Gross Read";
+ break;
+ case HDF5_RAW_WRITE_FIXED_DIMS:
+ msg = "Raw Write";
+ break;
+ case HDF5_RAW_READ_FIXED_DIMS:
+ msg = "Raw Read";
+ break;
+ default:
+ msg = "Unknown Timer";
+ break;
+ }
+
+ fprintf(output, " %s %s: %.2f\n", msg,
+ (start_stop == TSTART ? "Start" : "Stop"),
+ pt->total_time[t]);
+ }
+ }
+
+ return pt;
+}
+
+/*
+ * Function: get_time
+ * Purpose: Get the time from a ``sio_time'' object.
+ * Return: The number of seconds as a DOUBLE.
+ * Programmer: Bill Wendling, 01. October 2001
+ * Modifications:
+ */
+double
+get_time(sio_time *pt, timer_type t)
+{
+ return pt->total_time[t];
+}
+#ifdef STANDALONE
+#include "sio_standalone.c"
+#endif
+
diff --git a/tools/perform/sio_timer.h b/tools/perform/sio_timer.h
new file mode 100644
index 0000000..46702c3
--- /dev/null
+++ b/tools/perform/sio_timer.h
@@ -0,0 +1,78 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef SIO_TIMER__
+#define SIO_TIMER__
+
+#include "hdf5.h"
+
+#if defined(H5_TIME_WITH_SYS_TIME)
+# include <sys/time.h>
+# include <time.h>
+#elif defined(H5_HAVE_SYS_TIME_H)
+# include <sys/time.h>
+#else
+# include <time.h>
+#endif
+
+#ifdef H5_HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif /* H5_HAVE_WINSOCK2_H */
+
+/* The different types of timers we can have */
+typedef enum timer_type_ {
+ HDF5_FILE_OPENCLOSE,
+ HDF5_DATASET_CREATE,
+ HDF5_MPI_WRITE,
+ HDF5_MPI_READ,
+ HDF5_FILE_READ_OPEN,
+ HDF5_FILE_READ_CLOSE,
+ HDF5_FILE_WRITE_OPEN,
+ HDF5_FILE_WRITE_CLOSE,
+ HDF5_FINE_WRITE_FIXED_DIMS,
+ HDF5_FINE_READ_FIXED_DIMS,
+ HDF5_GROSS_WRITE_FIXED_DIMS,
+ HDF5_GROSS_READ_FIXED_DIMS,
+ HDF5_RAW_WRITE_FIXED_DIMS,
+ HDF5_RAW_READ_FIXED_DIMS,
+ NUM_TIMERS
+} timer_type;
+
+
+/* Miscellaneous identifiers */
+enum {
+ TSTART, /* Start a specified timer */
+ TSTOP /* Stop a specified timer */
+};
+
+/* The performance time structure */
+typedef struct sio_time_ {
+ double total_time[NUM_TIMERS];
+ struct timeval sys_timer[NUM_TIMERS];
+} sio_time;
+
+/* External function declarations */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+extern sio_time *sio_time_new(void);
+extern void sio_time_destroy(sio_time *pt);
+extern void set_timer_type(sio_time *pt);
+extern sio_time *set_time(sio_time *pt, timer_type t, int start_stop);
+extern double get_time(sio_time *pt, timer_type t);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SIO_TIMER__ */
diff --git a/tools/perform/zip_perf.c b/tools/perform/zip_perf.c
new file mode 100644
index 0000000..edd5b0f
--- /dev/null
+++ b/tools/perform/zip_perf.c
@@ -0,0 +1,653 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the files COPYING and Copyright.html. COPYING can be found at the root *
+ * of the source code distribution tree; Copyright.html can be found at the *
+ * root level of an installed copy of the electronic HDF5 document set and *
+ * is linked from the top-level documents page. It can also be found at *
+ * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have *
+ * access to either file, you may request a copy from help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/* ===========================================================================
+ * Usage: zip_perf [-d] [-f] [-h] [-1 to -9] [files...]
+ * -d : decompress
+ * -f : compress with Z_FILTERED
+ * -h : compress with Z_HUFFMAN_ONLY
+ * -1 to -9 : compression level
+ */
+
+/* our header files */
+#include "h5test.h"
+#include "h5tools.h"
+#include "h5tools_utils.h"
+
+#ifdef H5_HAVE_FILTER_DEFLATE
+
+#include <zlib.h>
+
+#ifdef VMS
+# define unlink delete
+#endif /* VMS */
+
+#ifdef RISCOS
+# define unlink remove
+# define fileno(file) file->__file
+#endif /* RISCOS */
+
+#define ONE_KB 1024
+#define ONE_MB (ONE_KB * ONE_KB)
+#define ONE_GB (ONE_MB * ONE_KB)
+
+#define MICROSECOND 1000000.0
+
+/* report 0.0 in case t is zero too */
+#define MB_PER_SEC(bytes,t) ((fabs(t)<0.0000000001) ? 0.0 : ((((double)bytes) / ONE_MB) / (t)))
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* TRUE */
+
+#ifndef FALSE
+#define FALSE (!TRUE)
+#endif /* FALSE */
+
+#ifndef S_IRWXU
+#define S_IRWXU (_S_IREAD|_S_IWRITE)
+#endif
+
+/* internal variables */
+static const char *prog=NULL;
+static const char *option_prefix=NULL;
+static char *filename=NULL;
+static int compress_percent = 0;
+static int compress_level = Z_DEFAULT_COMPRESSION;
+static int output, random_test = FALSE;
+static int report_once_flag;
+static double compression_time;
+
+/* internal functions */
+static void error(const char *fmt, ...);
+static void compress_buffer(Bytef *dest, uLongf *destLen, const Bytef *source,
+ uLong sourceLen);
+
+/* commandline options : long and short form */
+static const char *s_opts = "hB:b:c:p:rs:0123456789";
+static struct long_options l_opts[] = {
+ { "help", no_arg, 'h' },
+ { "compressability", require_arg, 'c' },
+ { "compressabilit", require_arg, 'c' },
+ { "compressabili", require_arg, 'c' },
+ { "compressabil", require_arg, 'c' },
+ { "compressabi", require_arg, 'c' },
+ { "compressab", require_arg, 'c' },
+ { "compressa", require_arg, 'c' },
+ { "compress", require_arg, 'c' },
+ { "compres", require_arg, 'c' },
+ { "compre", require_arg, 'c' },
+ { "compr", require_arg, 'c' },
+ { "comp", require_arg, 'c' },
+ { "com", require_arg, 'c' },
+ { "co", require_arg, 'c' },
+ { "file-size", require_arg, 's' },
+ { "file-siz", require_arg, 's' },
+ { "file-si", require_arg, 's' },
+ { "file-s", require_arg, 's' },
+ { "file", require_arg, 's' },
+ { "fil", require_arg, 's' },
+ { "fi", require_arg, 's' },
+ { "max-buffer-size", require_arg, 'B' },
+ { "max-buffer-siz", require_arg, 'B' },
+ { "max-buffer-si", require_arg, 'B' },
+ { "max-buffer-s", require_arg, 'B' },
+ { "max-buffer", require_arg, 'B' },
+ { "max-buffe", require_arg, 'B' },
+ { "max-buff", require_arg, 'B' },
+ { "max-buf", require_arg, 'B' },
+ { "max-bu", require_arg, 'B' },
+ { "max-b", require_arg, 'B' },
+ { "max", require_arg, 'B' },
+ { "min-buffer-size", require_arg, 'b' },
+ { "min-buffer-siz", require_arg, 'b' },
+ { "min-buffer-si", require_arg, 'b' },
+ { "min-buffer-s", require_arg, 'b' },
+ { "min-buffer", require_arg, 'b' },
+ { "min-buffe", require_arg, 'b' },
+ { "min-buff", require_arg, 'b' },
+ { "min-buf", require_arg, 'b' },
+ { "min-bu", require_arg, 'b' },
+ { "min-b", require_arg, 'b' },
+ { "min", require_arg, 'b' },
+ { "prefix", require_arg, 'p' },
+ { "prefi", require_arg, 'p' },
+ { "pref", require_arg, 'p' },
+ { "pre", require_arg, 'p' },
+ { "pr", require_arg, 'p' },
+ { "random-test", no_arg, 'r' },
+ { "random-tes", no_arg, 'r' },
+ { "random-te", no_arg, 'r' },
+ { "random-t", no_arg, 'r' },
+ { "random", no_arg, 'r' },
+ { "rando", no_arg, 'r' },
+ { "rand", no_arg, 'r' },
+ { "ran", no_arg, 'r' },
+ { "ra", no_arg, 'r' },
+ { NULL, 0, '\0' }
+};
+
+/*
+ * Function: error
+ * Purpose: Display error message and exit.
+ * Programmer: Bill Wendling, 05. June 2002
+ * Modifications:
+ */
+static void
+error(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ HDfprintf(stderr, "%s: error: ", prog);
+ HDvfprintf(stderr, fmt, ap);
+ HDfprintf(stderr, "\n");
+ va_end(ap);
+ HDexit(EXIT_FAILURE);
+}
+
+/*
+ * Function: cleanup
+ * Purpose: Cleanup the output file.
+ * Returns: Nothing
+ * Programmer: Bill Wendling, 06. June 2002
+ * Modifications:
+ */
+static void
+cleanup(void)
+{
+ if (!HDgetenv("HDF5_NOCLEANUP"))
+ HDunlink(filename);
+ HDfree(filename);
+}
+
+static void
+write_file(Bytef *source, uLongf sourceLen)
+{
+ Bytef *d_ptr, *dest;
+ uLongf d_len, destLen;
+ struct timeval timer_start, timer_stop;
+
+ /* destination buffer needs to be at least 0.1% larger than sourceLen
+ * plus 12 bytes */
+ destLen = (uLongf)((double)sourceLen + ((double)sourceLen * 0.1)) + 12;
+ dest = (Bytef *)HDmalloc(destLen);
+
+ if (!dest)
+ error("out of memory");
+
+ HDgettimeofday(&timer_start, NULL);
+ compress_buffer(dest, &destLen, source, sourceLen);
+ HDgettimeofday(&timer_stop, NULL);
+
+ compression_time += ((double)timer_stop.tv_sec +
+ ((double)timer_stop.tv_usec) / MICROSECOND) -
+ ((double)timer_start.tv_sec +
+ ((double)timer_start.tv_usec) / MICROSECOND);
+
+ if (report_once_flag) {
+ HDfprintf(stdout, "\tCompression Ratio: %g\n", ((double)destLen) / (double)sourceLen);
+ report_once_flag = 0;
+ }
+
+ d_ptr = dest;
+ d_len = destLen;
+
+ /* loop to make sure we write everything out that we want to write */
+ for (;;) {
+ int rc = (int)HDwrite(output, d_ptr, (size_t)d_len);
+
+ if (rc == -1)
+ error(HDstrerror(errno));
+
+ if (rc == (int)d_len)
+ break;
+
+ d_len -= rc;
+ d_ptr += rc;
+ }
+
+ HDfree(dest);
+}
+
+/*
+ * Function: compress_buffer
+ * Purpose: Compress the buffer.
+ * Returns: Z_OK - success
+ * Z_MEM_ERROR - not enough memory
+ * Z_BUF_ERROR - not enough room in the output buffer
+ * Z_STREAM_ERROR - level parameter is invalid
+ * Programmer: Bill Wendling, 05. June 2002
+ * Modifications:
+ */
+static void
+compress_buffer(Bytef *dest, uLongf *destLen, const Bytef *source,
+ uLong sourceLen)
+{
+ int rc = compress2(dest, destLen, source, sourceLen, compress_level);
+
+ if (rc != Z_OK) {
+ /* compress2 failed - cleanup and tell why */
+ cleanup();
+
+ switch (rc) {
+ case Z_MEM_ERROR:
+ error("not enough memory");
+ break;
+ case Z_BUF_ERROR:
+ error("not enough room in the output buffer");
+ break;
+ case Z_STREAM_ERROR:
+ error("level parameter (%d) is invalid", compress_level);
+ break;
+ default:
+ error("unknown compression error");
+ break;
+ }
+ }
+}
+
+#ifdef LATER
+/*
+ * Function: uncompress_buffer
+ * Purpose: Uncompress the buffer.
+ * Returns: Z_OK - success
+ * Z_MEM_ERROR - not enough memory
+ * Z_BUF_ERROR - not enough room in the output buffer
+ * Z_DATA_ERROR - the input data was corrupted
+ * Programmer: Bill Wendling, 05. June 2002
+ * Modifications:
+ */
+static int
+uncompress_buffer(Bytef *dest, uLongf *destLen, const Bytef *source,
+ uLong sourceLen)
+{
+ int rc = uncompress(dest, destLen, source, sourceLen);
+
+ return rc;
+}
+#endif /* LATER */
+
+/*
+ * Function: get_unique_name
+ * Purpose: Create a new file who's name doesn't conflict with
+ * pre-existing files.
+ * Returns: Nothing
+ * Programmer: Bill Wendling, 06. June 2002
+ * Modifications:
+ */
+#define ZIP_PERF_FILE "zip_perf.data"
+static void
+get_unique_name(void)
+{
+ const char *prefix = NULL;
+ const char *env = HDgetenv("HDF5_PREFIX");
+
+ if (env)
+ prefix = env;
+
+ if (option_prefix)
+ prefix = option_prefix;
+
+ if (prefix)
+ /* 2 = 1 for '/' + 1 for null terminator */
+ filename = (char *) HDmalloc(HDstrlen(prefix) + HDstrlen(ZIP_PERF_FILE) + 2);
+ else
+ filename = (char *) HDmalloc(HDstrlen(ZIP_PERF_FILE) + 1);
+
+ if (!filename)
+ error("out of memory");
+
+ filename[0] = 0;
+ if (prefix){
+ HDstrcpy(filename, prefix);
+ HDstrcat(filename, "/");
+ }
+ HDstrcat(filename, ZIP_PERF_FILE);
+}
+
+/*
+ * Function: usage
+ * Purpose: Print a usage message and then exit.
+ * Return: Nothing
+ * Programmer: Bill Wendling, 05. June 2002
+ * Modifications:
+ */
+static void
+usage(void)
+{
+ HDfprintf(stdout, "usage: %s [OPTIONS]\n", prog);
+ HDfprintf(stdout, " OPTIONS\n");
+ HDfprintf(stdout, " -h, --help Print this usage message and exit\n");
+ HDfprintf(stdout, " -1...-9 Level of compression, from 1 to 9\n");
+ HDfprintf(stdout, " -c P, --compressability=P Percentage of compressability of the random\n");
+ HDfprintf(stdout, " data you want [default: 0]");
+ HDfprintf(stdout, " -s S, --file-size=S Maximum size of uncompressed file [default: 64M]\n");
+ HDfprintf(stdout, " -B S, --max-buffer_size=S Maximum size of buffer [default: 1M]\n");
+ HDfprintf(stdout, " -b S, --min-buffer_size=S Minumum size of buffer [default: 128K]\n");
+ HDfprintf(stdout, " -p D, --prefix=D The directory prefix to place the file\n");
+ HDfprintf(stdout, " -r, --random-test Use random data to write to the file\n");
+ HDfprintf(stdout, " [default: no]\n");
+ HDfprintf(stdout, "\n");
+ HDfprintf(stdout, " D - a directory which exists\n");
+ HDfprintf(stdout, " P - a number between 0 and 100\n");
+ HDfprintf(stdout, " S - is a size specifier, an integer >=0 followed by a size indicator:\n");
+ HDfprintf(stdout, "\n");
+ HDfprintf(stdout, " K - Kilobyte (%d)\n", ONE_KB);
+ HDfprintf(stdout, " M - Megabyte (%d)\n", ONE_MB);
+ HDfprintf(stdout, " G - Gigabyte (%d)\n", ONE_GB);
+ HDfprintf(stdout, "\n");
+ HDfprintf(stdout, " Example: 37M = 37 Megabytes = %d bytes\n", 37 * ONE_MB);
+ HDfprintf(stdout, "\n");
+ HDfflush(stdout);
+}
+
+/*
+ * Function: parse_size_directive
+ * Purpose: Parse the size directive passed on the commandline. The size
+ * directive is an integer followed by a size indicator:
+ *
+ * K, k - Kilobyte
+ * M, m - Megabyte
+ *
+ * Return: The size as a size_t because this is related to buffer size.
+ * If an unknown size indicator is used, then the program will
+ * exit with EXIT_FAILURE as the return value.
+ * Programmer: Bill Wendling, 05. June 2002
+ * Modifications:
+ */
+static unsigned long
+parse_size_directive(const char *size)
+{
+ unsigned long s;
+ char *endptr;
+
+ s = HDstrtoul(size, &endptr, 10);
+
+ if (endptr && *endptr) {
+ while (*endptr != '\0' && (*endptr == ' ' || *endptr == '\t'))
+ ++endptr;
+
+ switch (*endptr) {
+ case 'K':
+ case 'k':
+ s *= ONE_KB;
+ break;
+ case 'M':
+ case 'm':
+ s *= ONE_MB;
+ break;
+ case 'G':
+ case 'g':
+ s *= ONE_GB;
+ break;
+ default:
+ error("illegal size specifier '%c'", *endptr);
+ break;
+ }
+ }
+
+ return s;
+}
+
+static void
+fill_with_random_data(Bytef *src, uLongf src_len)
+{
+ register unsigned u;
+ h5_stat_t stat_buf;
+
+ if (HDstat("/dev/urandom", &stat_buf) == 0) {
+ uLongf len = src_len;
+ Bytef *buf = src;
+ int fd = HDopen("/dev/urandom", O_RDONLY, 0);
+
+ HDfprintf(stdout, "Using /dev/urandom for random data\n");
+
+ if (fd < 0)
+ error(HDstrerror(errno));
+
+ for (;;) {
+ ssize_t rc = HDread(fd, buf, src_len);
+
+ if (rc == -1)
+ error(HDstrerror(errno));
+
+ if (rc == (ssize_t)len)
+ break;
+
+ buf += rc;
+ len -= rc;
+ }
+ } else {
+ HDfprintf(stdout, "Using random() for random data\n");
+
+ for (u = 0; u < src_len; ++u)
+ src[u] = (Bytef)(0xff & HDrandom());
+ }
+
+ if (compress_percent) {
+ unsigned long s = src_len * compress_percent / 100;
+
+ HDmemset(src, '\0', s);
+ }
+}
+
+static void
+do_write_test(unsigned long file_size, unsigned long min_buf_size,
+ unsigned long max_buf_size)
+{
+ uLongf src_len, total_len;
+ struct timeval timer_start, timer_stop;
+ double total_time;
+ Bytef *src;
+
+ for (src_len = min_buf_size; src_len <= max_buf_size; src_len <<= 1) {
+ register unsigned long i, iters;
+
+ iters = file_size / src_len;
+ src = (Bytef *)HDcalloc(1, sizeof(Bytef) * src_len);
+
+ if (!src) {
+ cleanup();
+ error("out of memory");
+ }
+
+ compression_time = 0.0;
+
+ if (random_test)
+ fill_with_random_data(src, src_len);
+
+ HDfprintf(stdout, "Buffer size == ");
+
+ if (src_len >= ONE_KB && (src_len % ONE_KB) == 0) {
+ if (src_len >= ONE_MB && (src_len % ONE_MB) == 0) {
+ HDfprintf(stdout, "%ldMB", src_len / ONE_MB);
+ } else {
+ HDfprintf(stdout, "%ldKB", src_len / ONE_KB);
+ }
+ } else {
+ HDfprintf(stdout, "%ld", src_len);
+ }
+
+ HDfprintf(stdout, "\n");
+
+ /* do uncompressed data write */
+ HDgettimeofday(&timer_start, NULL);
+ output = HDopen(filename, O_RDWR | O_CREAT, S_IRWXU);
+
+ if (output == -1)
+ error(HDstrerror(errno));
+
+ for (i = 0; i <= iters; ++i) {
+ Bytef *s_ptr = src;
+ uLong s_len = src_len;
+
+ /* loop to make sure we write everything out that we want to write */
+ for (;;) {
+ ssize_t rc = HDwrite(output, s_ptr, s_len);
+
+ if (rc == -1)
+ error(HDstrerror(errno));
+
+ if (rc == (ssize_t)s_len)
+ break;
+
+ s_len -= rc;
+ s_ptr += rc;
+ }
+ }
+
+ HDclose(output);
+ HDgettimeofday(&timer_stop, NULL);
+
+ total_time = ((double)timer_stop.tv_sec +
+ ((double)timer_stop.tv_usec) / MICROSECOND) -
+ ((double)timer_start.tv_sec +
+ ((double)timer_start.tv_usec) / MICROSECOND);
+
+ HDfprintf(stdout, "\tUncompressed Write Time: %.2fs\n", total_time);
+ HDfprintf(stdout, "\tUncompressed Write Throughput: %.2fMB/s\n",
+ MB_PER_SEC(file_size, total_time));
+
+ HDunlink(filename);
+
+ /* do compressed data write */
+ output = HDopen(filename, O_RDWR | O_CREAT, S_IRWXU);
+
+ if (output == -1)
+ error(HDstrerror(errno));
+
+ report_once_flag = 1;
+ HDgettimeofday(&timer_start, NULL);
+
+ for (total_len = 0; total_len < file_size; total_len += src_len)
+ write_file(src, src_len);
+
+ HDclose(output);
+ HDgettimeofday(&timer_stop, NULL);
+
+ total_time = ((double)timer_stop.tv_sec +
+ ((double)timer_stop.tv_usec) / MICROSECOND) -
+ ((double)timer_start.tv_sec +
+ ((double)timer_start.tv_usec) / MICROSECOND);
+
+ HDfprintf(stdout, "\tCompressed Write Time: %.2fs\n", total_time);
+ HDfprintf(stdout, "\tCompressed Write Throughput: %.2fMB/s\n",
+ MB_PER_SEC(file_size, total_time));
+ HDfprintf(stdout, "\tCompression Time: %gs\n", compression_time);
+
+ HDunlink(filename);
+ HDfree(src);
+ }
+}
+
+/*
+ * Function: main
+ * Purpose: Run the program
+ * Return: EXIT_SUCCESS or EXIT_FAILURE
+ * Programmer: Bill Wendling, 05. June 2002
+ * Modifications:
+ */
+int
+main(int argc, char **argv)
+{
+ unsigned long min_buf_size = 128 * ONE_KB, max_buf_size = ONE_MB;
+ unsigned long file_size = 64 * ONE_MB;
+ int opt;
+
+ prog = argv[0];
+
+ /* Initialize h5tools lib */
+ h5tools_init();
+
+ while ((opt = get_option(argc, (const char **)argv, s_opts, l_opts)) > 0) {
+ switch ((char)opt) {
+ case '0': case '1': case '2':
+ case '3': case '4': case '5':
+ case '6': case '7': case '8':
+ case '9':
+ compress_level = opt - '0';
+ break;
+ case 'B':
+ max_buf_size = parse_size_directive(opt_arg);
+ break;
+ case 'b':
+ min_buf_size = parse_size_directive(opt_arg);
+ break;
+ case 'c':
+ compress_percent = (int)HDstrtol(opt_arg, NULL, 10);
+
+ if (compress_percent < 0)
+ compress_percent = 0;
+ else if (compress_percent > 100)
+ compress_percent = 100;
+
+ break;
+ case 'p':
+ option_prefix = opt_arg;
+ break;
+ case 'r':
+ random_test = TRUE;
+ break;
+ case 's':
+ file_size = parse_size_directive(opt_arg);
+ break;
+ case '?':
+ usage();
+ exit(EXIT_FAILURE);
+ break;
+ case 'h':
+ default:
+ usage();
+ exit(EXIT_SUCCESS);
+ break;
+ }
+ }
+
+ if (min_buf_size > max_buf_size)
+ error("minmum buffer size (%d) exceeds maximum buffer size (%d)",
+ min_buf_size, max_buf_size);
+
+ HDfprintf(stdout, "Filesize: %ld\n", file_size);
+
+ if (compress_level == Z_DEFAULT_COMPRESSION)
+ HDfprintf(stdout, "Compression Level: 6\n");
+ else
+ HDfprintf(stdout, "Compression Level: %d\n", compress_level);
+
+ get_unique_name();
+ do_write_test(file_size, min_buf_size, max_buf_size);
+ cleanup();
+ return EXIT_SUCCESS;
+}
+
+#else
+
+/*
+ * Function: main
+ * Purpose: Dummy main() function for if HDF5 was configured without
+ * zlib stuff.
+ * Return: EXIT_SUCCESS
+ * Programmer: Bill Wendling, 10. June 2002
+ * Modifications:
+ */
+int
+main(void)
+{
+ HDfprintf(stdout, "No compression IO performance because zlib was not configured\n");
+ return EXIT_SUCCESS;
+}
+
+#endif /* !H5_HAVE_FILTER_DEFLATE */