From a890ba14c34c307a8426087e73eafedef3acb9fe Mon Sep 17 00:00:00 2001 From: Kaiyuan Hou Date: Sun, 4 Dec 2022 15:31:33 -0600 Subject: [PATCH 01/29] add config option to enable chunking feature --- configure.ac | 127 ++++++++++++++++++++++++++++++++++++++++ src/drivers/Makefile.am | 4 ++ 2 files changed, 131 insertions(+) diff --git a/configure.ac b/configure.ac index ae967b40a..f722ebfa8 100644 --- a/configure.ac +++ b/configure.ac @@ -135,6 +135,9 @@ dnl AH_TEMPLATE([ENABLE_IN_PLACE_SWAP], [Define if to enable in-place byte swap] dnl AH_TEMPLATE([DISABLE_IN_PLACE_SWAP],[Define if to disable in-place byte swap]) AH_TEMPLATE([ENABLE_SUBFILING], [Define if to enable subfiling feature]) AH_TEMPLATE([ENABLE_NETCDF4], [Define if to enable NetCDF-4 support]) +AH_TEMPLATE([ENABLE_CHUNKING], [Define if to enable chunked storage layout and chunking feature]) +AH_TEMPLATE([ENABLE_ZLIB], [Define if to enable zlib chunking method]) +AH_TEMPLATE([ENABLE_SZ], [Define if to enable sz chunking method]) AH_TEMPLATE([ENABLE_ADIOS], [Define if to enable ADIOS BP read feature]) AH_TEMPLATE([HDF5_VER_GE_1_10_4], [Define if HDF5 version is at least 1.10.4]) AH_TEMPLATE([NETCDF_GE_4_5_0], [Define if NetCDF version is at least 4.5.0]) @@ -2222,6 +2225,129 @@ fi AC_SUBST(ENABLE_BURST_BUFFER) AM_CONDITIONAL(ENABLE_BURST_BUFFER, [test x$enable_bbdriver = xyes]) +AC_ARG_ENABLE([chunking], + [AS_HELP_STRING([--enable-chunking], + [Enable chunked chunking driver support. @<:@default: disabled@:>@])], + [enable_chunking=${enableval}], [enable_chunking=no] +) + +ENABLE_CHUNKING=0 +if test "x$enable_chunking" = "xyes" ; then + AC_DEFINE(ENABLE_CHUNKING) + ENABLE_CHUNKING=1 +fi +AC_SUBST(ENABLE_CHUNKING) +AM_CONDITIONAL(ENABLE_CHUNKING, [test x$enable_chunking = xyes]) + +AC_ARG_ENABLE([zlib], + [AS_HELP_STRING([--enable-zlib], + [Enable zlib chunking method support. @<:@default: disabled@:>@])], + [enable_zlib=${enableval}], [enable_zlib=no] +) + +ENABLE_ZLIB=0 +if test "x$enable_zlib" = "xyes" ; then + AC_DEFINE(ENABLE_ZLIB) + ENABLE_ZLIB=1 +fi +AC_SUBST(ENABLE_ZLIB) +AM_CONDITIONAL(ENABLE_ZLIB, [test x$enable_zlib = xyes]) + +if test "x$enable_zlib" = "xyes" ; then + ZLIB_INSTALL="" + AC_ARG_WITH(zlib, + [AS_HELP_STRING([--with-zlib=/path/to/implementation], + [installation prefix for zlib implementation])], + if test "x${withval}" = xyes; then + AC_MSG_ERROR(--with-zlib is set but the value is NULL) + else + ZLIB_INSTALL=${withval} + fi + ) + + if test "x${ZLIB_INSTALL}" != x ; then + CPPFLAGS+=" -I${ZLIB_INSTALL}/include" + LDFLAGS+=" -L${ZLIB_INSTALL}/lib" + LIBS+=" -lz" + fi + + LIBS+=" -lm -ldl" + + have_zlib=no + AC_MSG_CHECKING(ZLIB library) + AC_SEARCH_LIBS([deflate], [z], [have_zlib=yes], [have_zlib=no]) + if test "x${have_zlib}" = xyes; then + AC_CHECK_HEADERS([zlib.h], [], [have_zlib=no]) + fi + + if test "x${have_zlib}" = xno; then + AC_MSG_ERROR([ + ------------------------------------------------------------ + The ZLIB library and header file are required to build + PnetCDF with ZLIB chunking support. Use option + --with-zlib=/path/to/implementation + to specify the location of ZLIB build. + Stopping ... + Check 'config.log' for more information. + ------------------------------------------------------------]) + fi +fi + +AC_ARG_ENABLE([sz], + [AS_HELP_STRING([--enable-sz], + [Enable sz chunking method support. @<:@default: disabled@:>@])], + [enable_sz=${enableval}], [enable_sz=no] +) + +ENABLE_SZ=0 +if test "x$enable_sz" = "xyes" ; then + AC_DEFINE(ENABLE_SZ) + ENABLE_SZ=1 +fi +AC_SUBST(ENABLE_SZ) +AM_CONDITIONAL(ENABLE_SZ, [test x$enable_sz = xyes]) + + +if test "x$enable_sz" = "xyes" ; then + SZ_INSTALL="" + AC_ARG_WITH(sz, + [AS_HELP_STRING([--with-sz=/path/to/implementation], + [installation prefix for sz implementation])], + if test "x${withval}" = xyes; then + AC_MSG_ERROR(--with-sz is set but the value is NULL) + else + SZ_INSTALL=${withval} + fi + ) + + if test "x${SZ_INSTALL}" != x ; then + CPPFLAGS+=" -I${SZ_INSTALL}/include" + LDFLAGS+=" -L${SZ_INSTALL}/lib" + LIBS+=" -lSZ -lzstd" + fi + + LIBS+=" -lm -ldl" + + have_sz=no + AC_MSG_CHECKING(SZ library) + AC_SEARCH_LIBS([deflate], [z], [have_sz=yes], [have_sz=no]) + if test "x${have_sz}" = xyes; then + AC_CHECK_HEADERS([sz.h], [], [have_sz=no]) + fi + + if test "x${have_sz}" = xno; then + AC_MSG_ERROR([ + ------------------------------------------------------------ + The SZ library and header file are required to build + PnetCDF with SZ chunking support. Use option + --with-sz=/path/to/implementation + to specify the location of SZ build. + Stopping ... + Check 'config.log' for more information. + ------------------------------------------------------------]) + fi +fi + ADIOS_INSTALL="" AC_ARG_WITH(adios, [AS_HELP_STRING([--with-adios@<:@=DIR@:>@], @@ -2532,6 +2658,7 @@ AC_CONFIG_FILES(Makefile \ src/drivers/nc4io/Makefile \ src/drivers/ncadios/Makefile \ src/drivers/ncbbio/Makefile \ + src/drivers/ncchunkio/Makefile \ src/drivers/ncfoo/Makefile \ src/binding/Makefile \ src/binding/cxx/Makefile \ diff --git a/src/drivers/Makefile.am b/src/drivers/Makefile.am index 3749fcd99..1d8a44314 100644 --- a/src/drivers/Makefile.am +++ b/src/drivers/Makefile.am @@ -20,6 +20,10 @@ if ENABLE_BURST_BUFFER SUBDIRS += ncbbio endif +if ENABLE_CHUNKING + SUBDIRS += ncchunkio +endif + if ENABLE_ADIOS SUBDIRS += ncadios endif From 3c1a9e375ff7b93c3947bf7798ff3a51a2ce6739 Mon Sep 17 00:00:00 2001 From: Kaiyuan Hou Date: Sun, 4 Dec 2022 16:43:13 -0600 Subject: [PATCH 02/29] add chunk drivere --- m4/foreach_idx.m4 | 7 + m4/list_len.m4 | 6 + src/drivers/ncchunkio/DEVELOPER_NOTES.md | 74 ++ src/drivers/ncchunkio/Makefile.am | 97 ++ src/drivers/ncchunkio/ncchk_filter_driver.h | 29 + src/drivers/ncchunkio/ncchk_filter_dummy.c | 137 ++ src/drivers/ncchunkio/ncchk_filter_sz.c | 312 +++++ src/drivers/ncchunkio/ncchk_filter_zlib.c | 295 +++++ src/drivers/ncchunkio/ncchkio_attr.c | 161 +++ src/drivers/ncchunkio/ncchkio_dim.c | 96 ++ src/drivers/ncchunkio/ncchkio_driver.c | 77 ++ src/drivers/ncchunkio/ncchkio_driver.h | 422 ++++++ src/drivers/ncchunkio/ncchkio_file.c | 828 ++++++++++++ src/drivers/ncchunkio/ncchkio_internal.c | 226 ++++ src/drivers/ncchunkio/ncchkio_internal.h | 390 ++++++ src/drivers/ncchunkio/ncchkio_var.c | 1130 +++++++++++++++++ src/drivers/ncchunkio/ncchkioi_cache.c | 113 ++ src/drivers/ncchunkio/ncchkioi_chunk.c | 164 +++ src/drivers/ncchunkio/ncchkioi_chunk_owner.c | 627 +++++++++ src/drivers/ncchunkio/ncchkioi_chunk_size.c | 226 ++++ src/drivers/ncchunkio/ncchkioi_convert.c | 939 ++++++++++++++ src/drivers/ncchunkio/ncchkioi_convert.m4 | 79 ++ src/drivers/ncchunkio/ncchkioi_get_var.c | 879 +++++++++++++ src/drivers/ncchunkio/ncchkioi_get_varn.c | 943 ++++++++++++++ src/drivers/ncchunkio/ncchkioi_iget.c | 230 ++++ src/drivers/ncchunkio/ncchkioi_iget_cb.c | 686 ++++++++++ src/drivers/ncchunkio/ncchkioi_iput.c | 180 +++ src/drivers/ncchunkio/ncchkioi_iput_cb.c | 622 +++++++++ src/drivers/ncchunkio/ncchkioi_lagacy.c | 719 +++++++++++ src/drivers/ncchunkio/ncchkioi_lists.c | 51 + src/drivers/ncchunkio/ncchkioi_nonblocking.c | 208 +++ src/drivers/ncchunkio/ncchkioi_profile.m4 | 98 ++ src/drivers/ncchunkio/ncchkioi_profile.m4h | 75 ++ .../ncchunkio/ncchkioi_profile_timers.m4 | 73 ++ src/drivers/ncchunkio/ncchkioi_put_var.c | 770 +++++++++++ src/drivers/ncchunkio/ncchkioi_put_varn.c | 818 ++++++++++++ src/drivers/ncchunkio/ncchkioi_util.c | 461 +++++++ src/drivers/ncchunkio/ncchkioi_var_init.c | 579 +++++++++ src/drivers/ncchunkio/ncchkioi_var_rd.c | 761 +++++++++++ src/drivers/ncchunkio/ncchkioi_var_resize.c | 177 +++ src/drivers/ncchunkio/ncchkioi_var_wr.c | 638 ++++++++++ src/drivers/ncchunkio/ncchkioi_vector.c | 56 + src/drivers/ncchunkio/ncchkioi_wait.c | 292 +++++ 43 files changed, 15751 insertions(+) create mode 100644 m4/foreach_idx.m4 create mode 100644 m4/list_len.m4 create mode 100644 src/drivers/ncchunkio/DEVELOPER_NOTES.md create mode 100644 src/drivers/ncchunkio/Makefile.am create mode 100644 src/drivers/ncchunkio/ncchk_filter_driver.h create mode 100644 src/drivers/ncchunkio/ncchk_filter_dummy.c create mode 100644 src/drivers/ncchunkio/ncchk_filter_sz.c create mode 100644 src/drivers/ncchunkio/ncchk_filter_zlib.c create mode 100644 src/drivers/ncchunkio/ncchkio_attr.c create mode 100644 src/drivers/ncchunkio/ncchkio_dim.c create mode 100644 src/drivers/ncchunkio/ncchkio_driver.c create mode 100644 src/drivers/ncchunkio/ncchkio_driver.h create mode 100644 src/drivers/ncchunkio/ncchkio_file.c create mode 100644 src/drivers/ncchunkio/ncchkio_internal.c create mode 100644 src/drivers/ncchunkio/ncchkio_internal.h create mode 100644 src/drivers/ncchunkio/ncchkio_var.c create mode 100644 src/drivers/ncchunkio/ncchkioi_cache.c create mode 100644 src/drivers/ncchunkio/ncchkioi_chunk.c create mode 100644 src/drivers/ncchunkio/ncchkioi_chunk_owner.c create mode 100644 src/drivers/ncchunkio/ncchkioi_chunk_size.c create mode 100644 src/drivers/ncchunkio/ncchkioi_convert.c create mode 100644 src/drivers/ncchunkio/ncchkioi_convert.m4 create mode 100644 src/drivers/ncchunkio/ncchkioi_get_var.c create mode 100644 src/drivers/ncchunkio/ncchkioi_get_varn.c create mode 100644 src/drivers/ncchunkio/ncchkioi_iget.c create mode 100644 src/drivers/ncchunkio/ncchkioi_iget_cb.c create mode 100644 src/drivers/ncchunkio/ncchkioi_iput.c create mode 100644 src/drivers/ncchunkio/ncchkioi_iput_cb.c create mode 100644 src/drivers/ncchunkio/ncchkioi_lagacy.c create mode 100644 src/drivers/ncchunkio/ncchkioi_lists.c create mode 100644 src/drivers/ncchunkio/ncchkioi_nonblocking.c create mode 100644 src/drivers/ncchunkio/ncchkioi_profile.m4 create mode 100644 src/drivers/ncchunkio/ncchkioi_profile.m4h create mode 100644 src/drivers/ncchunkio/ncchkioi_profile_timers.m4 create mode 100644 src/drivers/ncchunkio/ncchkioi_put_var.c create mode 100644 src/drivers/ncchunkio/ncchkioi_put_varn.c create mode 100644 src/drivers/ncchunkio/ncchkioi_util.c create mode 100644 src/drivers/ncchunkio/ncchkioi_var_init.c create mode 100644 src/drivers/ncchunkio/ncchkioi_var_rd.c create mode 100644 src/drivers/ncchunkio/ncchkioi_var_resize.c create mode 100644 src/drivers/ncchunkio/ncchkioi_var_wr.c create mode 100644 src/drivers/ncchunkio/ncchkioi_vector.c create mode 100644 src/drivers/ncchunkio/ncchkioi_wait.c diff --git a/m4/foreach_idx.m4 b/m4/foreach_idx.m4 new file mode 100644 index 000000000..fccde380c --- /dev/null +++ b/m4/foreach_idx.m4 @@ -0,0 +1,7 @@ +divert(`-1') +# foreach_idx(x, idx, (item_1, item_2, ..., item_n), stmt) +# parenthesized list, simple version +define(`foreach_idx', `pushdef(`$1')pushdef(`$2')_foreach_idx($@,0)popdef(`$2')popdef(`$1')') +define(`_arg1', `$1') +define(`_foreach_idx', `ifelse(`$3', `()', `',`define(`$1', _arg1$3)define(`$2', `$5')$4`'$0(`$1', `$2', (shift$3), `$4',incr($5))')') +divert`'dnl \ No newline at end of file diff --git a/m4/list_len.m4 b/m4/list_len.m4 new file mode 100644 index 000000000..7e6590eed --- /dev/null +++ b/m4/list_len.m4 @@ -0,0 +1,6 @@ +divert(`-1') +# list_len((item_1, item_2, ..., item_n)) +# parenthesized list, simple version +define(`list_len', `_list_len($@, 0)')`'dnl +define(`_list_len',`ifelse(`$1', `()', `$2', `$0((shift$1), incr(`$2'))')')`'dnl +divert`'dnl \ No newline at end of file diff --git a/src/drivers/ncchunkio/DEVELOPER_NOTES.md b/src/drivers/ncchunkio/DEVELOPER_NOTES.md new file mode 100644 index 000000000..99ee038f6 --- /dev/null +++ b/src/drivers/ncchunkio/DEVELOPER_NOTES.md @@ -0,0 +1,74 @@ +# Note for Developers + +### Table of contents +- [Future Work] +- [Internal global attributes] +- [Anchor variable (one per variable with chunking enabled)] +- [Reference table] +- [Chunks] +- [Requirement for compressed variables] + +--- + +## Internal global attributes: + * Number of chunked variables + +## Anchor variable (one per variable with chunking enabled): + * A scalar variable + * Data type is the same as user defined + * Internal attributes + + Dimension IDs are saved as an attribute of an array of integer type + + Number of dimensions is saved as an internal attribute + + An attribute to tell whether it is a fixed-size or record variable + + An attribute offset pointer to reference table + * For fixed-size variable, it is a scalar + * For record variable, it is an array of 8-type integers, one for each record + * This array can be allocated in multiple of 16 for example + * Need an integer for allocated size, e.g. multiple of 16 + * Need an integer for size (true number of records written) + + An attributes for chunk sizes, an integer array + + An attributes for compression algorithm + + An attributes for compression level + * If a variable missing these internal attributes, it is a traditional variable + +## Reference table: + * An array stores offsets of individual chunks + * Not a NetCDF variable. But we use the CDF5 format specification to define it + + TODO: give it a formal spec in BNF grammar + * For a fixed-size variable, it is a 1D array of size equal to the number of chunks + * This table is loaded into memory when calling ncmpi_inq_varid + * For blocking API, it is sync-ed and written to file by root + + TODO: in future, it can be written by multiple ranks in parallel + * For nonblocking API, multiple tables are written by multiple ranks in parallel + +## Chunks: + * Chunks are not NetCDF variables + + TODO: give it a formal spec in BNF grammar? + * Chunks are stored in space between NetCDF variables, i.e. padding areas in files + * Data is type-converted and byte-swapped before compression + * In principle, chunks should be stored in file contiguously with each other, + for all variables. But they are not required to be stored contiguously. + * The storage order of chunks is in row major + +## Requirement for compressed variables: + * Collective I/O only (this is the same required by HDF5) + * Must be chunked (same as HDF5) + + +## Future Work +* Reuse metadata accross variables + - Variable from same simulation space may have same access apttern. + - Instead of generating variable metadata and indexx table separately, we can + share information accross variables. + - Chunk sizeand chunk ownership info can be reused. +* Data seiving + - When rewriting to a chunk, we do't need to read the background if it is + fully overwritten. + - Need an efficient way to determine whether a chunk is fully rewrititen. + - It may be infesible due to communication and computation cost. + - HDF5 approximate this by checking if owner fully rewriten the chunk. +* Reuse metadata accross records + - I/O pattern accross time steps are likely the same. + - If we detect same I/O pattern as previous record, we can skip sending the metadata. + - MPI datatype created for previous timestep can also be reused. +--- diff --git a/src/drivers/ncchunkio/Makefile.am b/src/drivers/ncchunkio/Makefile.am new file mode 100644 index 000000000..882e49ba9 --- /dev/null +++ b/src/drivers/ncchunkio/Makefile.am @@ -0,0 +1,97 @@ +# +# Copyright (C) 2012, Northwestern University and Argonne National Laboratory +# See COPYRIGHT notice in top-level directory. +# +# $Id: Makefile.am 3283 2017-07-30 21:10:11Z wkliao $ +# +# @configure_input@ + +SUFFIXES = .a .o .c .m4 .h + +AM_CPPFLAGS = -I${top_srcdir}/src/include +AM_CPPFLAGS += -I${top_builddir}/src/include +AM_CPPFLAGS += -I${top_srcdir}/src/drivers/include +AM_CPPFLAGS += -I${top_builddir}/src/drivers/include + +if PNETCDF_DEBUG + AM_CPPFLAGS += -DPNETCDF_DEBUG +endif + +if PNETCDF_PROFILING + AM_CPPFLAGS += -DPNETCDF_PROFILING +endif + +noinst_LTLIBRARIES = libncchkio.la + +M4FLAGS += -I${top_srcdir}/m4 +if ENABLE_ERANGE_FILL +M4FLAGS += -DERANGE_FILL +endif + +M4_SRCS = ncchkioi_profile.m4 \ + ncchkioi_convert.m4 + +M4H_SRCS = ncchkioi_profile.m4h + +H_SRCS = ncchkio_driver.h + +C_SRCS = ncchkio_attr.c \ + ncchkio_dim.c \ + ncchkio_driver.c \ + ncchkio_file.c \ + ncchkio_var.c \ + ncchkio_internal.c \ + ncchkioi_util.c \ + ncchkioi_put_var.c \ + ncchkioi_get_var.c \ + ncchkioi_put_varn.c \ + ncchkioi_get_varn.c \ + ncchkioi_iput_cb.c \ + ncchkioi_iget_cb.c \ + ncchkioi_iput.c \ + ncchkioi_iget.c \ + ncchkioi_nonblocking.c \ + ncchkioi_cache.c \ + ncchkioi_chunk.c \ + ncchkioi_chunk_size.c \ + ncchkioi_chunk_owner.c \ + ncchkioi_var_init.c \ + ncchkioi_var_resize.c \ + ncchkioi_var_wr.c \ + ncchkioi_var_rd.c \ + ncchkioi_lists.c \ + ncchkioi_nonblocking.c \ + ncchkioi_wait.c \ + ncchk_filter_dummy.c + +if ENABLE_ZLIB + C_SRCS += ncchk_filter_zlib.c +endif + +if ENABLE_SZ + C_SRCS += ncchk_filter_sz.c +endif + +$(M4_SRCS:.m4=.c): Makefile +$(M4H_SRCS:.m4h=.h): Makefile + +.m4.c: + $(M4) $(AM_M4FLAGS) $(M4FLAGS) $< >$@ + +.m4h.h: + $(M4) $(AM_M4FLAGS) $(M4FLAGS) $< >$@ + +libncchkio_la_SOURCES = $(C_SRCS) $(H_SRCS) +nodist_libncchkio_la_SOURCES = $(M4_SRCS:.m4=.c) $(M4H_SRCS:.m4h=.h) + +# automake says "... BUILT_SOURCES is honored only by 'make all', 'make check', +# and 'make install'. This means you cannot build a specific target (e.g., +# 'make target') in a clean tree if it depends on a built source." +BUILT_SOURCES = $(M4_SRCS:.m4=.c) $(M4H_SRCS:.m4h=.h) + +CLEANFILES = $(M4_SRCS:.m4=.c) $(M4H_SRCS:.m4h=.h) core core.* *.gcda *.gcno *.gcov gmon.out + +EXTRA_DIST = $(M4_HFILES) $(M4_SRCS) $(M4H_SRCS) + +tests-local: all + diff --git a/src/drivers/ncchunkio/ncchk_filter_driver.h b/src/drivers/ncchunkio/ncchk_filter_driver.h new file mode 100644 index 000000000..b406587fc --- /dev/null +++ b/src/drivers/ncchunkio/ncchk_filter_driver.h @@ -0,0 +1,29 @@ +#ifndef NCCHK_FILTER_DRIVER_H +#define NCCHK_FILTER_DRIVER_H + +#include + +struct NCCHK_filter { + int (*init)(MPI_Info); + int (*finalize)(); + int (*inq_cpsize)(void*, int, int*, int, int*, MPI_Datatype); + int (*compress)(void*, int, void*, int*, int, int*, MPI_Datatype); + int (*compress_alloc)(void*, int, void**, int*, int, int*, MPI_Datatype); + int (*inq_dcsize)(void*, int, int*, int, int*, MPI_Datatype); + int (*decompress)(void*, int, void*, int*, int, int*, MPI_Datatype); + int (*decompress_alloc)(void*, int, void**, int*, int, int*, MPI_Datatype); +}; + +typedef struct NCCHK_filter NCCHK_filter; + +extern NCCHK_filter* ncchk_dummy_inq_driver(void); + +#if ENABLE_ZLIB +extern NCCHK_filter* ncchk_zlib_inq_driver(void); +#endif + +#if ENABLE_SZ +extern NCCHK_filter* ncchk_sz_inq_driver(void); +#endif + +#endif \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchk_filter_dummy.c b/src/drivers/ncchunkio/ncchk_filter_dummy.c new file mode 100644 index 000000000..59e7b8762 --- /dev/null +++ b/src/drivers/ncchunkio/ncchk_filter_dummy.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2017, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +int ncchk_dummy_init(MPI_Info info) { + return NC_NOERR; +} + +int ncchk_dummy_finalize() { + return NC_NOERR; +} + +/* Return an estimated compressed data size + * Actual compressed size should not exceed the estimation + */ +int ncchk_dummy_inq_cpsize(void *in, int in_len, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + *out_len = in_len; + return NC_NOERR; +} + +/* If out_len is large enough, compress the data at in and save it to out. out_len is set to actual compressed data size + * If out_len is NULL, we assume out is large enough for compressed data + */ +int ncchk_dummy_compress(void *in, int in_len, void *out, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + if (out_len != NULL){ + // Check output buffer size + if ((*out_len) < in_len){ + DEBUG_RETURN_ERROR(NC_ENOMEM); + } + + // Overwrite output buffer size with actual size + *out_len = in_len; + } + + // Copy data directly as dummy comrpession + memcpy(out, in, in_len); + + return NC_NOERR; +} + +/* Compress the data at in and save it to a newly allocated buffer at out. out_len is set to actual compressed data size + * The caller is responsible to free the buffer + * If out_len is not NULL, it will be set to buffer size allocated + */ +int ncchk_dummy_compress_alloc(void *in, int in_len, void **out, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + // Allocate output buffer + *out = (void*)malloc(in_len); + + // Buffer size + if (out_len != NULL) { + *out_len = in_len; + } + + // Copy data directly as dummy comrpession + memcpy(*out, in, in_len); + + return NC_NOERR; +} + +/* Return an estimated decompressed data size + * Actual decompressed size should not exceed the estimation + */ +int ncchk_dummy_inq_dcsize(void *in, int in_len, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + *out_len = in_len; + return NC_NOERR; +} + +/* If out_len is large enough, decompress the data at in and save it to out. out_len is set to actual decompressed size + * If out_len is NULL, we assume out is large enough for decompressed data + */ +int ncchk_dummy_decompress(void *in, int in_len, void *out, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + if (out_len != NULL){ + // Check output buffer size + if ((*out_len) < in_len){ + DEBUG_RETURN_ERROR(NC_ENOMEM); + } + + // Overwrite output buffer size with actual size + *out_len = in_len; + } + + // Copy data directly as dummy comrpession + memcpy(out, in, in_len); + + return NC_NOERR; +} + +/* Decompress the data at in and save it to a newly allocated buffer at out. out_len is set to actual decompressed data size + * The caller is responsible to free the buffer + * If out_len is not NULL, it will be set to buffer size allocated + */ +int ncchk_dummy_decompress_alloc(void *in, int in_len, void **out, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + // Allocate output buffer + *out = (void*)malloc(in_len); + + // Buffer size + if (out_len != NULL) { + *out_len = in_len; + } + + // Copy data directly as dummy comrpession + memcpy(*out, in, in_len); + + return NC_NOERR; +} + +static NCCHK_filter ncchkio_driver = { + ncchk_dummy_init, + ncchk_dummy_finalize, + ncchk_dummy_inq_cpsize, + ncchk_dummy_compress, + ncchk_dummy_compress_alloc, + ncchk_dummy_inq_dcsize, + ncchk_dummy_decompress, + ncchk_dummy_decompress_alloc +}; + +NCCHK_filter* ncchk_dummy_inq_driver(void) { + return &ncchkio_driver; +} + diff --git a/src/drivers/ncchunkio/ncchk_filter_sz.c b/src/drivers/ncchunkio/ncchk_filter_sz.c new file mode 100644 index 000000000..ca5de3419 --- /dev/null +++ b/src/drivers/ncchunkio/ncchk_filter_sz.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2017, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +static int mpi_to_sz_type(MPI_Datatype dtype){ + if (dtype == MPI_FLOAT){ + return SZ_FLOAT; + } + else if (dtype == MPI_DOUBLE){ + return SZ_DOUBLE; + } + else if (dtype == MPI_BYTE){ + return SZ_UINT8; + } + else if (dtype == MPI_CHAR){ + return SZ_INT8; + } + else if (dtype == MPI_SHORT){ + return SZ_INT16; + } + else if (dtype == MPI_UNSIGNED_SHORT){ + return SZ_UINT16; + } + else if (dtype == MPI_INT){ + return SZ_INT32; + } + else if (dtype == MPI_UNSIGNED){ + return SZ_UINT32; + } + else if (dtype == MPI_LONG_LONG){ + return SZ_INT64; + } + else if (dtype == MPI_UNSIGNED_LONG_LONG){ + return SZ_UINT64; + } + + return -1; +} + +int ncchk_sz_init(MPI_Info info) { + sz_params sz; + + memset(&sz, 0, sizeof(sz_params)); + sz.sol_ID = SZ; + sz.sampleDistance = 50; + sz.quantization_intervals = 0; + sz.max_quant_intervals = 65536; + sz.predThreshold = 0.98; + sz.szMode = SZ_BEST_COMPRESSION; + sz.losslessCompressor = ZSTD_COMPRESSOR; + sz.gzipMode = 1; + sz.errorBoundMode = ABS; + sz.absErrBound = 1E-3; + sz.relBoundRatio = 1E-5; + SZ_Init_Params(&sz); + + return NC_NOERR; +} + +int ncchk_sz_finalize() { + SZ_Finalize(); + + return NC_NOERR; +} + +/* Return an estimated compressed data size + * Actual compressed size should not exceed the estimation + */ +int ncchk_sz_inq_cpsize(void *in, int in_len, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + return NC_ENOTSUPPORT; // sz has no size estimation +} + +/* If out_len is large enough, compress the data at in and save it to out. out_len is set to actual compressed data size + * If out_len is NULL, we assume out is large enough for compressed data + */ +int ncchk_sz_compress(void *in, int in_len, void *out, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + int err; + int i; + int szdtype; + size_t r[4]; + size_t outsize; + void *buf = NULL; + + szdtype = mpi_to_sz_type(dtype); + if (szdtype < 0){ + DEBUG_ASSIGN_ERROR(err, NC_EINVAL) + goto out; + } + + for(i = 0; i < 4; i++){ + if (i < ndim){ + r[i] = dims[i]; + } + else{ + r[i] = 0; + } + } + for(i = 4; i < ndim; i++){ + r[3] *= dims[i]; + } + + buf = SZ_compress(szdtype, in, &outsize, 0, r[3], r[2], r[1], r[0]); + + if (out_len != NULL){ + // If buffer not large enough + if (*out_len < outsize){ + DEBUG_ASSIGN_ERROR(err, NC_ENOMEM) + goto out; + } + + // Size of comrpessed data + *out_len = outsize; + } + + memcpy(out, buf, outsize); + +out: + if (buf != NULL){ + free(buf); + } + + return err; +} + +/* Compress the data at in and save it to a newly allocated buffer at out. out_len is set to actual compressed data size + * The caller is responsible to free the buffer + * If out_len is not NULL, it will be set to buffer size allocated + */ +int ncchk_sz_compress_alloc(void *in, int in_len, void **out, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + int err; + int i; + int szdtype; + size_t r[4]; + size_t outsize; + void *buf = NULL; + + szdtype = mpi_to_sz_type(dtype); + if (szdtype < 0){ + DEBUG_ASSIGN_ERROR(err, NC_EINVAL) + goto out; + } + + for(i = 0; i < 4; i++){ + if (i < ndim){ + r[i] = dims[i]; + } + else{ + r[i] = 0; + } + } + for(i = 4; i < ndim; i++){ + r[3] *= dims[i]; + } + + *out = SZ_compress(szdtype, in, &outsize, 0, r[3], r[2], r[1], r[0]); + + if (out_len != NULL){ + // Size of comrpessed data + *out_len = outsize; + } + +out: + if (buf != NULL){ + free(buf); + } + + return err; +} + +/* Return an estimated decompressed data size + * Actual decompressed size should not exceed the estimation + */ +int ncchk_sz_inq_dcsize(void *in, int in_len, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + return NC_ENOTSUPPORT; // sz has no size estimation +} + +/* If out_len is large enough, decompress the data at in and save it to out. out_len is set to actual decompressed size + * If out_len is NULL, we assume out is large enough for decompressed data + */ +int ncchk_sz_decompress(void *in, int in_len, void *out, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + int err; + int i; + size_t r[4]; + int szdtype; + int outsize; + void *buf = NULL; + + szdtype = mpi_to_sz_type(dtype); + if (szdtype < 0){ + DEBUG_ASSIGN_ERROR(err, NC_EINVAL) + goto out; + } + + MPI_Type_size(dtype, &outsize); + for(i = 0; i < 4; i++){ + if (i < ndim){ + r[i] = dims[i]; + outsize *= dims[i]; + } + else{ + r[i] = 0; + } + } + for(i = 4; i < ndim; i++){ + r[3] *= dims[i]; + outsize *= dims[i]; + } + + buf = SZ_decompress(szdtype, in, (size_t)in_len, 0, r[3], r[2], r[1], r[0]); + + if (out_len != NULL){ + // If buffer not large enough + if (*out_len < outsize){ + DEBUG_ASSIGN_ERROR(err, NC_ENOMEM) + goto out; + } + + // Size of comrpessed data + *out_len = outsize; + } + + memcpy(out, buf, outsize); + +out: + if (buf != NULL){ + free(buf); + } + + return err; +} + +/* Decompress the data at in and save it to a newly allocated buffer at out. out_len is set to actual decompressed data size + * The caller is responsible to free the buffer + * If out_len is not NULL, it will be set to buffer size allocated + */ +int ncchk_sz_decompress_alloc(void *in, int in_len, void **out, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + int err; + int i; + size_t r[4]; + int szdtype; + int outsize; + void *buf = NULL; + + szdtype = mpi_to_sz_type(dtype); + if (szdtype < 0){ + DEBUG_ASSIGN_ERROR(err, NC_EINVAL) + goto out; + } + + MPI_Type_size(dtype, &outsize); + for(i = 0; i < 4; i++){ + if (i < ndim){ + r[i] = dims[i]; + outsize *= dims[i]; + } + else{ + r[i] = 0; + } + } + for(i = 4; i < ndim; i++){ + r[3] *= dims[i]; + outsize *= dims[i]; + } + + *out = SZ_decompress(szdtype, in, (size_t)in_len, 0, r[3], r[2], r[1], r[0]); + + if (out_len != NULL){ + // Size of comrpessed data + *out_len = outsize; + } + +out: + if (buf != NULL){ + free(buf); + } + + return err; +} + +static NCCHK_filter ncchk_driver_sz = { + ncchk_sz_init, + ncchk_sz_finalize, + ncchk_sz_inq_cpsize, + ncchk_sz_compress, + ncchk_sz_compress_alloc, + ncchk_sz_inq_dcsize, + ncchk_sz_decompress, + ncchk_sz_decompress_alloc +}; + +NCCHK_filter* ncchk_sz_inq_driver(void) { + return &ncchk_driver_sz; +} + diff --git a/src/drivers/ncchunkio/ncchk_filter_zlib.c b/src/drivers/ncchunkio/ncchk_filter_zlib.c new file mode 100644 index 000000000..fff5085f2 --- /dev/null +++ b/src/drivers/ncchunkio/ncchk_filter_zlib.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2017, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +int ncchk_zlib_init(MPI_Info info) { + return NC_NOERR; +} + +int ncchk_zlib_finalize() { + return NC_NOERR; +} + +/* Return an estimated compressed data size + * Actual compressed size should not exceed the estimation + */ +int ncchk_zlib_inq_cpsize(void *in, int in_len, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + return NC_ENOTSUPPORT; // Zlib has no size estimation +} + +/* If out_len is large enough, compress the data at in and save it to out. out_len is set to actual compressed data size + * If out_len is NULL, we assume out is large enough for compressed data + */ +int ncchk_zlib_compress(void *in, int in_len, void *out, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + int err; + + // zlib struct + z_stream defstream; + defstream.zalloc = Z_NULL; + defstream.zfree = Z_NULL; + defstream.opaque = Z_NULL; + defstream.avail_in = (uInt)(in_len); // input size + defstream.next_in = (Bytef*)in; // input + if (out_len != NULL){ + defstream.avail_out = (uInt)(*out_len); // output buffer size + } + else{ + defstream.avail_out = (uInt)1000000000; // Assume it is large enough + } + defstream.next_out = (Bytef *)out; // output buffer + + // the actual compression work. + err = deflateInit(&defstream, Z_DEFAULT_COMPRESSION); + if (err != Z_OK){ + printf("deflateInit fail: %d: %s\n", err, defstream.msg); + DEBUG_RETURN_ERROR(NC_EIO) + } + err = deflate(&defstream, Z_FINISH); + if (err != Z_STREAM_END){ + printf("deflate fail: %d: %s\n", err, defstream.msg); + DEBUG_RETURN_ERROR(NC_EIO) + } + err = deflateEnd(&defstream); + if (err != Z_OK){ + printf("deflateEnd fail: %d: %s\n", err, defstream.msg); + DEBUG_RETURN_ERROR(NC_EIO) + } + + // If buffer not large enough + if (defstream.avail_in > 0){ + DEBUG_RETURN_ERROR(NC_ENOMEM) + } + + // Size of comrpessed data + if (out_len != NULL){ + *out_len = defstream.total_out; + } + + return NC_NOERR; +} + +/* Compress the data at in and save it to a newly allocated buffer at out. out_len is set to actual compressed data size + * The caller is responsible to free the buffer + * If out_len is not NULL, it will be set to buffer size allocated + */ +int ncchk_zlib_compress_alloc(void *in, int in_len, void **out, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + int err; + int bsize; // Start by 1/8 of the in_len + char *buf; + + bsize = in_len >> 3; + if (bsize < 6){ + bsize = 6; + } + buf = (char*)malloc(bsize); + + // zlib struct + z_stream defstream; + defstream.zalloc = Z_NULL; + defstream.zfree = Z_NULL; + defstream.opaque = Z_NULL; + defstream.avail_in = (uInt)(in_len); // input size + defstream.next_in = (Bytef*)in; // input + defstream.avail_out = (uInt)(bsize); // output buffer size + defstream.next_out = (Bytef *)buf; // output buffer + + // Initialize deflat stream + err = deflateInit(&defstream, Z_DEFAULT_COMPRESSION); + if (err != Z_OK){ + printf("deflateInit fail: %d: %s\n", err, defstream.msg); + DEBUG_RETURN_ERROR(NC_EIO) + } + + // The actual compression work + err = Z_OK; + while (err != Z_STREAM_END){ + // Compress data + err = deflate(&defstream, Z_NO_FLUSH | Z_FINISH); + // Check if buffer is lage enough + if (err != Z_STREAM_END){ + // Enlarge buffer + buf = (char*)realloc(buf, bsize << 1); + + // Reset buffer info in stream + defstream.next_out = buf + bsize; + defstream.avail_out = bsize; + + // Reocrd new buffer size + bsize <<= 1; + } + } + + // Finalize deflat stream + err = deflateEnd(&defstream); + if (err != Z_OK){ + printf("deflateEnd fail: %d: %s\n", err, defstream.msg); + DEBUG_RETURN_ERROR(NC_EIO) + } + + // Size of comrpessed data + if (out_len != NULL){ + *out_len = defstream.total_out; + } + + // Compressed data + *out = buf; + + return NC_NOERR; +} + +/* Return an estimated decompressed data size + * Actual decompressed size should not exceed the estimation + */ +int ncchk_zlib_inq_dcsize(void *in, int in_len, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + return NC_ENOTSUPPORT; // Zlib has no size estimation +} + +/* If out_len is large enough, decompress the data at in and save it to out. out_len is set to actual decompressed size + * If out_len is NULL, we assume out is large enough for decompressed data + */ +int ncchk_zlib_decompress(void *in, int in_len, void *out, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + int err; + + // zlib struct + z_stream infstream; + infstream.zalloc = Z_NULL; + infstream.zfree = Z_NULL; + infstream.opaque = Z_NULL; + infstream.avail_in = (unsigned long) in_len; // input size + infstream.next_in = (Bytef *)in; // input + if (out_len != NULL){ + infstream.avail_out = (uInt)(*out_len); // output buffer size + } + else{ + infstream.avail_out = (uInt)1000000000; // Assume it is large enough + } + infstream.next_out = (Bytef *)out; // buffer size + + // the actual decompression work. + err = inflateInit(&infstream); + if (err != Z_OK){ + printf("inflateInit fail: %d: %s\n", err, infstream.msg); + DEBUG_RETURN_ERROR(NC_EIO) + } + err = inflate(&infstream, Z_FINISH); + if (err != Z_STREAM_END){ + printf("inflate fail: %d: %s\n", err, infstream.msg); + DEBUG_RETURN_ERROR(NC_EIO) + } + err = inflateEnd(&infstream); + if (err != Z_OK){ + printf("inflateEnd fail: %d: %s\n", err, infstream.msg); + DEBUG_RETURN_ERROR(NC_EIO) + } + + // If buffer not large enough + if (infstream.avail_in > 0){ + DEBUG_RETURN_ERROR(NC_ENOMEM) + } + + // Size of decomrpessed data + if (out_len != NULL){ + *out_len = infstream.total_out; + } + + return NC_NOERR; +} + +/* Decompress the data at in and save it to a newly allocated buffer at out. out_len is set to actual decompressed data size + * The caller is responsible to free the buffer + * If out_len is not NULL, it will be set to buffer size allocated + */ +int ncchk_zlib_decompress_alloc(void *in, int in_len, void **out, int *out_len, int ndim, int *dims, MPI_Datatype dtype) { + int err; + int bsize = in_len << 1; // Start by 2 times of the in_len + char *buf; + + buf = (char*)malloc(bsize); + + // zlib struct + z_stream infstream; + infstream.zalloc = Z_NULL; + infstream.zfree = Z_NULL; + infstream.opaque = Z_NULL; + infstream.avail_in = (uInt)(in_len); // input size + infstream.next_in = (Bytef*)in; // input + infstream.avail_out = (uInt)(bsize); // output buffer size + infstream.next_out = (Bytef *)buf; // output buffer + + // Initialize deflat stream + err = inflateInit(&infstream); + if (err != Z_OK){ + printf("inflateInit fail: %d: %s\n", err, infstream.msg); + DEBUG_RETURN_ERROR(NC_EIO) + } + + // The actual decompression work + err = Z_OK; + while (err != Z_STREAM_END){ + // Compress data + err = inflate(&infstream, Z_NO_FLUSH | Z_FINISH); + // Check if buffer is lage enough + if (err != Z_STREAM_END){ + // Enlarge buffer + buf = (char*)realloc(buf, bsize << 1); + + // Reset buffer info in stream + infstream.next_out = buf + bsize; + infstream.avail_out = bsize; + + // Reocrd new buffer size + bsize <<= 1; + } + } + + // Finalize deflat stream + err = inflateEnd(&infstream); + if (err != Z_OK){ + printf("inflateEnd fail: %d: %s\n", err, infstream.msg); + DEBUG_RETURN_ERROR(NC_EIO) + } + + // Size of comrpessed data + if (out_len != NULL){ + *out_len = infstream.total_out; + } + + // Compressed data + *out = buf; + + return NC_NOERR; +} + +static NCCHK_filter ncchk_driver_zlib = { + ncchk_zlib_init, + ncchk_zlib_finalize, + ncchk_zlib_inq_cpsize, + ncchk_zlib_compress, + ncchk_zlib_compress_alloc, + ncchk_zlib_inq_dcsize, + ncchk_zlib_decompress, + ncchk_zlib_decompress_alloc +}; + +NCCHK_filter* ncchk_zlib_inq_driver(void) { + return &ncchk_driver_zlib; +} + diff --git a/src/drivers/ncchunkio/ncchkio_attr.c b/src/drivers/ncchunkio/ncchkio_attr.c new file mode 100644 index 000000000..caa50e161 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkio_attr.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2017, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_inq_attname() : dispatcher->inq_attname() + * ncmpi_inq_attid() : dispatcher->inq_attid() + * ncmpi_inq_att() : dispatcher->inq_att() + * ncmpi_rename_att() : dispatcher->inq_rename_att() + * ncmpi_copy_att() : dispatcher->inq_copy_att() + * ncmpi_del_att() : dispatcher->inq_del_att() + * ncmpi_get_att() : dispatcher->inq_get_att() + * ncmpi_put_att() : dispatcher->inq_put_arr() + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include +#include +#include +#include "ncchkio_internal.h" + +int +ncchkio_inq_attname(void *ncdp, + int varid, + int attid, + char *name) +{ + int err; + NC_chk *ncchkp = (NC_chk*)ncdp; + + err = ncchkp->driver->inq_attname(ncchkp->ncp, varid, attid, name); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int +ncchkio_inq_attid(void *ncdp, + int varid, + const char *name, + int *attidp) +{ + int err; + NC_chk *ncchkp = (NC_chk*)ncdp; + + err = ncchkp->driver->inq_attid(ncchkp->ncp, varid, name, attidp); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int +ncchkio_inq_att(void *ncdp, + int varid, + const char *name, + nc_type *datatypep, + MPI_Offset *lenp) +{ + int err; + NC_chk *ncchkp = (NC_chk*)ncdp; + + err = ncchkp->driver->inq_att(ncchkp->ncp, varid, name, datatypep, lenp); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int +ncchkio_rename_att(void *ncdp, + int varid, + const char *name, + const char *newname) +{ + int err; + NC_chk *ncchkp = (NC_chk*)ncdp; + + err = ncchkp->driver->rename_att(ncchkp->ncp, varid, name, newname); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + + +int +ncchkio_copy_att(void *ncdp_in, + int varid_in, + const char *name, + void *ncdp_out, + int varid_out) +{ + int err; + NC_chk *foo_in = (NC_chk*)ncdp_in; + NC_chk *foo_out = (NC_chk*)ncdp_out; + + err = foo_in->driver->copy_att(foo_in->ncp, varid_in, name, + foo_out->ncp, varid_out); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int +ncchkio_del_att(void *ncdp, + int varid, + const char *name) +{ + int err; + NC_chk *ncchkp = (NC_chk*)ncdp; + + err = ncchkp->driver->del_att(ncchkp->ncp, varid, name); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int +ncchkio_get_att(void *ncdp, + int varid, + const char *name, + void *buf, + MPI_Datatype itype) +{ + int err; + NC_chk *ncchkp = (NC_chk*)ncdp; + + err = ncchkp->driver->get_att(ncchkp->ncp, varid, name, buf, itype); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int +ncchkio_put_att(void *ncdp, + int varid, + const char *name, + nc_type xtype, + MPI_Offset nelems, + const void *buf, + MPI_Datatype itype) +{ + int err; + NC_chk *ncchkp = (NC_chk*)ncdp; + + err = ncchkp->driver->put_att(ncchkp->ncp, varid, name, xtype, nelems, buf, + itype); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} diff --git a/src/drivers/ncchunkio/ncchkio_dim.c b/src/drivers/ncchunkio/ncchkio_dim.c new file mode 100644 index 000000000..8933b0de8 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkio_dim.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_def_dim() : dispatcher->def_dim() + * ncmpi_inq_dimid() : dispatcher->inq_dimid() + * ncmpi_inq_dim() : dispatcher->inq_dim() + * ncmpi_rename_dim() : dispatcher->rename_dim() + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include + +#include +#include +#include +#include "ncchkio_internal.h" + +int +ncchkio_def_dim(void *ncdp, + const char *name, + MPI_Offset size, + int *dimidp) +{ + int err; + NC_chk *ncchkp = (NC_chk*)ncdp; + + err = ncchkp->driver->def_dim(ncchkp->ncp, name, size, dimidp); + if (err != NC_NOERR) return err; + + if (size == NC_UNLIMITED){ + ncchkp->recdim = *dimidp; + } + + return NC_NOERR; +} + +int +ncchkio_inq_dimid(void *ncdp, + const char *name, + int *dimid) +{ + int err; + NC_chk *ncchkp = (NC_chk*)ncdp; + + err = ncchkp->driver->inq_dimid(ncchkp->ncp, name, dimid); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int +ncchkio_inq_dim(void *ncdp, + int dimid, + char *name, + MPI_Offset *sizep) +{ + int err; + NC_chk *ncchkp = (NC_chk*)ncdp; + + err = ncchkp->driver->inq_dim(ncchkp->ncp, dimid, name, sizep); + if (err != NC_NOERR) return err; + + if (dimid == ncchkp->recdim){ // update # records + if (*sizep < ncchkp->recsize){ + *sizep = ncchkp->recsize; + } + } + + return NC_NOERR; +} + +int +ncchkio_rename_dim(void *ncdp, + int dimid, + const char *newname) +{ + int err; + NC_chk *ncchkp = (NC_chk*)ncdp; + + err = ncchkp->driver->rename_dim(ncchkp->ncp, dimid, newname); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} diff --git a/src/drivers/ncchunkio/ncchkio_driver.c b/src/drivers/ncchunkio/ncchkio_driver.c new file mode 100644 index 000000000..1fda000f5 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkio_driver.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2017, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +static PNC_driver ncchkio_driver = { + /* FILE APIs */ + ncchkio_create, + ncchkio_open, + ncchkio_close, + ncchkio_enddef, + ncchkio__enddef, + ncchkio_redef, + ncchkio_sync, + ncchkio_flush, + ncchkio_abort, + ncchkio_set_fill, + ncchkio_inq, + ncchkio_inq_misc, + ncchkio_sync_numrecs, + ncchkio_begin_indep_data, + ncchkio_end_indep_data, + + /* DIMENSION APIs */ + ncchkio_def_dim, + ncchkio_inq_dimid, + ncchkio_inq_dim, + ncchkio_rename_dim, + + /* ATTRIBUTE APIs */ + ncchkio_inq_att, + ncchkio_inq_attid, + ncchkio_inq_attname, + ncchkio_copy_att, + ncchkio_rename_att, + ncchkio_del_att, + ncchkio_get_att, + ncchkio_put_att, + + /* VARIABLE APIs */ + ncchkio_def_var, + ncchkio_def_var_fill, + ncchkio_fill_var_rec, + ncchkio_inq_var, + ncchkio_inq_varid, + ncchkio_rename_var, + ncchkio_get_var, + ncchkio_put_var, + ncchkio_get_varn, + ncchkio_put_varn, + ncchkio_get_vard, + ncchkio_put_vard, + ncchkio_iget_var, + ncchkio_iput_var, + ncchkio_bput_var, + ncchkio_iget_varn, + ncchkio_iput_varn, + ncchkio_bput_varn, + + ncchkio_buffer_attach, + ncchkio_buffer_detach, + ncchkio_wait, + ncchkio_cancel +}; + +PNC_driver* ncchkio_inq_driver(void) { + return &ncchkio_driver; +} + diff --git a/src/drivers/ncchunkio/ncchkio_driver.h b/src/drivers/ncchunkio/ncchkio_driver.h new file mode 100644 index 000000000..cea0ed989 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkio_driver.h @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2017, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifndef _ncchkio_DRIVER_H +#define _ncchkio_DRIVER_H + +#include +#include +#include +#include + +#include "ncchkioi_profile.h" + +#define NC_CHK_VAR_RAW 0 +#define NC_CHK_VAR_COMPRESSED 1 +#define NC_CHK_VAR_DATA 2 +#define NC_CHK_VAR_META 3 + +#define NC_CHK_MAPPING_STATIC 0 +#define NC_CHK_MAPPING_DYNAMIC 01 + +#define NC_CHK_COMM_CHUNK 0 +#define NC_CHK_COMM_PROC 1 + +#define NC_CHK_ 1 + +/* Chunk cache structure */ +typedef struct NC_chk_cache { + char *buf; // Buffer + size_t bsize; // Size in byte + int serial; // batch number to detect swap out of cache allocated in the same batch + struct NC_chk_cache **ref; // Ref to clr when it is swap out + struct NC_chk_cache *prev; + struct NC_chk_cache *next; +} NC_chk_cache; + +/* Get_req structure */ +typedef struct NC_chk_req { + int varid; + int nreq; + MPI_Offset *start; + MPI_Offset **starts; + MPI_Offset *count; + MPI_Offset **counts; + MPI_Offset *stride; + MPI_Offset bufcount; + MPI_Datatype buftype; + char *buf; + char *xbuf; + char **xbufs; +} NC_chk_req; + +/* Get_req list structure */ +typedef struct NC_chk_req_list { + NC_chk_req *reqs; // Array of request object + int *ids; // Array of request ids + int *pos; // Array of position of request ids in ids + int nalloc; // Size of the pool + int nused; // Number of ids issued +} NC_chk_req_list; + +typedef struct NC_chk_var_chunk { + MPI_Offset *start; + MPI_Offset *xdata_offs; + MPI_Offset *xdata_lens; + int owner; + char *data; + char *xdata; +} NC_chk_var_chunk; + +typedef struct NC_chk_chunk_index_entry { + MPI_Offset off; + int len; +} NC_chk_chunk_index_entry; + +typedef struct NC_chk_var { + int varkind; + int isrec; + int isnew; + + nc_type xtype; + MPI_Datatype etype; + int esize; + + int ndim; + MPI_Offset *dimsize; + int *dimids; + + int varid; + + int nchunk; + int nchunkrec; + int nchunkalloc; + int nrec; + int nrecalloc; + int expanded; + int chunksize; + int *nchunks; + int *cidsteps; + int *chunk_owner; + int *chunkdim; + int *dirty; + NC_chk_cache **chunk_cache; + + int nmychunk; + int nmychunkrec; + int *mychunks; + + MPI_Offset metaoff; + NC_chk_chunk_index_entry *chunk_index; + // MPI_Offset *data_offs; + // int *data_lens; + + NCCHK_filter *filter_driver; /* Compression driver */ + int filter; + + int chunk_map_method; +} NC_chk_var; + +typedef struct NC_chk_var_list { + NC_chk_var *data; + int cnt; + int nalloc; +} NC_chk_var_list; + +typedef struct NC_chk NC_chk; /* forward reference */ +struct NC_chk { + int mode; /* file _open/_create mode */ + int flag; /* define/data/collective/indep mode */ + int rank; + int np; + char *path; /* path name */ + MPI_Comm comm; /* MPI communicator */ + void *ncp; /* pointer to driver's internal object */ + struct PNC_driver *driver; + int blockmapping; + MPI_Offset recsize; /* record dim size */ + MPI_Offset recnalloc; /* record dim allocated */ + MPI_Offset default_recnalloc; + int recdim; /* record dim id */ + NC_chk_var_list vars; + NC_chk_req_list putlist, getlist; + int comm_unit; + int delay_init; + int exact_cown; + int max_ndim; + int max_chunk_size; + MPI_Offset nmychunks; // Sum of nmychunk in everyvar + int default_filter; + int nwrite; + MPI_Offset getsize; + MPI_Offset putsize; + size_t cache_limit; + size_t cache_limit_hint; + size_t cache_used; + int cache_serial; + NC_chk_cache *cache_head; + NC_chk_cache *cache_tail; + int ndim; // Number of dim in file + int *chunkdim; // Default chunk dim for each dimension + MPI_Offset cown_size; // Size of all chunks owned + MPI_Datatype overlaptype; + MPI_Op max_cown_op; + MPI_Offset assigned_chunks; + double cown_ratio; + size_t hdr_reserve; // Additional reserve space in the file header +#ifdef PNETCDF_PROFILING + NC_chk_timers profile; + MPI_Offset sendsize; + MPI_Offset recvsize; + MPI_Offset var_size_sum; + MPI_Offset var_zsize_sum; + int nsend; + int nrecv; + int nremote; + int nreq; + int nlocal; +#endif +}; + +extern int ncchkio_create ( + MPI_Comm comm, const char *path, int cmode, int ncid, MPI_Info info, void **ncdp); + +extern int ncchkio_open ( + MPI_Comm comm, const char *path, int omode, int ncid, MPI_Info info, void **ncdp); + +extern int ncchkio_close (void *ncdp); + +extern int ncchkio_enddef (void *ncdp); + +extern int ncchkio__enddef ( + void *ncdp, MPI_Offset h_minfree, MPI_Offset v_align, MPI_Offset v_minfree, MPI_Offset r_align); + +extern int ncchkio_redef (void *ncdp); + +extern int ncchkio_sync (void *ncdp); + +extern int ncchkio_flush (void *ncdp); + +extern int ncchkio_abort (void *ncdp); + +extern int ncchkio_set_fill (void *ncdp, int fill_mode, int *old_fill_mode); + +extern int ncchkio_fill_var_rec (void *ncdp, int varid, MPI_Offset recno); + +extern int ncchkio_inq (void *ncdp, int *ndimsp, int *nvarsp, int *nattsp, int *xtendimp); + +extern int ncchkio_inq_misc (void *ncdp, + int *pathlen, + char *path, + int *num_fix_varsp, + int *num_rec_varsp, + int *striping_size, + int *striping_count, + MPI_Offset *header_size, + MPI_Offset *header_extent, + MPI_Offset *recsize, + MPI_Offset *put_size, + MPI_Offset *get_size, + MPI_Info *info_used, + int *nreqs, + MPI_Offset *usage, + MPI_Offset *buf_size); + +extern int ncchkio_sync_numrecs (void *ncdp); + +extern int ncchkio_begin_indep_data (void *ncdp); + +extern int ncchkio_end_indep_data (void *ncdp); + +extern int ncchkio_def_dim (void *ncdp, const char *name, MPI_Offset size, int *dimidp); + +extern int ncchkio_inq_dimid (void *ncdp, const char *name, int *dimidp); + +extern int ncchkio_inq_dim (void *ncdp, int dimid, char *name, MPI_Offset *lengthp); + +extern int ncchkio_rename_dim (void *ncdp, int dimid, const char *newname); + +extern int ncchkio_inq_att ( + void *ncdp, int varid, const char *name, nc_type *xtypep, MPI_Offset *lenp); + +extern int ncchkio_inq_attid (void *ncdp, int varid, const char *name, int *idp); + +extern int ncchkio_inq_attname (void *ncdp, int varid, int attnum, char *name); + +extern int ncchkio_copy_att ( + void *ncdp_in, int varid_in, const char *name, void *ncdp_out, int varid_out); + +extern int ncchkio_rename_att (void *ncdp, int varid, const char *name, const char *newname); + +extern int ncchkio_del_att (void *ncdp, int varid, const char *name); + +extern int ncchkio_get_att ( + void *ncdp, int varid, const char *name, void *value, MPI_Datatype itype); + +extern int ncchkio_put_att (void *ncdp, + int varid, + const char *name, + nc_type xtype, + MPI_Offset nelems, + const void *value, + MPI_Datatype itype); + +extern int ncchkio_def_var ( + void *ncdp, const char *name, nc_type type, int ndims, const int *dimids, int *varidp); + +extern int ncchkio_def_var_fill (void *ncdp, int varid, int nofill, const void *fill_value); + +extern int ncchkio_inq_var (void *ncdp, + int varid, + char *name, + nc_type *xtypep, + int *ndimsp, + int *dimids, + int *nattsp, + MPI_Offset *offsetp, + int *no_fill, + void *fill_value); + +extern int ncchkio_inq_varid (void *ncdp, const char *name, int *varid); + +extern int ncchkio_rename_var (void *ncdp, int varid, const char *newname); + +extern int ncchkio_get_var (void *ncdp, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode); + +extern int ncchkio_put_var (void *ncdp, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode); + +extern int ncchkio_get_varn (void *ncdp, + int varid, + int num, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode); + +extern int ncchkio_put_varn (void *ncdp, + int varid, + int num, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode); + +extern int ncchkio_get_vard (void *ncdp, + int varid, + MPI_Datatype filetype, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode); + +extern int ncchkio_put_vard (void *ncdp, + int varid, + MPI_Datatype filetype, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode); + +extern int ncchkio_iget_var (void *ncdp, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *req, + int reqMode); + +extern int ncchkio_iput_var (void *ncdp, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *req, + int reqMode); + +extern int ncchkio_bput_var (void *ncdp, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *req, + int reqMode); + +extern int ncchkio_iget_varn (void *ncdp, + int varid, + int num, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *reqid, + int reqMode); + +extern int ncchkio_iput_varn (void *ncdp, + int varid, + int num, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *reqid, + int reqMode); + +extern int ncchkio_bput_varn (void *ncdp, + int varid, + int num, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *reqid, + int reqMode); + +extern int ncchkio_buffer_attach (void *ncdp, MPI_Offset bufsize); + +extern int ncchkio_buffer_detach (void *ncdp); + +extern int ncchkio_wait (void *ncdp, int num_reqs, int *req_ids, int *statuses, int reqMode); + +extern int ncchkio_cancel (void *ncdp, int num_reqs, int *req_ids, int *statuses); + +#endif diff --git a/src/drivers/ncchunkio/ncchkio_file.c b/src/drivers/ncchunkio/ncchkio_file.c new file mode 100644 index 000000000..956fb9246 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkio_file.c @@ -0,0 +1,828 @@ +/* + * Copyright (C) 2017, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs + * + * ncmpi_create() : dispatcher->create() + * ncmpi_open() : dispatcher->open() + * ncmpi_close() : dispatcher->close() + * ncmpi_enddef() : dispatcher->enddef() + * ncmpi__enddef() : dispatcher->_enddef() + * ncmpi_redef() : dispatcher->redef() + * ncmpi_begin_indep_data() : dispatcher->begin_indep_data() + * ncmpi_end_indep_data() : dispatcher->end_indep_data() + * ncmpi_abort() : dispatcher->abort() + * ncmpi_inq() : dispatcher->inq() + * ncmpi_inq_misc() : dispatcher->inq_misc() + * ncmpi_wait() : dispatcher->wait() + * ncmpi_wait_all() : dispatcher->wait() + * ncmpi_cancel() : dispatcher->cancel() + * + * ncmpi_set_fill() : dispatcher->set_fill() + * ncmpi_fill_var_rec() : dispatcher->fill_rec() + * ncmpi_def_var_fill() : dispatcher->def_var_fill() + * ncmpi_inq_var_fill() : dispatcher->inq() + * + * ncmpi_sync() : dispatcher->sync() + * ncmpi_flush() : dispatcher->flush() + * ncmpi_sync_numrecs() : dispatcher->sync_numrecs() + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include /* strlen() */ + +#include "../ncmpio/ncmpio_NC.h" +#include "ncchkio_internal.h" + +int ncchkio_create ( + MPI_Comm comm, const char *path, int cmode, int ncid, MPI_Info info, void **ncpp) /* OUT */ +{ + int err; + int one = 1; + void *ncp = NULL; + NC_chk *ncchkp; + PNC_driver *driver = NULL; +#ifdef PNETCDF_PROFILING + double t0, t1; + + t0 = MPI_Wtime (); +#endif + + /* TODO: use comde to determine the true driver */ + driver = ncmpio_inq_driver (); + if (driver == NULL) return NC_ENOTNC; + + err = driver->create (comm, path, cmode | NC_64BIT_DATA, ncid, info, &ncp); + if (err != NC_NOERR) return err; + + /* Create a NC_chk object and save its driver pointer */ + ncchkp = (NC_chk *)NCI_Malloc (sizeof (NC_chk)); + if (ncchkp == NULL) DEBUG_RETURN_ERROR (NC_ENOMEM) + + ncchkp->path = (char *)NCI_Malloc (strlen (path) + 1); + if (ncchkp->path == NULL) { + NCI_Free (ncchkp); + DEBUG_RETURN_ERROR (NC_ENOMEM) + } + strcpy (ncchkp->path, path); + ncchkp->mode = cmode | NC_WRITE; + ncchkp->driver = driver; + ncchkp->flag = 0; + ncchkp->ncp = ncp; + ncchkp->comm = comm; + MPI_Comm_rank (comm, &(ncchkp->rank)); + MPI_Comm_size (comm, &(ncchkp->np)); + + ncchkioi_init (ncchkp, 1); + + err = ncchkioi_extract_hint (ncchkp, info); + if (err != NC_NOERR) return err; + + err = driver->put_att (ncchkp->ncp, NC_GLOBAL, "_comressed", NC_INT, 1, &one, + MPI_INT); // Mark this file as compressed + if (err != NC_NOERR) return err; + + *ncpp = ncchkp; + + // Timer array is not avaiable until init, can't use NC_CHK_TIMER_START +#ifdef PNETCDF_PROFILING + t0 = MPI_Wtime () - t0; + ncchkp->profile.tt[NC_CHK_TIMER_VAR_INIT] += t0; + ncchkp->profile.tt[NC_CHK_TIMER_TOTAL] += t0; +#endif + + return NC_NOERR; +} + +int ncchkio_open ( + MPI_Comm comm, const char *path, int omode, int ncid, MPI_Info info, void **ncpp) { + int err; + int one = 0; + void *ncp = NULL; + NC_chk *ncchkp = NULL; + PNC_driver *driver = NULL; +#ifdef PNETCDF_PROFILING + double t0; + + t0 = MPI_Wtime (); +#endif + + /* TODO: use comde to determine the true driver */ + driver = ncmpio_inq_driver (); + if (driver == NULL) { + DEBUG_ASSIGN_ERROR (err, NC_ENOTNC) + goto errout; + } + + err = driver->open (comm, path, omode, ncid, info, &ncp); + if (err != NC_NOERR) goto errout; + + /* Create a NC_chk object and save its driver pointer */ + ncchkp = (NC_chk *)NCI_Malloc (sizeof (NC_chk)); + if (ncchkp == NULL) { + DEBUG_ASSIGN_ERROR (err, NC_ENOMEM) + goto errout; + } + + ncchkp->path = (char *)NCI_Malloc (strlen (path) + 1); + if (ncchkp->path == NULL) { + NCI_Free (ncchkp); + DEBUG_ASSIGN_ERROR (err, NC_ENOMEM) + goto errout; + } + strcpy (ncchkp->path, path); + ncchkp->mode = omode; + ncchkp->driver = driver; + if (ncchkp->mode & NC_WRITE) { + ncchkp->flag = 0; + } else { + ncchkp->flag |= NC_MODE_RDONLY; + } + ncchkp->ncp = ncp; + ncchkp->comm = comm; + MPI_Comm_rank (comm, &(ncchkp->rank)); + MPI_Comm_size (comm, &(ncchkp->np)); + + ncchkioi_init (ncchkp, 0); + + err = ncchkioi_extract_hint (ncchkp, info); + if (err != NC_NOERR) goto errout; + + err = driver->get_att (ncchkp->ncp, NC_GLOBAL, "_comressed", &one, + MPI_INT); // Mark this file as compressed + if (err != NC_NOERR) { + if (err == NC_ENOTATT) { err = NC_EINVAL; } + goto errout; + } + + // Not compressed file + if (one != 1) { + NCI_Free (ncchkp->path); + NCI_Free (ncchkp); + DEBUG_RETURN_ERROR (NC_EINVAL) + } + + err = ncchkioi_get_default_chunk_dim (ncchkp); + if (err != NC_NOERR) return err; + + ncchkioi_parse_var_info (ncchkp); + + *ncpp = ncchkp; + + // Timer array is not avaiable until init, can't use NC_CHK_TIMER_START +#ifdef PNETCDF_PROFILING + t0 = MPI_Wtime () - t0; + ncchkp->profile.tt[NC_CHK_TIMER_VAR_INIT] += t0; + ncchkp->profile.tt[NC_CHK_TIMER_TOTAL] += t0; +#endif + + return NC_NOERR; + +errout: + if (ncp != NULL) { driver->close (ncchkp->ncp); } + if (ncchkp != NULL) { + if (ncchkp->path != NULL) { NCI_Free (ncchkp->path); } + NCI_Free (ncchkp); + } + + return err; +} + +int ncchkio_close (void *ncdp) { + int err = NC_NOERR; +#ifdef PNETCDF_PROFILING + MPI_Offset put_size, get_size; + char *_env_str = getenv ("PNETCDF_SHOW_PERFORMANCE_INFO"); +#endif + NC_chk *ncchkp = (NC_chk *)ncdp; + +#ifdef PNETCDF_PROFILING + if (_env_str != NULL && *_env_str != '0') { ncchkioi_update_statistics (ncchkp); } +#endif + + NC_CHK_TIMER_START (NC_CHK_TIMER_FINALIZE) + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + + if (ncchkp == NULL) DEBUG_RETURN_ERROR (NC_EBADID) + + if (!(ncchkp->flag & NC_MODE_RDONLY)) { + int i; + + NC_CHK_TIMER_START (NC_CHK_TIMER_FINALIZE_META) + + err = ncchkp->driver->redef (ncchkp->ncp); + if (err != NC_NOERR) { return err; } + + // record chunk dim + for (i = 0; i < ncchkp->vars.cnt; i++) { + if (ncchkp->vars.data[i].isnew) { + err = ncchkp->driver->put_att (ncchkp->ncp, ncchkp->vars.data[i].varid, "_chunkdim", + NC_INT, ncchkp->vars.data[i].ndim, + ncchkp->vars.data[i].chunkdim, MPI_INT); + if (err != NC_NOERR) { return err; } + err = + ncchkp->driver->put_att (ncchkp->ncp, ncchkp->vars.data[i].varid, "_filter", + NC_INT, 1, &(ncchkp->vars.data[i].filter), MPI_INT); + if (err != NC_NOERR) { return err; } + } + } + + // Record recsize + err = ncchkp->driver->put_att (ncchkp->ncp, NC_GLOBAL, "_recsize", NC_INT64, 1, + &(ncchkp->recsize), + MPI_LONG_LONG); // Mark this file as compressed + if (err != NC_NOERR) return err; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_FINALIZE_META) + } + +#ifdef PNETCDF_PROFILING + err = ncchkp->driver->inq_misc (ncchkp->ncp, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, &put_size, &get_size, NULL, NULL, NULL, NULL); + CHK_ERR + ncchkp->putsize += put_size; + ncchkp->getsize += get_size; +#endif + err = ncchkp->driver->close (ncchkp->ncp); + CHK_ERR + + ncchkioi_cache_free (ncchkp); + + err = ncchkioi_var_list_free (&(ncchkp->vars)); + CHK_ERR + + err = ncchkioi_req_list_free (&(ncchkp->putlist)); + CHK_ERR + err = ncchkioi_req_list_free (&(ncchkp->getlist)); + CHK_ERR + + NCI_Free (ncchkp->chunkdim); + + if (ncchkp->overlaptype != MPI_DATATYPE_NULL) { MPI_Type_free (&(ncchkp->overlaptype)); } + if (ncchkp->max_cown_op != MPI_OP_NULL) { MPI_Op_free (&(ncchkp->max_cown_op)); } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_FINALIZE) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + +#ifdef PNETCDF_PROFILING + if (_env_str != NULL && *_env_str != '0') { + ncchkioi_profile_add_time (ncchkp, NC_CHK_TIMER_PUT_SIZE, + (double)ncchkp->putsize / 1048576.0f); + ncchkioi_profile_add_time (ncchkp, NC_CHK_TIMER_GET_SIZE, + (double)ncchkp->getsize / 1048576.0f); + ncchkioi_profile_add_time (ncchkp, NC_CHK_TIMER_SEND_SIZE, + (double)ncchkp->sendsize / 1048576.0f); + ncchkioi_profile_add_time (ncchkp, NC_CHK_TIMER_RECV_SIZE, + (double)ncchkp->recvsize / 1048576.0f); + ncchkioi_profile_add_time (ncchkp, NC_CHK_TIMER_NSEND, (double)ncchkp->nsend); + ncchkioi_profile_add_time (ncchkp, NC_CHK_TIMER_NRECV, (double)ncchkp->nrecv); + ncchkioi_profile_add_time (ncchkp, NC_CHK_TIMER_NREMOTE, (double)ncchkp->nremote); + ncchkioi_profile_add_time (ncchkp, NC_CHK_TIMER_NREQ, (double)ncchkp->nreq); + ncchkioi_profile_add_time (ncchkp, NC_CHK_TIMER_NLOCAL, (double)ncchkp->nlocal); + ncchkioi_profile_add_time (ncchkp, NC_CHK_TIMER_NCHUNK, (double)ncchkp->nmychunks); + ncchkioi_profile_add_time (ncchkp, NC_CHK_TIMER_VAR_SIZE, + (double)ncchkp->var_size_sum / 1048576.0f); + ncchkioi_profile_add_time (ncchkp, NC_CHK_TIMER_VAR_ZSIZE, + (double)ncchkp->var_zsize_sum / 1048576.0f); + + ncchkioi_print_profile (ncchkp); + } +#endif + +err_out:; + + NCI_Free (ncchkp->path); + + NCI_Free (ncchkp); + + return err; +} + +int ncchkio_enddef (void *ncdp) { + int err = NC_NOERR, ret; + int i; + MPI_Offset logrecnalloc, drecnalloc; + MPI_Offset rsize; + NC_chk_var *varp; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT) + + drecnalloc = 1; + logrecnalloc = 0; + while (drecnalloc < ncchkp->default_recnalloc) { + logrecnalloc++; + drecnalloc <<= 1; + } + + // Reserve header space + rsize = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + varp = ncchkp->vars.data + i; + rsize = 0; + if (varp->varkind == NC_CHK_VAR_COMPRESSED) { + if (varp->isrec) { + rsize += + ((8 + 16) + 4 + 8 + 4) * 8 + ((8 + 16) + 4 + 8 + 4 * varp->ndim) * 2; // Atts + rsize += ((8 + 32) + 8) * (ncchkp->default_recnalloc + logrecnalloc + 1); // dims + rsize += ((8 + 32) + 8 + 8 + (8 + 8 + (8 + 12 + 4 + 8 + 4)) + 4 + 8 + 8) * + (ncchkp->default_recnalloc + 2 * logrecnalloc); // vars + } else { + rsize += + ((8 + 16) + 4 + 8 + 4) * 8 + ((8 + 16) + 4 + 8 + 4 * varp->ndim) * 2; // Atts + rsize += ((8 + 32) + 8) * 3; // dims + rsize += + ((8 + 32) + 8 + 8 + (8 + 8 + (8 + 12 + 4 + 8 + 4)) + 4 + 8 + 8) * 3; // vars + } + } else { + rsize += ((8 + 16) + 4 + 8 + 4); // Atts + } + } + //rsize *= 2; // 2 times for future expension + // Add additional reserve size + rsize += ncchkp->hdr_reserve; + + err = ncchkp->driver->_enddef (ncchkp->ncp, rsize, 0, 0, 0); + if (err != NC_NOERR) return err; + + err = ncchkioi_get_default_chunk_dim (ncchkp); + if (err != NC_NOERR) return err; + + if (!(ncchkp->delay_init)) { + int nread; + int *lens; + MPI_Aint *fdisps, *mdisps; + MPI_Datatype ftype, mtype; + MPI_Status status; + NC_chk_var *varp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_META) + + lens = NCI_Malloc (sizeof (int) * ncchkp->vars.cnt); + fdisps = NCI_Malloc (sizeof (MPI_Aint) * ncchkp->vars.cnt * 2); + mdisps = fdisps + ncchkp->vars.cnt; + + nread = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + varp = ncchkp->vars.data + i; + + ncchkioi_var_init (ncchkp, varp, 0, NULL, NULL); + + if (!(varp->isnew)) { + ret = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_metaoffset", + &(varp->metaoff), MPI_LONG_LONG); + if (ret == NC_NOERR) { + lens[nread] = sizeof (NC_chk_chunk_index_entry) * (varp->nchunk); + fdisps[nread] = varp->metaoff; + mdisps[nread++] = (MPI_Aint) (varp->chunk_index); + } else { + varp->metaoff = -1; + memset (varp->chunk_index, 0, + sizeof (NC_chk_chunk_index_entry) * (varp->nchunk + 1)); + } + } + } + + if (nread) { + ncchkioi_sort_file_offset (nread, fdisps, mdisps, lens); + + MPI_Type_create_hindexed (nread, lens, fdisps, MPI_BYTE, &ftype); + CHK_ERR_TYPE_COMMIT (&ftype); + + MPI_Type_create_hindexed (nread, lens, mdisps, MPI_BYTE, &mtype); + CHK_ERR_TYPE_COMMIT (&mtype); + + // Set file view + CHK_ERR_SET_VIEW (((NC *)(ncchkp->ncp))->collective_fh, + ((NC *)(ncchkp->ncp))->begin_var, MPI_BYTE, ftype, "native", + MPI_INFO_NULL); + + // Read data + CHK_ERR_READ_AT_ALL (((NC *)(ncchkp->ncp))->collective_fh, 0, MPI_BOTTOM, 1, mtype, + &status); + + // Restore file view + CHK_ERR_SET_VIEW (((NC *)(ncchkp->ncp))->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", + MPI_INFO_NULL); + +#ifdef WORDS_BIGENDIAN // Switch back to big endian + ncchkioi_idx_in_swapn (varp->chunk_index, varp->nchunk + 1); +#endif + MPI_Type_free (&ftype); + MPI_Type_free (&mtype); + } + + NCI_Free (lens); + NCI_Free (fdisps); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_META) + } + +err_out:; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + + return err; +} + +int ncchkio__enddef (void *ncdp, + MPI_Offset h_minfree, + MPI_Offset v_align, + MPI_Offset v_minfree, + MPI_Offset r_align) { + int err = NC_NOERR, ret; + int i; + MPI_Offset logrecnalloc, drecnalloc; + MPI_Offset rsize; + NC_chk_var *varp; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT) + + drecnalloc = 1; + logrecnalloc = 0; + while (drecnalloc < ncchkp->default_recnalloc) { + logrecnalloc++; + drecnalloc <<= 1; + } + + // Reserve header space + rsize = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + varp = ncchkp->vars.data + i; + rsize = 0; + if (varp->varkind == NC_CHK_VAR_COMPRESSED) { + if (varp->isrec) { + rsize += + ((8 + 16) + 4 + 8 + 4) * 8 + ((8 + 16) + 4 + 8 + 4 * varp->ndim) * 2; // Atts + rsize += ((8 + 32) + 8) * (ncchkp->default_recnalloc + logrecnalloc + 1); // dims + rsize += ((8 + 32) + 8 + 8 + (8 + 8 + (8 + 12 + 4 + 8 + 4)) + 4 + 8 + 8) * + (ncchkp->default_recnalloc + 2 * logrecnalloc); // vars + } else { + rsize += + ((8 + 16) + 4 + 8 + 4) * 8 + ((8 + 16) + 4 + 8 + 4 * varp->ndim) * 2; // Atts + rsize += ((8 + 32) + 8) * 3; // dims + rsize += + ((8 + 32) + 8 + 8 + (8 + 8 + (8 + 12 + 4 + 8 + 4)) + 4 + 8 + 8) * 3; // vars + } + } else { + rsize += ((8 + 16) + 4 + 8 + 4); // Atts + } + } + rsize *= 2; // 2 times for future expension + + err = ncchkp->driver->_enddef (ncchkp->ncp, h_minfree + rsize, v_align, v_minfree, r_align); + if (err != NC_NOERR) return err; + + err = ncchkioi_get_default_chunk_dim (ncchkp); + if (err != NC_NOERR) return err; + + if (!(ncchkp->delay_init)) { + int nread; + int *lens; + MPI_Aint *fdisps, *mdisps; + MPI_Datatype ftype, mtype; + MPI_Status status; + NC_chk_var *varp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_META) + + lens = NCI_Malloc (sizeof (int) * ncchkp->vars.cnt); + fdisps = NCI_Malloc (sizeof (MPI_Aint) * ncchkp->vars.cnt * 2); + mdisps = fdisps + ncchkp->vars.cnt; + + nread = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + varp = ncchkp->vars.data + i; + + err = ncchkioi_var_init (ncchkp, varp, 0, NULL, NULL); + CHK_ERR + + if (!(varp->isnew)) { + ret = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_metaoffset", + &(varp->metaoff), MPI_LONG_LONG); + if (ret == NC_NOERR) { + lens[nread] = sizeof (NC_chk_chunk_index_entry) * (varp->nchunk); + fdisps[nread] = varp->metaoff; + mdisps[nread++] = (MPI_Aint) (varp->chunk_index); + } else { + varp->metaoff = -1; + memset (varp->chunk_index, 0, + sizeof (NC_chk_chunk_index_entry) * (varp->nchunk + 1)); + } + } + } + + if (nread) { + ncchkioi_sort_file_offset (nread, fdisps, mdisps, lens); + + MPI_Type_create_hindexed (nread, lens, fdisps, MPI_BYTE, &ftype); + CHK_ERR_TYPE_COMMIT (&ftype); + + MPI_Type_create_hindexed (nread, lens, mdisps, MPI_BYTE, &mtype); + CHK_ERR_TYPE_COMMIT (&mtype); + + // Set file view + CHK_ERR_SET_VIEW (((NC *)(ncchkp->ncp))->collective_fh, + ((NC *)(ncchkp->ncp))->begin_var, MPI_BYTE, ftype, "native", + MPI_INFO_NULL); + + // Read data + CHK_ERR_READ_AT_ALL (((NC *)(ncchkp->ncp))->collective_fh, 0, MPI_BOTTOM, 1, mtype, + &status); + + // Restore file view + CHK_ERR_SET_VIEW (((NC *)(ncchkp->ncp))->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", + MPI_INFO_NULL); + +#ifdef WORDS_BIGENDIAN // Switch back to big endian + ncchkioi_idx_in_swapn (varp->chunk_index, varp->nchunk + 1); +#endif + + MPI_Type_free (&ftype); + MPI_Type_free (&mtype); + } + + NCI_Free (lens); + NCI_Free (fdisps); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_META) + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + +err_out:; + return err; +} + +int ncchkio_redef (void *ncdp) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->redef (ncchkp->ncp); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_begin_indep_data (void *ncdp) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->begin_indep_data (ncchkp->ncp); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_end_indep_data (void *ncdp) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->end_indep_data (ncchkp->ncp); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_abort (void *ncdp) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + if (ncchkp == NULL) DEBUG_RETURN_ERROR (NC_EBADID) + + err = ncchkp->driver->abort (ncchkp->ncp); + + NCI_Free (ncchkp->path); + NCI_Free (ncchkp); + + return err; +} + +int ncchkio_inq (void *ncdp, int *ndimsp, int *nvarsp, int *nattsp, int *xtendimp) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->inq (ncchkp->ncp, ndimsp, NULL, nattsp, xtendimp); + if (err != NC_NOERR) return err; + + if (nvarsp != NULL) { *nvarsp = ncchkp->vars.cnt; } + + return NC_NOERR; +} + +int ncchkio_inq_misc (void *ncdp, + int *pathlen, + char *path, + int *num_fix_varsp, + int *num_rec_varsp, + int *striping_size, + int *striping_count, + MPI_Offset *header_size, + MPI_Offset *header_extent, + MPI_Offset *recsize, + MPI_Offset *put_size, + MPI_Offset *get_size, + MPI_Info *info_used, + int *nreqs, + MPI_Offset *usage, + MPI_Offset *buf_size) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->inq_misc (ncchkp->ncp, pathlen, path, num_fix_varsp, num_rec_varsp, + striping_size, striping_count, header_size, header_extent, + recsize, put_size, get_size, info_used, nreqs, usage, buf_size); + if (err != NC_NOERR) return err; + + if (num_fix_varsp != NULL) { *num_fix_varsp = ncchkp->vars.cnt; } + + if (nreqs != NULL) { *nreqs = ncchkp->putlist.nused + ncchkp->getlist.nused; } + + if (put_size != NULL) { *put_size += ncchkp->putsize; } + + if (get_size != NULL) { *get_size += ncchkp->getsize; } + + return NC_NOERR; +} + +int ncchkio_cancel (void *ncdp, int num_req, int *req_ids, int *statuses) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->cancel (ncchkp->ncp, num_req, req_ids, statuses); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_wait (void *ncdp, int num_reqs, int *req_ids, int *statuses, int reqMode) { + int err = NC_NOERR, status = NC_NOERR; + int i; + int ncom = 0, nraw = 0; + int *rawreqs = NULL, *comreqs = NULL; + int *rawstats = NULL, *comstats = NULL; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_START (NC_CHK_TIMER_WAIT) + + if (num_reqs < 0) { // NC_REQ_ALL || nreqs == NC_PUT_REQ_ALL || nreqs == NC_GET_REQ_ALL + err = ncchkioi_wait (ncchkp, num_reqs, NULL, NULL, reqMode); + if (status == NC_NOERR) { status = err; } + err = ncchkp->driver->wait (ncchkp->ncp, num_reqs, NULL, NULL, reqMode); + if (status == NC_NOERR) { status = err; } + goto done; + } + + if (num_reqs > 0) { + // Count number of get and put requests + for (i = 0; i < num_reqs; i++) { + if (req_ids[i] & 1) { nraw++; } + } + + // Allocate buffer + ncom = num_reqs - nraw; + rawreqs = (int *)NCI_Malloc (sizeof (int) * nraw); + CHK_PTR (rawreqs) + comreqs = (int *)NCI_Malloc (sizeof (int) * ncom); + CHK_PTR (comreqs) + + // Build put and get req list + nraw = ncom = 0; + for (i = 0; i < num_reqs; i++) { + if (req_ids[i] & 1) { + rawreqs[nraw++] = req_ids[i] >> 1; + } else { + comreqs[ncom++] = req_ids[i] >> 1; + } + } + } + + if (statuses != NULL) { + rawstats = (int *)NCI_Malloc (sizeof (int) * nraw); + CHK_PTR (rawstats) + comstats = (int *)NCI_Malloc (sizeof (int) * ncom); + CHK_PTR (comstats) + } else { + rawstats = NULL; + comstats = NULL; + } + + if (nraw > 0) { + err = ncchkp->driver->wait (ncchkp->ncp, nraw, rawreqs, rawstats, reqMode); + if (status == NC_NOERR) { status = err; } + } + + if (ncom > 0) { + err = ncchkioi_wait (ncchkp, ncom, comreqs, comstats, reqMode); + if (status == NC_NOERR) { status = err; } + } + + // Assign stats + if (statuses != NULL) { + nraw = ncom = 0; + for (i = 0; i < num_reqs; i++) { + if (req_ids[i] & 1) { + statuses[i] = rawstats[nraw++]; + } else { + statuses[i] = comstats[ncom++]; + } + } + + NCI_Free (rawstats); + NCI_Free (comstats); + } + + NCI_Free (rawreqs); + NCI_Free (comreqs); + +err_out:; + if (status == NC_NOERR) status = err; +done:; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_WAIT) + + return status; +} + +int ncchkio_set_fill (void *ncdp, int fill_mode, int *old_fill_mode) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->set_fill (ncchkp->ncp, fill_mode, old_fill_mode); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_fill_var_rec (void *ncdp, int varid, MPI_Offset recno) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->fill_var_rec (ncchkp->ncp, varid, recno); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_def_var_fill (void *ncdp, int varid, int no_fill, const void *fill_value) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->def_var_fill (ncchkp->ncp, varid, no_fill, fill_value); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_sync_numrecs (void *ncdp) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->sync_numrecs (ncchkp->ncp); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_sync (void *ncdp) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->sync (ncchkp->ncp); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_flush (void *ncdp) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->flush (ncchkp->ncp); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} diff --git a/src/drivers/ncchunkio/ncchkio_internal.c b/src/drivers/ncchunkio/ncchkio_internal.c new file mode 100644 index 000000000..14be14707 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkio_internal.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2018, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "../ncmpio/ncmpio_NC.h" +#include "ncchkio_internal.h" + +int ncchkioi_init (NC_chk *ncchkp, int isnew) { + int err; + + ncchkp->max_ndim = 0; + ncchkp->max_chunk_size = 0; + ncchkp->getsize = 0; + ncchkp->putsize = 0; + ncchkp->nmychunks = 0; + ncchkp->nwrite = 0; + ncchkp->cache_head = NULL; + ncchkp->cache_tail = NULL; + ncchkp->cache_used = 0; + ncchkp->cache_limit = 0; + ncchkp->cache_serial = 0; + ncchkp->ndim = 0; + ncchkp->chunkdim = NULL; + ncchkp->assigned_chunks = 0; + ncchkp->cown_size = 0; + ncchkp->max_cown_op = MPI_OP_NULL; + ncchkp->overlaptype = MPI_DATATYPE_NULL; + + err = ncchkp->driver->inq (ncchkp->ncp, NULL, NULL, NULL, &(ncchkp->recdim)); + if (err != NC_NOERR) return err; + + if (isnew) { + ncchkp->recsize = 0; + } else { + err = ncchkp->driver->get_att (ncchkp->ncp, NC_GLOBAL, "_recsize", &(ncchkp->recsize), + MPI_LONG_LONG); + CHK_ERR // Mark this file as compressed + } + + /* Initialize var list */ + err = ncchkioi_var_list_init (&(ncchkp->vars)); + if (err != NC_NOERR) return err; + + /* Initialize nonblocking list */ + err = ncchkioi_req_list_init (&(ncchkp->getlist)); + if (err != NC_NOERR) return err; + err = ncchkioi_req_list_init (&(ncchkp->putlist)); + if (err != NC_NOERR) return err; + +#ifdef PNETCDF_PROFILING + memset (&(ncchkp->profile), 0, sizeof (NC_chk_timers)); + ncchkp->sendsize = 0; + ncchkp->recvsize = 0; + ncchkp->nsend = 0; + ncchkp->nrecv = 0; + ncchkp->nremote = 0; + ncchkp->nreq = 0; + ncchkp->nlocal = 0; +#endif + +err_out:; + return err; +} + +int ncchkioi_parse_var_info (NC_chk *ncchkp) { + int err = NC_NOERR, ret; + int vid; + int i; + int nvar; + int varkind; + NC_chk_var *varp; + + int nread; + int *lens; + MPI_Aint *fdisps, *mdisps; + MPI_Datatype ftype, mtype; + MPI_Status status; + + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_META) + + err = ncchkp->driver->inq (ncchkp->ncp, NULL, &nvar, NULL, &(ncchkp->recdim)); + CHK_ERR + + if (nvar > 0) { + for (vid = 0; vid < nvar; vid++) { + err = ncchkp->driver->get_att (ncchkp->ncp, vid, "_varkind", &varkind, + MPI_INT); // Comressed var? + if (err != NC_NOERR) { continue; } + + if (varkind == NC_CHK_VAR_COMPRESSED || varkind == NC_CHK_VAR_RAW) { + err = ncchkioi_var_list_add (&(ncchkp->vars)); + if (err < 0) return err; + varp = ncchkp->vars.data + err; + + memset (varp, 0, sizeof (NC_chk_var)); + + varp->varid = vid; + varp->varkind = varkind; + + if (varp->varkind == NC_CHK_VAR_COMPRESSED) { + err = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_ndim", &(varp->ndim), + MPI_INT); // Original dimensions + if (err != NC_NOERR) return err; + + varp->dimids = (int *)NCI_Malloc (sizeof (int) * varp->ndim); + CHK_PTR (varp->dimids) + varp->dimsize = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim); + CHK_PTR (varp->dimsize) + + err = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_dimids", + varp->dimids, MPI_INT); // Dimensiona IDs + if (err != NC_NOERR) return err; + + for (i = 0; i < varp->ndim; i++) { + ncchkp->driver->inq_dim (ncchkp->ncp, varp->dimids[i], NULL, + varp->dimsize + i); + } + if (varp->dimids[0] == ncchkp->recdim) { + varp->isrec = 1; + if (varp->dimsize[0] < ncchkp->recsize) { + varp->dimsize[0] = ncchkp->recsize; + } + } else { + varp->isrec = 0; + } + + err = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_datatype", + &(varp->xtype), MPI_INT); // Original datatype + if (err != NC_NOERR) return err; + + varp->esize = NC_Type_size (varp->xtype); + varp->etype = ncmpii_nc2mpitype (varp->xtype); + varp->chunkdim = NULL; + } + } + } + + // Collective read index table + if (!(ncchkp->delay_init)) { + lens = NCI_Malloc (sizeof (int) * nvar); + CHK_PTR (lens) + fdisps = NCI_Malloc (sizeof (MPI_Aint) * nvar * 2); + CHK_PTR (fdisps) + mdisps = fdisps + nvar; + + nread = 0; + for (vid = 0; vid < ncchkp->vars.cnt; vid++) { + varp = ncchkp->vars.data + vid; + + if (varp->varkind == NC_CHK_VAR_COMPRESSED) { + // Init var + err = ncchkioi_var_init (ncchkp, varp, 0, NULL, NULL); + CHK_ERR + + ret = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_metaoffset", + &(varp->metaoff), MPI_LONG_LONG); + if (ret == NC_NOERR) { + lens[nread] = sizeof (NC_chk_chunk_index_entry) * (varp->nchunk); + fdisps[nread] = varp->metaoff; + mdisps[nread++] = (MPI_Aint) (varp->chunk_index); + } else { + varp->metaoff = -1; + memset (varp->chunk_index, 0, + sizeof (NC_chk_chunk_index_entry) * (varp->nchunk + 1)); + } + } + } + + if (nread) { + ncchkioi_sort_file_offset (nread, fdisps, mdisps, lens); + + MPI_Type_create_hindexed (nread, lens, fdisps, MPI_BYTE, &ftype); + CHK_ERR_TYPE_COMMIT (&ftype); + + MPI_Type_create_hindexed (nread, lens, mdisps, MPI_BYTE, &mtype); + CHK_ERR_TYPE_COMMIT (&mtype); + + // Set file view + CHK_ERR_SET_VIEW (((NC *)(ncchkp->ncp))->collective_fh, + ((NC *)(ncchkp->ncp))->begin_var, MPI_BYTE, ftype, "native", + MPI_INFO_NULL); + + // Read data + CHK_ERR_READ_AT_ALL (((NC *)(ncchkp->ncp))->collective_fh, 0, MPI_BOTTOM, 1, mtype, + &status); + + // Restore file view + CHK_ERR_SET_VIEW (((NC *)(ncchkp->ncp))->collective_fh, 0, MPI_BYTE, MPI_BYTE, + "native", MPI_INFO_NULL); + +#ifdef WORDS_BIGENDIAN // Switch back to little endian + ncchkioi_idx_in_swapn (varp - chunk_index, varp->nchunk + 1); +#endif + + MPI_Type_free (&ftype); + MPI_Type_free (&mtype); + } + + for (vid = 0; vid < ncchkp->vars.cnt; vid++) { + varp = ncchkp->vars.data + vid; + } + + NCI_Free (lens); + NCI_Free (fdisps); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_META) + +err_out:; + return err; +} \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkio_internal.h b/src/drivers/ncchunkio/ncchkio_internal.h new file mode 100644 index 000000000..aec7c51f7 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkio_internal.h @@ -0,0 +1,390 @@ +#ifndef _ncchkio_INTERNAL_H +#define _ncchkio_INTERNAL_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ncchkio_driver.h" +#ifdef PNETCDF_DEBUG +#include +#endif + +#define NC_CHK_FILTER_NONE 0 +#define NC_CHK_FILTER_DUMMY 1 +#define NC_CHK_FILTER_ZLIB 2 +#define NC_CHK_FILTER_SZ 3 + +#define NC_CHK_DEFAULT_REC_ALLOC 1024 +#define NC_CHK_REC_MULTIPLIER 2 + +#ifdef PNETCDF_DEBUG +#define DEBUG_ABORT \ + { \ + char *_env_str = getenv ("PNETCDF_ABORT_ON_ERR"); \ + if (_env_str != NULL && *_env_str != '0') { abort (); } \ + } +#else +#define DEBUG_ABORT +#endif + +#define RET_ERR(E) \ + { \ + err = E; \ + DEBUG_TRACE_ERROR (err); \ + DEBUG_ABORT \ + goto err_out; \ + } +#define CHK_ERR \ + if (err != NC_NOERR) { \ + DEBUG_ABORT \ + goto err_out; \ + } + +#define CHK_MPIERR \ + if (err != MPI_SUCCESS) { \ + err = ncmpii_error_mpi2nc (err, "MPI"); \ + DEBUG_TRACE_ERROR (err); \ + DEBUG_ABORT \ + goto err_out; \ + } + +#define CHK_PTR(P) \ + if (!P) { \ + err = NC_ENOMEM; \ + DEBUG_TRACE_ERROR (err); \ + DEBUG_ABORT \ + goto err_out; \ + } + +#define CHK_ERR_WAIT(V0, V1) \ + err = MPI_Wait (V0, V1); \ + CHK_MPIERR + +#define CHK_ERR_ALLREDUCE(V0, V1, V2, V3, V4, V5) \ + err = MPI_Allreduce (V0, V1, V2, V3, V4, V5); \ + CHK_MPIERR + +#define CHK_ERR_IALLREDUCE(V0, V1, V2, V3, V4, V5, V6) \ + err = MPI_Iallreduce (V0, V1, V2, V3, V4, V5, V6); \ + CHK_MPIERR + +#define CHK_ERR_REDUCE(V0, V1, V2, V3, V4, V5, V6) \ + err = MPI_Reduce (V0, V1, V2, V3, V4, V5, V6); \ + CHK_MPIERR + +#define CHK_ERR_GATHER(V0, V1, V2, V3, V4, V5, V6, V7) \ + err = MPI_Gather (V0, V1, V2, V3, V4, V5, V6, V7); \ + CHK_MPIERR + +#ifdef PNETCDF_DEBUG +#define CHK_ERR_PACK(V0, V1, V2, V3, V4, V5, V6) \ + { \ + assert ((V0) != NULL); \ + assert ((V3) != NULL); \ + err = MPI_Pack (V0, V1, V2, V3, V4, V5, V6); \ + CHK_MPIERR \ + } +#else +#define CHK_ERR_PACK(V0, V1, V2, V3, V4, V5, V6) \ + err = MPI_Pack (V0, V1, V2, V3, V4, V5, V6); \ + CHK_MPIERR +#endif + +#ifdef PNETCDF_DEBUG +#define CHK_ERR_UNPACK(V0, V1, V2, V3, V4, V5, V6) \ + { \ + int esize; \ + MPI_Type_size (V5, &esize); \ + if (V1 - *((int *)(V2)) < V4 * esize) { abort (); } \ + err = MPI_Unpack (V0, V1, V2, V3, V4, V5, V6); \ + CHK_MPIERR \ + } +#else +#define CHK_ERR_UNPACK(V0, V1, V2, V3, V4, V5, V6) \ + err = MPI_Unpack (V0, V1, V2, V3, V4, V5, V6); \ + CHK_MPIERR +#endif + +#define CHK_ERR_TYPE_COMMIT(V0) \ + err = MPI_Type_commit (V0); \ + CHK_MPIERR + +#ifdef PNETCDF_DEBUG +#define CHK_ERR_TYPE_CREATE_SUBARRAY(V0, V1, V2, V3, V4, V5, V6) \ + { \ + int d; \ + for (d = 0; d < V0; d++) { \ + if (V1[d] < V2[d] + V3[d]) { \ + printf ( \ + "Error: Subarray outside array at dim %d. size = %d, ssize = %d, start = " \ + "%d\n", \ + d, V1[d], V2[d], V3[d]); \ + abort (); \ + } \ + if (V2[d] <= 0) { \ + printf ("Error: Subarray size <= 0 at dim %d. ssize = %d\n", d, V2[d]); \ + abort (); \ + } \ + } \ + err = MPI_Type_create_subarray (V0, V1, V2, V3, V4, V5, V6); \ + CHK_MPIERR \ + } +#else +#define CHK_ERR_TYPE_CREATE_SUBARRAY(V0, V1, V2, V3, V4, V5, V6) \ + err = MPI_Type_create_subarray (V0, V1, V2, V3, V4, V5, V6); \ + CHK_MPIERR +#endif + +#define CHK_ERR_WAITALL(V0, V1, V2) \ + err = MPI_Waitall (V0, V1, V2); \ + CHK_MPIERR +#define CHK_ERR_MPROBE(V0, V1, V2, V3, V4) \ + err = MPI_Mprobe (V0, V1, V2, V3, V4); \ + CHK_MPIERR + +#define CHK_ERR_GET_COUNT(V0, V1, V2) \ + err = MPI_Get_count (V0, V1, V2); \ + CHK_MPIERR + +#define CHK_ERR_IMRECV(V0, V1, V2, V3, V4) \ + err = MPI_Imrecv (V0, V1, V2, V3, V4); \ + CHK_MPIERR + +#ifdef PNETCDF_DEBUG +#define CHK_ERR_ISEND(V0, V1, V2, V3, V4, V5, V6) \ + assert (V1 >= 0); \ + err = MPI_Isend (V0, V1, V2, V3, V4, V5, V6); \ + CHK_MPIERR +#else +#define CHK_ERR_ISEND(V0, V1, V2, V3, V4, V5, V6) \ + err = MPI_Isend (V0, V1, V2, V3, V4, V5, V6); \ + CHK_MPIERR +#endif + +#ifdef PNETCDF_DEBUG +#define CHK_ERR_IRECV(V0, V1, V2, V3, V4, V5, V6) \ + assert (V1 >= 0); \ + err = MPI_Irecv (V0, V1, V2, V3, V4, V5, V6); \ + CHK_MPIERR +#else +#define CHK_ERR_IRECV(V0, V1, V2, V3, V4, V5, V6) \ + err = MPI_Irecv (V0, V1, V2, V3, V4, V5, V6); \ + CHK_MPIERR +#endif + +#define CHK_ERR_SET_VIEW(V0, V1, V2, V3, V4, V5) \ + err = MPI_File_set_view (V0, V1, V2, V3, V4, V5); \ + CHK_MPIERR + +#define CHK_ERR_READ_AT_ALL(V0, V1, V2, V3, V4, V5) \ + err = MPI_File_read_at_all (V0, V1, V2, V3, V4, V5); \ + CHK_MPIERR + +#define CHK_ERR_WRITE_AT_ALL(V0, V1, V2, V3, V4, V5) \ + err = MPI_File_write_at_all (V0, V1, V2, V3, V4, V5); \ + CHK_MPIERR + +#define CHK_ALLOC(V0) \ + if (V0 == NULL) { DEBUG_RETURN_ERROR (NC_ENOMEM) } + +typedef struct NC_chk_vector { + int esize; + int size; + int nalloc; + char *data; +} NC_chk_vector; + +// File +extern int ncchkioi_init (NC_chk *, int); +extern int ncchkioi_parse_var_info (NC_chk *); +extern int ncchkioi_var_list_init (NC_chk_var_list *); +extern int ncchkioi_var_list_free (NC_chk_var_list *); +extern int ncchkioi_var_list_add (NC_chk_var_list *); + +// Util +extern int ncchkioi_extract_hint (NC_chk *, MPI_Info); +extern int ncchkioi_export_hint (NC_chk *, MPI_Info); +extern MPI_Offset NC_Type_size (nc_type); +extern void ncchkioi_sort_file_offset (int, MPI_Aint *, MPI_Aint *, int *); +extern int ncchkioi_update_statistics (NC_chk *); +extern int ncchkioi_get_default_chunk_dim (NC_chk *); +extern int ncchkioi_subarray_off_len (int, int *, int *, int *, MPI_Offset *, int *); +extern void ncchkioi_idx_in_swapn (NC_chk_chunk_index_entry *, MPI_Offset); +#ifdef PNETCDF_PROFILING +extern int ncchkioi_print_profile (NC_chk *); +extern void ncchkioi_profile_add_time (NC_chk *ncchkp, int id, double t); +#endif + +// Misc +typedef struct ncchkioi_chunk_overlap_t { + MPI_Offset osize; + int rank; +} ncchkioi_chunk_overlap_t; +extern int ncchkioi_init_nvar_core_reduce (NC_chk *ncchkp, + int nvar, + NC_chk_var **varps, + int *rcnt, + int *roff, + MPI_Offset **starts, + MPI_Offset **counts); +extern int ncchkioi_calc_chunk_overlap (NC_chk *ncchkp, + NC_chk_var *varp, + int nreq, + MPI_Offset **starts, + MPI_Offset **counts, + ncchkioi_chunk_overlap_t *ocnt); +extern void ncchkioi_assign_chunk_owner (NC_chk *ncchkp, + NC_chk_var *varp, + ncchkioi_chunk_overlap_t *ocnt); +extern int ncchkioi_sync_ocnt_reduce (NC_chk *ncchkp, + int nchunk, + ncchkioi_chunk_overlap_t *ocnt, + ncchkioi_chunk_overlap_t *ocnt_all, + MPI_Request *req); +extern void ncchkioi_write_chunk_ocnt (NC_chk *ncchkp, + NC_chk_var *varp, + void *ocnt, + size_t ocnt_size); +extern int ncchkioi_calc_chunk_owner (NC_chk *, NC_chk_var *, int, MPI_Offset **, MPI_Offset **); +extern int ncchkioi_calc_chunk_owner_reduce ( + NC_chk *ncchkp, NC_chk_var *varp, int nreq, MPI_Offset **starts, MPI_Offset **counts); +extern int ncchkioi_calc_chunk_size (NC_chk *, NC_chk_var *, int, MPI_Offset **, MPI_Offset **); +extern int ncchkioiconvert (void *, void *, MPI_Datatype, MPI_Datatype, int); + +// Var +extern int ncchkioi_var_init (NC_chk *, NC_chk_var *, int, MPI_Offset **, MPI_Offset **); +extern int ncchkioi_load_var (NC_chk *, NC_chk_var *, int, int *); +extern int ncchkioi_load_var_bg (NC_chk *, NC_chk_var *, int, int *); +extern int ncchkioi_load_nvar (NC_chk *, int, int *, int *, int *); +extern int ncchkioi_load_nvar_bg (NC_chk *, int, int *, int *, int *); +extern int ncchkioi_save_var (NC_chk *, NC_chk_var *); +extern int ncchkioi_save_nvar (NC_chk *, int, int *); +extern void ncchkioi_var_free (NC_chk_var *); +extern int ncchkioi_var_resize (NC_chk *, NC_chk_var *); +extern int ncchkioi_init_nvar (NC_chk *, int, int *, int, int *); +extern int ncchkioi_resize_nvar (NC_chk *, int, int *, int, int *); + +// Cache +extern int ncchkioi_cache_alloc (NC_chk *, MPI_Offset, NC_chk_cache **); +extern void ncchkioi_cache_visit (NC_chk *, NC_chk_cache *); +extern void ncchkioi_cache_free (NC_chk *); + +// Chunks +extern int ncchkioi_chunk_itr_init ( + NC_chk_var *, const MPI_Offset *, const MPI_Offset *, MPI_Offset *, int *); +extern int ncchkioi_chunk_itr_next ( + NC_chk_var *, const MPI_Offset *, const MPI_Offset *, MPI_Offset *, int *); +extern MPI_Offset get_chunk_overlap ( + NC_chk_var *, MPI_Offset *, const MPI_Offset *, const MPI_Offset *, MPI_Offset *, MPI_Offset *); +extern int get_chunk_id (NC_chk_var *, MPI_Offset *); +extern int get_chunk_itr (NC_chk_var *, int, MPI_Offset *); +extern int ncchkioi_chunk_itr_init_ex (NC_chk_var *, + const MPI_Offset *, + const MPI_Offset *, + MPI_Offset *, + int *, + MPI_Offset *, + MPI_Offset *); +extern int ncchkioi_chunk_itr_next_ex (NC_chk_var *, + const MPI_Offset *, + const MPI_Offset *, + MPI_Offset *, + int *, + MPI_Offset *, + MPI_Offset *); + +// Get +// extern int ncchkioi_get_var_old(NC_chk*, NC_chk_var*, MPI_Offset*, MPI_Offset*, MPI_Offset*, +// void*); +extern int ncchkioi_get_var_cb_chunk ( + NC_chk *, NC_chk_var *, const MPI_Offset *, const MPI_Offset *, const MPI_Offset *, void *); +extern int ncchkioi_get_var_cb_proc ( + NC_chk *, NC_chk_var *, const MPI_Offset *, const MPI_Offset *, const MPI_Offset *, void *); +extern int ncchkioi_get_varn ( + NC_chk *, NC_chk_var *, int, MPI_Offset *const *, MPI_Offset *const *, const void *); +extern int ncchkioi_get_varn_cb_chunk (NC_chk *, + NC_chk_var *, + int, + MPI_Offset *const *, + MPI_Offset *const *, + MPI_Offset *const *, + void **); +extern int ncchkioi_get_varn_cb_proc ( + NC_chk *, NC_chk_var *, int, MPI_Offset *const *, MPI_Offset *const *, void **); +extern int ncchkioi_iget_var (NC_chk *, + int, + const MPI_Offset *, + const MPI_Offset *, + const MPI_Offset *, + const MPI_Offset *, + void *, + MPI_Offset, + MPI_Datatype, + int *); +extern int ncchkioi_iget_varn (NC_chk *, + int, + int, + MPI_Offset *const *, + MPI_Offset *const *, + void *, + MPI_Offset, + MPI_Datatype, + int *); +extern int ncchkioi_iget_cb_chunk (NC_chk *, int, int *, int *); +extern int ncchkioi_iget_cb_proc (NC_chk *, int, int *, int *); + +// Put +// extern int ncchkioi_put_var_old(NC_chk*, NC_chk_var*, const MPI_Offset*, const MPI_Offset*, const +// MPI_Offset*, void*); +extern int ncchkioi_put_var ( + NC_chk *, NC_chk_var *, const MPI_Offset *, const MPI_Offset *, const MPI_Offset *, void *); +extern int ncchkioi_put_var_cb_chunk ( + NC_chk *, NC_chk_var *, const MPI_Offset *, const MPI_Offset *, const MPI_Offset *, void *); +extern int ncchkioi_put_var_cb_proc ( + NC_chk *, NC_chk_var *, const MPI_Offset *, const MPI_Offset *, const MPI_Offset *, void *); +extern int ncchkioi_put_varn ( + NC_chk *, NC_chk_var *, int, MPI_Offset *const *, MPI_Offset *const *, const void *); +extern int ncchkioi_put_varn_cb_chunk (NC_chk *, + NC_chk_var *, + int, + MPI_Offset *const *, + MPI_Offset *const *, + MPI_Offset *const *, + void **); +extern int ncchkioi_put_varn_cb_proc ( + NC_chk *, NC_chk_var *, int, MPI_Offset *const *, MPI_Offset *const *, void **); +extern int ncchkioi_iput_var (NC_chk *, + int, + const MPI_Offset *, + const MPI_Offset *, + const MPI_Offset *, + const void *, + const void *, + int *); +extern int ncchkioi_iput_varn (NC_chk *, + int, + int, + MPI_Offset *const *, + MPI_Offset *const *, + const void *, + const void *, + int *); +extern int ncchkioi_iput_cb_chunk (NC_chk *, int, int *, int *); +extern int ncchkioi_iput_cb_proc (NC_chk *, int, int *, int *); + +// Nonblocking +extern int ncchkioi_req_list_init (NC_chk_req_list *); +extern int ncchkioi_req_list_free (NC_chk_req_list *); +extern int ncchkioi_req_list_add (NC_chk_req_list *, int *); +extern int ncchkioi_req_list_remove (NC_chk_req_list *, int); +extern int ncchkioi_wait_put_reqs (NC_chk *, int, int *, int *); +extern int ncchkioi_wait_get_reqs (NC_chk *, int, int *, int *); +extern int ncchkioi_wait (NC_chk *, int, int *, int *, int); + +// Vector +extern int ncchkioi_vector_init (NC_chk_vector *, int); +extern int ncchkioi_vector_init_ex (NC_chk_vector *, int, int); +extern void ncchkioi_vector_free (NC_chk_vector *); +extern int ncchkioi_vector_append (NC_chk_vector *, void *); +#endif \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkio_var.c b/src/drivers/ncchunkio/ncchkio_var.c new file mode 100644 index 000000000..5aa7000c3 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkio_var.c @@ -0,0 +1,1130 @@ +/* + * Copyright (C) 2017, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_def_var() : dispatcher->def_var() + * ncmpi_inq_varid() : dispatcher->inq_varid() + * ncmpi_inq_var() : dispatcher->inq_var() + * ncmpi_rename_var() : dispatcher->rename_var() + * + * ncmpi_get_var() : dispatcher->get_var() + * ncmpi_put_var() : dispatcher->put_var() + * ncmpi_get_var_() : dispatcher->get_var() + * ncmpi_put_var_() : dispatcher->put_var() + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + * + * ncmpi_iget_var() : dispatcher->iget_var() + * ncmpi_iput_var() : dispatcher->iput_var() + * ncmpi_iget_var_() : dispatcher->iget_var() + * ncmpi_iput_var_() : dispatcher->iput_var() + * + * ncmpi_buffer_attach() : dispatcher->buffer_attach() + * ncmpi_buffer_detach() : dispatcher->buffer_detach() + * ncmpi_bput_var_() : dispatcher->bput_var() + * + * ncmpi_get_varn_() : dispatcher->get_varn() + * ncmpi_put_varn_() : dispatcher->put_varn() + * + * ncmpi_iget_varn_() : dispatcher->iget_varn() + * ncmpi_iput_varn_() : dispatcher->iput_varn() + * ncmpi_bput_varn_() : dispatcher->bput_varn() + * + * ncmpi_get_vard() : dispatcher->get_vard() + * ncmpi_put_vard() : dispatcher->put_vard() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "../ncmpio/ncmpio_NC.h" +#include "ncchkio_internal.h" + +int ncchkio_def_var ( + void *ncdp, const char *name, nc_type xtype, int ndims, const int *dimids, int *varidp) { + int i, err; + NC_chk *ncchkp = (NC_chk *)ncdp; + NC_chk_var *varp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT) + + err = ncchkioi_var_list_add (&(ncchkp->vars)); + if (err < 0) return err; + *varidp = err; + + varp = ncchkp->vars.data + (*varidp); + + varp->ndim = ndims; + varp->chunkdim = NULL; + varp->chunk_index = NULL; + varp->chunk_owner = NULL; + varp->xtype = xtype; + varp->esize = NC_Type_size (xtype); + varp->etype = ncmpii_nc2mpitype (xtype); + varp->isnew = 1; + varp->expanded = 0; + + if (ndims < 1) { // Do not compress scalar + varp->varkind = NC_CHK_VAR_RAW; + varp->dimsize = NULL; + + err = ncchkp->driver->def_var (ncchkp->ncp, name, xtype, ndims, dimids, &varp->varid); + if (err != NC_NOERR) return err; + + err = ncchkp->driver->put_att (ncchkp->ncp, varp->varid, "_varkind", NC_INT, 1, + &(varp->varkind), MPI_INT); // Comressed var? + if (err != NC_NOERR) return err; + } else { + err = ncchkp->driver->def_var (ncchkp->ncp, name, xtype, 0, NULL, + &varp->varid); // Dummy var for attrs + if (err != NC_NOERR) return err; + + varp->varkind = NC_CHK_VAR_COMPRESSED; + varp->dimids = (int *)NCI_Malloc (sizeof (int) * ndims); + memcpy (varp->dimids, dimids, sizeof (int) * ndims); + varp->dimsize = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * ndims); + for (i = 0; i < ndims; i++) { + ncchkp->driver->inq_dim (ncchkp->ncp, dimids[i], NULL, varp->dimsize + i); + } + if (varp->dimids[0] == ncchkp->recdim) { + varp->isrec = 1; + } else { + varp->isrec = 0; + } + + err = ncchkp->driver->put_att (ncchkp->ncp, varp->varid, "_ndim", NC_INT, 1, &ndims, + MPI_INT); // Original dimensions + if (err != NC_NOERR) return err; + err = ncchkp->driver->put_att (ncchkp->ncp, varp->varid, "_dimids", NC_INT, ndims, dimids, + MPI_INT); // Dimensiona IDs + if (err != NC_NOERR) return err; + err = ncchkp->driver->put_att (ncchkp->ncp, varp->varid, "_datatype", NC_INT, 1, &xtype, + MPI_INT); // Original datatype + if (err != NC_NOERR) return err; + err = ncchkp->driver->put_att (ncchkp->ncp, varp->varid, "_varkind", NC_INT, 1, + &(varp->varkind), MPI_INT); // Comressed var? + if (err != NC_NOERR) return err; + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + + return NC_NOERR; +} + +int ncchkio_inq_varid (void *ncdp, const char *name, int *varid) { + int i, vid, err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + + err = ncchkp->driver->inq_varid (ncchkp->ncp, name, &vid); + if (err != NC_NOERR) return err; + + if (varid != NULL) { + for (i = 0; i < ncchkp->vars.cnt; i++) { + if (ncchkp->vars.data[i].varid == vid) { + *varid = i; + break; + } + } + if (i >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_ENOTVAR) } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + + return NC_NOERR; +} + +int ncchkio_inq_var (void *ncdp, + int varid, + char *name, + nc_type *xtypep, + int *ndimsp, + int *dimids, + int *nattsp, + MPI_Offset *offsetp, + int *no_fillp, + void *fill_valuep) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + NC_chk_var *varp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + + if (varid < 0 || varid >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_EINVAL); } + + varp = ncchkp->vars.data + varid; + + err = ncchkp->driver->inq_var (ncchkp->ncp, varp->varid, name, xtypep, NULL, NULL, nattsp, + offsetp, no_fillp, fill_valuep); + if (err != NC_NOERR) return err; + + if (ndimsp != NULL) { *ndimsp = varp->ndim; } + + if (dimids != NULL) { memcpy (dimids, varp->dimids, sizeof (int) * varp->ndim); } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + + return NC_NOERR; +} + +int ncchkio_rename_var (void *ncdp, int varid, const char *newname) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + NC_chk_var *varp; + + if (varid < 0 || varid >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_EINVAL); } + varp = ncchkp->vars.data + varid; + + err = ncchkp->driver->rename_var (ncchkp->ncp, varp->varid, newname); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_get_var (void *ncdp, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode) { + int err = NC_NOERR, status = NC_NOERR, ret; + void *cbuf = (void *)buf; + void *xbuf = (void *)buf; + MPI_Offset nelem; + NC_chk_var *varp; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET) + + if (varid < 0 || varid >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_EINVAL); } + varp = ncchkp->vars.data + varid; + + if (varp->varkind == NC_CHK_VAR_RAW) { + return ncchkp->driver->get_var (ncchkp->ncp, varp->varid, start, count, stride, imap, buf, + bufcount, buftype, reqMode); + } + + if (ncchkp->delay_init && (varp->chunkdim == NULL)) { + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_META) + + err = ncchkioi_var_init (ncchkp, varp, 1, (MPI_Offset **)&start, (MPI_Offset **)&count); + CHK_ERR + + if (!(varp->isnew)) { + ret = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_metaoffset", + &(varp->metaoff), MPI_LONG_LONG); + if (ret == NC_NOERR) { // Read index table + MPI_Status status; + + // Set file view + CHK_ERR_SET_VIEW (((NC *)(ncchkp->ncp))->collective_fh, + ((NC *)(ncchkp->ncp))->begin_var, MPI_BYTE, MPI_BYTE, "native", + MPI_INFO_NULL); + // Read data + CHK_ERR_READ_AT_ALL ( + ((NC *)(ncchkp->ncp))->collective_fh, varp->metaoff, varp->chunk_index, + sizeof (NC_chk_chunk_index_entry) * varp->nchunk, MPI_BYTE, &status); + } else { + varp->metaoff = -1; + memset (varp->chunk_index, 0, + sizeof (NC_chk_chunk_index_entry) * (varp->nchunk + 1)); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_META) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET) + } + + if (varp->isrec && (varp->dimsize[0] < ncchkp->recsize) && + (start[0] + count[0] >= varp->dimsize[0])) { + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_RESIZE) + + err = ncchkioi_var_resize (ncchkp, varp); + CHK_ERR + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_RESIZE) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET) + } + + if (buftype != varp->etype) { + int i; + + nelem = 1; + for (i = 0; i < varp->ndim; i++) { nelem *= count[i]; } + + xbuf = (char *)NCI_Malloc (nelem * varp->esize); + CHK_PTR (xbuf) + } else { + xbuf = cbuf; + } + + // Collective buffer + switch (ncchkp->comm_unit) { + case NC_CHK_COMM_CHUNK: + err = ncchkioi_get_var_cb_chunk (ncchkp, varp, start, count, stride, xbuf); + break; + case NC_CHK_COMM_PROC: + err = ncchkioi_get_var_cb_proc (ncchkp, varp, start, count, stride, xbuf); + break; + } + CHK_ERR + + if (buftype != varp->etype) { + err = ncchkioiconvert (xbuf, cbuf, varp->etype, buftype, nelem); + if (err != NC_NOERR) return err; + } + + if (xbuf != cbuf) NCI_Free (xbuf); + if (cbuf != buf) NCI_Free (cbuf); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + +err_out:; + if (status == NC_NOERR) status = err; + return status; /* first error encountered */ +} + +int ncchkio_put_var (void *ncdp, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode) { + int err = NC_NOERR, ret; + void *cbuf = (void *)buf; + void *xbuf = (void *)buf; + NC_chk_var *varp; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT) + + if (reqMode == NC_REQ_INDEP) { DEBUG_RETURN_ERROR (NC_ENOTSUPPORT); } + + if (varid < 0 || varid >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_EINVAL); } + varp = ncchkp->vars.data + varid; + + if (varp->varkind == NC_CHK_VAR_RAW) { + return ncchkp->driver->put_var (ncchkp->ncp, varp->varid, start, count, stride, imap, buf, + bufcount, buftype, reqMode); + } + + if (ncchkp->delay_init && (varp->chunkdim == NULL)) { + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_PUT) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_META) + + err = ncchkioi_var_init (ncchkp, varp, 1, (MPI_Offset **)&start, (MPI_Offset **)&count); + CHK_ERR + + if (!(varp->isnew)) { + ret = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_metaoffset", + &(varp->metaoff), MPI_LONG_LONG); + if (ret == NC_NOERR) { // Read index table + MPI_Status status; + + // Set file view + CHK_ERR_SET_VIEW (((NC *)(ncchkp->ncp))->collective_fh, + ((NC *)(ncchkp->ncp))->begin_var, MPI_BYTE, MPI_BYTE, "native", + MPI_INFO_NULL); + // Read data + CHK_ERR_READ_AT_ALL ( + ((NC *)(ncchkp->ncp))->collective_fh, varp->metaoff, varp->chunk_index, + sizeof (NC_chk_chunk_index_entry) * varp->nchunk, MPI_BYTE, &status); + } else { + varp->metaoff = -1; + memset (varp->chunk_index, 0, + sizeof (NC_chk_chunk_index_entry) * (varp->nchunk + 1)); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_META) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT) + } + + if (imap != NULL || bufcount != -1) { + /* pack buf to cbuf -------------------------------------------------*/ + /* If called from a true varm API or a flexible API, ncmpii_pack() + * packs user buf into a contiguous cbuf (need to be freed later). + * Otherwise, cbuf is simply set to buf. ncmpii_pack() also returns + * etype (MPI primitive datatype in buftype), and nelems (number of + * etypes in buftype * bufcount) + */ + int ndims; + MPI_Offset nelems; + MPI_Datatype etype; + + err = ncchkp->driver->inq_var (ncchkp->ncp, varid, NULL, NULL, &ndims, NULL, NULL, NULL, + NULL, NULL); + if (err != NC_NOERR) goto err_check; + + err = ncmpii_pack (ndims, count, imap, (void *)buf, bufcount, buftype, &nelems, &etype, + &cbuf); + if (err != NC_NOERR) goto err_check; + + imap = NULL; + bufcount = (nelems == 0) ? 0 : -1; /* make it a high-level API */ + buftype = etype; /* an MPI primitive type */ + } + +err_check: + if (err != NC_NOERR) { + if (reqMode & NC_REQ_INDEP) return err; + reqMode |= NC_REQ_ZERO; /* participate collective call */ + } + + if (buftype != varp->etype) { + int i; + MPI_Offset nelem; + + nelem = 1; + for (i = 0; i < varp->ndim; i++) { nelem *= count[i]; } + + xbuf = (char *)NCI_Malloc (nelem * varp->esize); + CHK_PTR (xbuf) + err = ncchkioiconvert (cbuf, xbuf, buftype, varp->etype, nelem); + if (err != NC_NOERR) return err; + } else { + xbuf = cbuf; + } + + err = ncchkioi_put_var (ncchkp, varp, start, count, stride, xbuf); + CHK_ERR + + if (cbuf != buf) NCI_Free (cbuf); + + if (xbuf != cbuf) NCI_Free (xbuf); + if (cbuf != buf) NCI_Free (cbuf); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + +err_out:; + return err; /* first error encountered */ +} + +int ncchkio_iget_var (void *ncdp, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *reqid, + int reqMode) { + int err; + void *cbuf = (void *)buf; + void *xbuf = (void *)buf; + NC_chk_var *varp; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_START (NC_CHK_TIMER_IGET) + + if (reqMode == NC_REQ_INDEP) { DEBUG_RETURN_ERROR (NC_ENOTSUPPORT); } + + if (varid < 0 || varid >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_EINVAL); } + varp = ncchkp->vars.data + varid; + + if (varp->varkind == NC_CHK_VAR_RAW) { + err = ncchkp->driver->iget_var (ncchkp->ncp, varp->varid, start, count, stride, imap, buf, + bufcount, buftype, reqid, reqMode); + if (err != NC_NOERR) { return err; } + if (reqid != NULL) { *reqid = *reqid * 2 + 1; } + return NC_NOERR; + } + + ncchkioi_iget_var (ncchkp, varid, start, count, stride, imap, buf, bufcount, buftype, reqid); + if (reqid != NULL) { (*reqid) *= 2; } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_IGET) + + return NC_NOERR; +} + +int ncchkio_iput_var (void *ncdp, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *reqid, + int reqMode) { + int err = NC_NOERR; + void *cbuf = (void *)buf; + void *xbuf = (void *)buf; + NC_chk_var *varp; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_START (NC_CHK_TIMER_IPUT) + + if (reqMode == NC_REQ_INDEP) { DEBUG_RETURN_ERROR (NC_ENOTSUPPORT); } + + if (varid < 0 || varid >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_EINVAL); } + varp = ncchkp->vars.data + varid; + + if (varp->varkind == NC_CHK_VAR_RAW) { + err = ncchkp->driver->iput_var (ncchkp->ncp, varp->varid, start, count, stride, imap, buf, + bufcount, buftype, reqid, reqMode); + if (err != NC_NOERR) { return err; } + if (reqid != NULL) { *reqid = *reqid * 2 + 1; } + return NC_NOERR; + } + + if (varp->isrec) { + if (ncchkp->recsize < start[0] + count[0]) { ncchkp->recsize = start[0] + count[0]; } + } + + if (imap != NULL || bufcount != -1) { + /* pack buf to cbuf -------------------------------------------------*/ + /* If called from a true varm API or a flexible API, ncmpii_pack() + * packs user buf into a contiguous cbuf (need to be freed later). + * Otherwise, cbuf is simply set to buf. ncmpii_pack() also returns + * etype (MPI primitive datatype in buftype), and nelems (number of + * etypes in buftype * bufcount) + */ + int ndims; + MPI_Offset nelems; + MPI_Datatype etype; + + err = ncchkp->driver->inq_var (ncchkp->ncp, varid, NULL, NULL, &ndims, NULL, NULL, NULL, + NULL, NULL); + if (err != NC_NOERR) goto err_check; + + err = ncmpii_pack (ndims, count, imap, (void *)buf, bufcount, buftype, &nelems, &etype, + &cbuf); + if (err != NC_NOERR) goto err_check; + + imap = NULL; + bufcount = (nelems == 0) ? 0 : -1; /* make it a high-level API */ + buftype = etype; /* an MPI primitive type */ + } + +err_check: + if (err != NC_NOERR) { + if (reqMode & NC_REQ_INDEP) return err; + reqMode |= NC_REQ_ZERO; /* participate collective call */ + } + + if (buftype != varp->etype) { + int i; + MPI_Offset nelem; + + nelem = 1; + for (i = 0; i < varp->ndim; i++) { nelem *= count[i]; } + + xbuf = (char *)NCI_Malloc (nelem * varp->esize); + CHK_PTR (xbuf) + err = ncchkioiconvert (cbuf, xbuf, buftype, varp->etype, nelem); + if (err != NC_NOERR) return err; + } else { + xbuf = cbuf; + } + + err = ncchkioi_iput_var (ncchkp, varid, start, count, stride, xbuf, buf, reqid); + if (reqid != NULL) { (*reqid) *= 2; } + + if (cbuf != buf && cbuf != xbuf) NCI_Free (cbuf); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_IPUT) + +err_out:; + return err; +} + +int ncchkio_buffer_attach (void *ncdp, MPI_Offset bufsize) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->buffer_attach (ncchkp->ncp, bufsize); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_buffer_detach (void *ncdp) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + err = ncchkp->driver->buffer_detach (ncchkp->ncp); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_bput_var (void *ncdp, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *reqid, + int reqMode) { + int err = NC_NOERR; + int i; + void *cbuf = (void *)buf; + void *xbuf; + MPI_Offset nelem; + NC_chk_var *varp; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_START (NC_CHK_TIMER_IPUT) + + if (reqMode == NC_REQ_INDEP) { DEBUG_RETURN_ERROR (NC_ENOTSUPPORT); } + + if (varid < 0 || varid >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_EINVAL); } + varp = ncchkp->vars.data + varid; + + if (varp->varkind == NC_CHK_VAR_RAW) { + err = ncchkp->driver->bput_var (ncchkp->ncp, varp->varid, start, count, stride, imap, buf, + bufcount, buftype, reqid, reqMode); + if (err != NC_NOERR) { return err; } + if (reqid != NULL) { *reqid = *reqid * 2 + 1; } + return NC_NOERR; + } + + if (varp->isrec) { + if (ncchkp->recsize < start[0] + count[0]) { ncchkp->recsize = start[0] + count[0]; } + } + + if (imap != NULL || bufcount != -1) { + /* pack buf to cbuf -------------------------------------------------*/ + /* If called from a true varm API or a flexible API, ncmpii_pack() + * packs user buf into a contiguous cbuf (need to be freed later). + * Otherwise, cbuf is simply set to buf. ncmpii_pack() also returns + * etype (MPI primitive datatype in buftype), and nelems (number of + * etypes in buftype * bufcount) + */ + int ndims; + MPI_Offset nelems; + MPI_Datatype etype; + + err = ncchkp->driver->inq_var (ncchkp->ncp, varid, NULL, NULL, &ndims, NULL, NULL, NULL, + NULL, NULL); + if (err != NC_NOERR) goto err_check; + + err = ncmpii_pack (ndims, count, imap, (void *)buf, bufcount, buftype, &nelems, &etype, + &cbuf); + if (err != NC_NOERR) goto err_check; + + imap = NULL; + bufcount = (nelems == 0) ? 0 : -1; /* make it a high-level API */ + buftype = etype; /* an MPI primitive type */ + } + +err_check: + if (err != NC_NOERR) { + if (reqMode & NC_REQ_INDEP) return err; + reqMode |= NC_REQ_ZERO; /* participate collective call */ + } + + nelem = 1; + for (i = 0; i < varp->ndim; i++) { nelem *= count[i]; } + + xbuf = (char *)NCI_Malloc (nelem * varp->esize); + CHK_PTR (xbuf) + + if (buftype != varp->etype) { + err = ncchkioiconvert (cbuf, xbuf, buftype, varp->etype, nelem); + if (err != NC_NOERR) return err; + } else { + memcpy (xbuf, cbuf, varp->esize * nelem); + } + + err = ncchkioi_iput_var (ncchkp, varid, start, count, stride, xbuf, buf, reqid); + CHK_ERR + if (reqid != NULL) { (*reqid) *= 2; } + + if (cbuf != buf) NCI_Free (cbuf); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_IPUT) + +err_out:; + return err; +} +int ncchkio_get_varn (void *ncdp, + int varid, + int num, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode) { + int err = NC_NOERR, ret; + int i; + void *cbuf = (void *)buf; + void *xbuf = (void *)buf; + MPI_Offset nelem; + NC_chk_var *varp; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET) + + if (reqMode == NC_REQ_INDEP) { DEBUG_RETURN_ERROR (NC_ENOTSUPPORT); } + + if (varid < 0 || varid >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_EINVAL); } + varp = ncchkp->vars.data + varid; + + if (varp->varkind == NC_CHK_VAR_RAW) { + return ncchkp->driver->get_varn (ncchkp->ncp, varp->varid, num, starts, counts, buf, + bufcount, buftype, reqMode); + } + + if (ncchkp->delay_init && (varp->chunkdim == NULL)) { + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_META) + + err = ncchkioi_var_init (ncchkp, varp, num, (MPI_Offset **)starts, (MPI_Offset **)counts); + CHK_ERR + + if (!(varp->isnew)) { + ret = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_metaoffset", + &(varp->metaoff), MPI_LONG_LONG); + if (ret == NC_NOERR) { // Read index table + MPI_Status status; + + // Set file view + CHK_ERR_SET_VIEW (((NC *)(ncchkp->ncp))->collective_fh, + ((NC *)(ncchkp->ncp))->begin_var, MPI_BYTE, MPI_BYTE, "native", + MPI_INFO_NULL); + // Read data + CHK_ERR_READ_AT_ALL ( + ((NC *)(ncchkp->ncp))->collective_fh, varp->metaoff, varp->chunk_index, + sizeof (NC_chk_chunk_index_entry) * varp->nchunk, MPI_BYTE, &status); + } else { + varp->metaoff = -1; + memset (varp->chunk_index, 0, + sizeof (NC_chk_chunk_index_entry) * (varp->nchunk + 1)); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_META) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET) + } + + if (varp->isrec && (varp->dimsize[0] < ncchkp->recsize)) { + for (i = 0; i < num; i++) { + if (starts[i][0] + counts[i][0] >= varp->dimsize[0]) { + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_RESIZE) + + err = ncchkioi_var_resize (ncchkp, varp); + CHK_ERR + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_RESIZE) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET) + + break; + } + } + } + + if (buftype != varp->etype) { + int j; + MPI_Offset tmp; + + nelem = 0; + for (i = 0; i < num; i++) { + tmp = 1; + for (j = 0; j < varp->ndim; j++) { tmp *= counts[i][j]; } + nelem += tmp; + } + + xbuf = (char *)NCI_Malloc (nelem * varp->esize); + CHK_PTR (xbuf) + } else { + xbuf = cbuf; + } + + err = ncchkioi_get_varn (ncchkp, varp, num, starts, counts, xbuf); + if (err != NC_NOERR) return err; + + if (buftype != varp->etype) { + err = ncchkioiconvert (xbuf, cbuf, varp->etype, buftype, nelem); + if (err != NC_NOERR) return err; + } + + if (xbuf != cbuf) NCI_Free (xbuf); + if (cbuf != buf) NCI_Free (cbuf); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + +err_out:; + return err; +} + +int ncchkio_put_varn (void *ncdp, + int varid, + int num, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode) { + int err = NC_NOERR, ret; + void *cbuf = (void *)buf; + void *xbuf = (void *)buf; + NC_chk_var *varp; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT) + + if (reqMode == NC_REQ_INDEP) { DEBUG_RETURN_ERROR (NC_ENOTSUPPORT); } + + if (varid < 0 || varid >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_EINVAL); } + varp = ncchkp->vars.data + varid; + + if (varp->varkind == NC_CHK_VAR_RAW) { + return ncchkp->driver->put_varn (ncchkp->ncp, varp->varid, num, starts, counts, buf, + bufcount, buftype, reqMode); + } + + if (ncchkp->delay_init && (varp->chunkdim == NULL)) { + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_PUT) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_META) + + err = ncchkioi_var_init (ncchkp, varp, num, (MPI_Offset **)starts, (MPI_Offset **)counts); + CHK_ERR + if (!(varp->isnew)) { + ret = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_metaoffset", + &(varp->metaoff), MPI_LONG_LONG); + if (ret == NC_NOERR) { // Read index table + MPI_Status status; + + // Set file view + CHK_ERR_SET_VIEW (((NC *)(ncchkp->ncp))->collective_fh, + ((NC *)(ncchkp->ncp))->begin_var, MPI_BYTE, MPI_BYTE, "native", + MPI_INFO_NULL); + // Read data + CHK_ERR_READ_AT_ALL ( + ((NC *)(ncchkp->ncp))->collective_fh, varp->metaoff, varp->chunk_index, + sizeof (NC_chk_chunk_index_entry) * varp->nchunk, MPI_BYTE, &status); + } else { + varp->metaoff = -1; + memset (varp->chunk_index, 0, + sizeof (NC_chk_chunk_index_entry) * (varp->nchunk + 1)); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_META) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT) + } + + if (buftype != varp->etype) { + int i, j; + MPI_Offset nelem, tmp; + + nelem = 0; + for (i = 0; i < num; i++) { + tmp = 1; + for (j = 0; j < varp->ndim; j++) { tmp *= counts[i][j]; } + nelem += tmp; + } + + xbuf = (char *)NCI_Malloc (nelem * varp->esize); + CHK_PTR (xbuf) + err = ncchkioiconvert (cbuf, xbuf, buftype, varp->etype, nelem); + if (err != NC_NOERR) return err; + } else { + xbuf = cbuf; + } + + err = ncchkioi_put_varn (ncchkp, varp, num, starts, counts, xbuf); + if (err != NC_NOERR) return err; + +err_out:; + if (xbuf != cbuf) NCI_Free (xbuf); + if (cbuf != buf) NCI_Free (cbuf); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + + return err; +} + +int ncchkio_iget_varn (void *ncdp, + int varid, + int num, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *reqid, + int reqMode) { + int err; + void *cbuf = (void *)buf; + void *xbuf = (void *)buf; + NC_chk_var *varp; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_START (NC_CHK_TIMER_IGET) + + if (reqMode == NC_REQ_INDEP) { DEBUG_RETURN_ERROR (NC_ENOTSUPPORT); } + + if (varid < 0 || varid >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_EINVAL); } + varp = ncchkp->vars.data + varid; + + if (varp->varkind == NC_CHK_VAR_RAW) { + err = ncchkp->driver->iget_varn (ncchkp->ncp, varp->varid, num, starts, counts, buf, + bufcount, buftype, reqid, reqMode); + if (err != NC_NOERR) { return err; } + if (reqid != NULL) { *reqid = *reqid * 2 + 1; } + return NC_NOERR; + } + + xbuf = cbuf; + err = ncchkioi_iget_varn (ncchkp, varid, num, starts, counts, buf, bufcount, buftype, reqid); + if (err != NC_NOERR) return err; + if (reqid != NULL) { (*reqid) *= 2; } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_IGET) + + return NC_NOERR; +} + +int ncchkio_iput_varn (void *ncdp, + int varid, + int num, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *reqid, + int reqMode) { + int err; + int i; + void *cbuf = (void *)buf; + void *xbuf = (void *)buf; + NC_chk_var *varp; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_START (NC_CHK_TIMER_IPUT) + + if (reqMode == NC_REQ_INDEP) { DEBUG_RETURN_ERROR (NC_ENOTSUPPORT); } + + if (varid < 0 || varid >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_EINVAL); } + varp = ncchkp->vars.data + varid; + + if (varp->isrec) { + for (i = 0; i < num; i++) { + if (ncchkp->recsize < starts[i][0] + counts[i][0]) { + ncchkp->recsize = starts[i][0] + counts[i][0]; + } + } + } + + if (varp->varkind == NC_CHK_VAR_RAW) { + err = ncchkp->driver->iput_varn (ncchkp->ncp, varp->varid, num, starts, counts, buf, + bufcount, buftype, reqid, reqMode); + if (err != NC_NOERR) { return err; } + if (reqid != NULL) { *reqid = *reqid * 2 + 1; } + return NC_NOERR; + } + + if (buftype != varp->etype) { + int j; + MPI_Offset nelem, tmp; + + nelem = 0; + for (i = 0; i < num; i++) { + tmp = 1; + for (j = 0; j < varp->ndim; j++) { tmp *= counts[i][j]; } + nelem += tmp; + } + + xbuf = (char *)NCI_Malloc (nelem * varp->esize); + err = ncchkioiconvert (cbuf, xbuf, buftype, varp->etype, nelem); + if (err != NC_NOERR) return err; + } else { + xbuf = cbuf; + } + + err = ncchkioi_iput_varn (ncchkp, varid, num, starts, counts, xbuf, buf, reqid); + if (err != NC_NOERR) return err; + if (reqid != NULL) { (*reqid) *= 2; } + + if (cbuf != buf && cbuf != xbuf) NCI_Free (cbuf); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_IPUT) + + return NC_NOERR; +} + +int ncchkio_bput_varn (void *ncdp, + int varid, + int num, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *reqid, + int reqMode) { + int err; + int i, j; + void *cbuf = (void *)buf; + void *xbuf = (void *)buf; + MPI_Offset nelem, tmp; + NC_chk_var *varp; + NC_chk *ncchkp = (NC_chk *)ncdp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_START (NC_CHK_TIMER_IPUT) + + if (reqMode == NC_REQ_INDEP) { DEBUG_RETURN_ERROR (NC_ENOTSUPPORT); } + + if (varid < 0 || varid >= ncchkp->vars.cnt) { DEBUG_RETURN_ERROR (NC_EINVAL); } + varp = ncchkp->vars.data + varid; + + if (varp->isrec) { + for (i = 0; i < num; i++) { + if (ncchkp->recsize < starts[i][0] + counts[i][0]) { + ncchkp->recsize = starts[i][0] + counts[i][0]; + } + } + } + + if (varp->varkind == NC_CHK_VAR_RAW) { + err = ncchkp->driver->bput_varn (ncchkp->ncp, varp->varid, num, starts, counts, buf, + bufcount, buftype, reqid, reqMode); + if (err != NC_NOERR) { return err; } + if (reqid != NULL) { *reqid = *reqid * 2 + 1; } + return NC_NOERR; + } + + nelem = 0; + for (i = 0; i < num; i++) { + tmp = 1; + for (j = 0; j < varp->ndim; j++) { tmp *= counts[i][j]; } + nelem += tmp; + } + xbuf = (char *)NCI_Malloc (nelem * varp->esize); + + if (buftype != varp->etype) { + err = ncchkioiconvert (cbuf, xbuf, buftype, varp->etype, nelem); + if (err != NC_NOERR) return err; + } else { + memcpy (xbuf, cbuf, nelem * varp->esize); + } + + err = ncchkioi_iput_varn (ncchkp, varid, num, starts, counts, xbuf, buf, reqid); + if (err != NC_NOERR) return err; + if (reqid != NULL) { (*reqid) *= 2; } + + if (cbuf != buf && cbuf != xbuf) NCI_Free (cbuf); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_TOTAL) + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_IPUT) + + return NC_NOERR; +} + +int ncchkio_get_vard (void *ncdp, + int varid, + MPI_Datatype filetype, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + DEBUG_RETURN_ERROR (NC_ENOTSUPPORT); + + err = ncchkp->driver->get_vard (ncchkp->ncp, varid, filetype, buf, bufcount, buftype, reqMode); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} + +int ncchkio_put_vard (void *ncdp, + int varid, + MPI_Datatype filetype, + const void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode) { + int err; + NC_chk *ncchkp = (NC_chk *)ncdp; + + DEBUG_RETURN_ERROR (NC_ENOTSUPPORT); + + err = ncchkp->driver->put_vard (ncchkp->ncp, varid, filetype, buf, bufcount, buftype, reqMode); + if (err != NC_NOERR) return err; + + return NC_NOERR; +} diff --git a/src/drivers/ncchunkio/ncchkioi_cache.c b/src/drivers/ncchunkio/ncchkioi_cache.c new file mode 100644 index 000000000..8dc02fb90 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_cache.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ncchkio_internal.h" + +static int ncchkioi_cache_evict (NC_chk *ncchkp) { + int err=NC_NOERR; + NC_chk_cache *target; + + target = ncchkp->cache_head; + + if (target == NULL || target->serial >= ncchkp->cache_serial) { + printf ("Rank %d: Cache limit exceeded\n", ncchkp->rank); + RET_ERR(NC_ENOMEM) + } + + // Remove from list + ncchkp->cache_head = target->next; + if (ncchkp->cache_tail == target) { ncchkp->cache_tail = NULL; } + + ncchkp->cache_used -= target->bsize; // Return budget + ncchkp->cache_head = target->next; + + *(target->ref) = NULL; // Mark as evicted + NCI_Free (target->buf); + NCI_Free (target); + +err_out:; + return err; +} + +int ncchkioi_cache_alloc (NC_chk *ncchkp, MPI_Offset size, NC_chk_cache **ref) { + int err = NC_NOERR; + NC_chk_cache *target; + + // Evict cached data if no space + if (ncchkp->cache_limit > 0) { + while (ncchkp->cache_used + size > ncchkp->cache_limit) { + err = ncchkioi_cache_evict (ncchkp); + CHK_ERR + } + } + ncchkp->cache_used += size; + + // Prepare cache entry + target = (NC_chk_cache *)NCI_Malloc (sizeof (NC_chk_cache)); + if (target == NULL) { DEBUG_RETURN_ERROR (NC_ENOMEM) } + target->bsize = size; + target->next = NULL; + target->prev = ncchkp->cache_tail; + target->ref = ref; + target->serial = ncchkp->cache_serial; + target->buf = NCI_Malloc (size); +#ifdef PNETCDF_DEBUG + memset (target->buf, 0, size); +#endif + + // Insert to list tail + if (ncchkp->cache_tail != NULL) { + ncchkp->cache_tail->next = target; + } else { + ncchkp->cache_head = target; + } + ncchkp->cache_tail = target; + + // Assign reference + *ref = target; + +err_out:; + return err; +} + +void ncchkioi_cache_visit (NC_chk *ncchkp, NC_chk_cache *target) { + if (target != ncchkp->cache_tail) { + // Remove from list + if (target->prev != NULL) { target->prev->next = target->next; } + if (target->next != NULL) { target->next->prev = target->prev; } + + // Insert to list tail + target->next = NULL; + target->prev = ncchkp->cache_tail; + ncchkp->cache_tail->next = target; + ncchkp->cache_tail = target; + } +} + +void ncchkioi_cache_free (NC_chk *ncchkp) { + NC_chk_cache *pre, *cur; + + cur = ncchkp->cache_head; + while (cur != NULL) { + pre = cur; + cur = cur->next; + NCI_Free (pre->buf); + NCI_Free (pre); + } +} diff --git a/src/drivers/ncchunkio/ncchkioi_chunk.c b/src/drivers/ncchunkio/ncchkioi_chunk.c new file mode 100644 index 000000000..ebd3c70d8 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_chunk.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "ncchkio_internal.h" + + +#define min(a,b) (((a)<(b))?(a):(b)) +#define max(a,b) (((a)>(b))?(a):(b)) + +MPI_Offset get_chunk_overlap(NC_chk_var *varp, MPI_Offset* cord, const MPI_Offset *start, const MPI_Offset *count, MPI_Offset *ostart, MPI_Offset *ocount){ + int i; + MPI_Offset ret = varp->esize; + + for(i = 0; i < varp->ndim; i++){ + ostart[i] = max(start[i], cord[i]); + ocount[i] = min(start[i] + count[i], cord[i] + varp->chunkdim[i]) - ostart[i]; + if (ocount[i] <= 0){ + ocount[i] = 0; + } + ret *= ocount[i]; + } + + return ret; +} + +int get_chunk_id(NC_chk_var *varp, MPI_Offset *cord){ + int i, ret; + + ret = (int)(cord[0]) / varp->chunkdim[0]; + for(i = 1; i < varp->ndim; i++){ + ret = ret * varp->nchunks[i] + (int)(cord[i]) / varp->chunkdim[i]; + } + + return ret; +} + +int get_chunk_itr(NC_chk_var *varp, int idx, MPI_Offset* cord){ + int i; + + for(i = varp->ndim - 1; i >= 0; i--){ + cord[i] = (idx % varp->nchunks[i]) * varp->chunkdim[i]; + idx /= varp->nchunks[i]; + } + + return 0; +} + +int ncchkioi_chunk_itr_init(NC_chk_var *varp, const MPI_Offset *start, const MPI_Offset *count, MPI_Offset *citr, int *cid){ + int i; + + *cid = 0; + for(i = 0; i < varp->ndim; i++){ + citr[i] = start[i] - (start[i] % varp->chunkdim[i]); + *cid += citr[i] / varp->chunkdim[i] * varp->cidsteps[i]; + } + + return NC_NOERR; +} + +int ncchkioi_chunk_itr_next(NC_chk_var *varp, const MPI_Offset *start, const MPI_Offset *count, MPI_Offset *citr, int *cid){ + int i, j; + int nchk = 1; + + i = varp->ndim - 1; + citr[i] += varp->chunkdim[i]; + (*cid)++; + for(; i > 0; i--){ + if (citr[i] >= start[i] + count[i]){ + citr[i - 1] += varp->chunkdim[i - 1]; + j = citr[i]; + citr[i] = start[i] - (start[i] % varp->chunkdim[i]); + *cid += varp->cidsteps[i - 1] - varp->cidsteps[i] * (j - citr[i]) / varp->chunkdim[i]; + } + else{ + break; + } + } + + if (citr[0] >= start[0] + count[0]){ + return 0; + } + + return 1; +} + +int ncchkioi_chunk_itr_init_ex(NC_chk_var *varp, const MPI_Offset *start, const MPI_Offset *count, MPI_Offset *citr, int *cid, MPI_Offset *ostart, MPI_Offset *ocount){ + int i; + + *cid = 0; + for(i = 0; i < varp->ndim; i++){ + citr[i] = start[i] - (start[i] % varp->chunkdim[i]); + *cid += citr[i] / varp->chunkdim[i] * varp->cidsteps[i]; + ostart[i] = start[i]; + ocount[i] = min(count[i], citr[i] + varp->chunkdim[i] - ostart[i]); + } + + return NC_NOERR; +} + +int ncchkioi_chunk_itr_next_ex(NC_chk_var *varp, const MPI_Offset *start, const MPI_Offset *count, MPI_Offset *citr, int *cid, MPI_Offset *ostart, MPI_Offset *ocount){ + int i, j; + int nchk = 1; + + i = varp->ndim - 1; + citr[i] += varp->chunkdim[i]; + + (*cid)++; + for(; i > 0; i--){ + if (citr[i] >= start[i] + count[i]){ + citr[i - 1] += varp->chunkdim[i - 1]; + ostart[i - 1] += ocount[i - 1]; + ocount[i - 1] = min(varp->chunkdim[i - 1], start[i - 1] + count[i - 1] - ostart[i - 1]); + j = citr[i]; + citr[i] = start[i] - (start[i] % varp->chunkdim[i]); + ostart[i] = start[i]; + ocount[i] = min(count[i], citr[i] + varp->chunkdim[i] - ostart[i]); + *cid += varp->cidsteps[i - 1] - varp->cidsteps[i] * (j - citr[i]) / varp->chunkdim[i]; + } + else{ + break; + } + } + + if (citr[0] >= start[0] + count[0]){ + return 0; + } + + if (i == varp->ndim - 1){ + ostart[i] += ocount[i]; + ocount[i] = min(varp->chunkdim[i], start[i] + count[i] - ostart[i]); + for (i++; i < varp->ndim; i++) { + ostart[i] = start[i]; + ocount[i] = min(count[i], citr[i] + varp->chunkdim[i] - ostart[i]); + } + } + + return 1; +} \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkioi_chunk_owner.c b/src/drivers/ncchunkio/ncchkioi_chunk_owner.c new file mode 100644 index 000000000..7e1fbc4eb --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_chunk_owner.c @@ -0,0 +1,627 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ncchkio_internal.h" + +void ncchkioi_write_chunk_ocnt (NC_chk *ncchkp, NC_chk_var *varp, void *ocnt, size_t ocnt_size) { +#ifdef PNETCDF_PROFILING + { + int i, j; + char *pprefix = getenv ("PNETCDF_OWNER_PREFIX"); + + if (pprefix != NULL) { + if (ncchkp->rank == 0) { + void *ocnt_in; + int *cown; + MPI_Status stat; + FILE *pfile; + char fname[1024], ppath[1024]; + + ocnt_in = NCI_Malloc (ocnt_size * varp->nchunkrec); + cown = NCI_Malloc (sizeof (int) * varp->nchunkrec); + + strcpy (fname, ncchkp->path); + for (i = strlen (fname); i > 0; i--) { + if (fname[i] == '.') { + fname[i] = '\0'; + } else if (fname[i] == '\\' || fname[i] == '/') { + i++; + break; + } + } + sprintf (ppath, "%s%s_owner.csv", pprefix, fname + i); + pfile = fopen (ppath, "a"); + + fprintf (pfile, "Var:, %d\n", varp->varid); + fprintf (pfile, "Rank\\Chunk, "); + for (j = 0; j < varp->nchunkrec; j++) { fprintf (pfile, "%d, ", j); } + fprintf (pfile, "\nOwner, "); + for (j = 0; j < varp->nchunk; j++) { + fprintf (pfile, "%d, ", varp->chunk_owner[j]); + } + fprintf (pfile, "\n0, "); + if (ocnt_size == sizeof (MPI_Offset)) { + for (j = 0; j < varp->nchunkrec; j++) { + fprintf (pfile, "%lld, ", ((MPI_Offset *)ocnt)[j]); + } + } else { + for (j = 0; j < varp->nchunkrec; j++) { + fprintf (pfile, "%lld, ", ((ncchkioi_chunk_overlap_t *)ocnt)[j].osize); + } + } + fprintf (pfile, "\n"); + for (i = 1; i < ncchkp->np; i++) { + if (ocnt_size == sizeof (MPI_Offset)) { + MPI_Recv (ocnt_in, varp->nchunkrec, MPI_LONG_LONG, i, 0, ncchkp->comm, + &stat); + fprintf (pfile, "%d, ", i); + for (j = 0; j < varp->nchunkrec; j++) { + fprintf (pfile, "%lld, ", ((MPI_Offset *)ocnt_in)[j]); + } + } else { + MPI_Recv (ocnt_in, varp->nchunkrec, ncchkp->overlaptype, i, 0, ncchkp->comm, + &stat); + fprintf (pfile, "%d, ", i); + for (j = 0; j < varp->nchunkrec; j++) { + fprintf (pfile, "%lld, ", + ((ncchkioi_chunk_overlap_t *)ocnt_in)[j].osize); + } + } + fprintf (pfile, "\n"); + + MPI_Recv (cown, varp->nchunkrec, MPI_INT, i, 0, ncchkp->comm, &stat); + for (j = 0; j < varp->nchunkrec; j++) { + if (cown[j] != varp->chunk_owner[j]) { + printf ("Warning: cown[%d][%d] on rank %d = %d, != %d\n", varp->varid, j, + i, cown[j], varp->chunk_owner[j]); + } + } + } + + fclose (pfile); + NCI_Free (ocnt_in); + NCI_Free (cown); + } else { + if (ocnt_size == sizeof (MPI_Offset)) { + MPI_Send (ocnt, varp->nchunkrec, MPI_LONG_LONG, 0, 0, ncchkp->comm); + } else { + MPI_Send (ocnt, varp->nchunkrec, ncchkp->overlaptype, 0, 0, ncchkp->comm); + } + MPI_Send (varp->chunk_owner, varp->nchunkrec, MPI_INT, 0, 0, ncchkp->comm); + } + } + } +#endif +} + +void max_osize_rank_op (void *inp, void *inoutp, int *len, MPI_Datatype *dptr) { + int i; + ncchkioi_chunk_overlap_t *in = (ncchkioi_chunk_overlap_t *)inp; + ncchkioi_chunk_overlap_t *inout = (ncchkioi_chunk_overlap_t *)inoutp; + + for (i = 0; i < *len; i++) { + if (in->osize > inout->osize) { + inout->osize = in->osize; + inout->rank = in->rank; + } else if ((in->osize == inout->osize) && (in->rank < inout->rank)) { + inout->osize = in->osize; + inout->rank = in->rank; + } + in++; + inout++; + } +} + +int ncchkioi_calc_chunk_owner ( + NC_chk *ncchkp, NC_chk_var *varp, int nreq, MPI_Offset **starts, MPI_Offset **counts) { + return ncchkioi_calc_chunk_owner_reduce (ncchkp, varp, nreq, starts, counts); +} + +static inline void ncchkioi_rec_chunk_overlap (MPI_Offset *ostart, + MPI_Offset *osize, + MPI_Offset *citr, + NC_chk_var *varp, + MPI_Offset *ocnt, + NC_chk_req *reqp) { + int i; + int req; + int cid; // Chunk iterator + MPI_Offset overlapsize; + + for (req = 0; req < reqp->nreq; req++) { + ncchkioi_chunk_itr_init_ex (varp, reqp->starts[req], reqp->counts[req], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + if (cid < varp->nchunkrec) { // Count only first record + // Count overlap + overlapsize = 1; + for (i = 0; i < varp->ndim; i++) { overlapsize *= osize[i]; } + ocnt[cid] += (double)overlapsize; + if (ocnt[cid] > varp->chunksize) { ocnt[cid] = (double)varp->chunksize; } + } + } while (ncchkioi_chunk_itr_next_ex (varp, reqp->starts[req], reqp->counts[req], citr, &cid, + ostart, osize)); + } +} + +int ncchkioi_calc_chunk_overlap (NC_chk *ncchkp, + NC_chk_var *varp, + int nreq, + MPI_Offset **starts, + MPI_Offset **counts, + ncchkioi_chunk_overlap_t *ocnt) { + int err = NC_NOERR; + int i, j, k; + int cid; // Chunk iterator + int req; + MPI_Offset overlapsize; + MPI_Offset *ostart, *osize; + MPI_Offset *citr; // Bounding box for chunks overlapping my own write region + + ostart = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim * 3); + CHK_PTR (ostart) + osize = ostart + varp->ndim; + citr = osize + varp->ndim; + + memset (ocnt, 0, sizeof (ncchkioi_chunk_overlap_t) * varp->nchunkrec); + + // Count overlapsize of each request + if (varp->isrec) { + for (req = 0; req < nreq; req++) { + ncchkioi_chunk_itr_init_ex (varp, starts[req], counts[req], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + if (cid < varp->nchunkrec) { // Count only first record + // Count overlap + overlapsize = 1; + for (i = 0; i < varp->ndim; i++) { overlapsize *= osize[i]; } + ocnt[cid].osize += (double)overlapsize; + if (ocnt[cid].osize > varp->chunksize) { + ocnt[cid].osize = (double)varp->chunksize; + } + } + } while (ncchkioi_chunk_itr_next_ex (varp, starts[req], counts[req], citr, &cid, ostart, + osize)); + } + } else { + for (req = 0; req < nreq; req++) { + ncchkioi_chunk_itr_init_ex (varp, starts[req], counts[req], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Count overlap + overlapsize = 1; + for (i = 0; i < varp->ndim; i++) { overlapsize *= osize[i]; } + ocnt[cid].osize += overlapsize; + if (ocnt[cid].osize > varp->chunksize) { ocnt[cid].osize = varp->chunksize; } + } while (ncchkioi_chunk_itr_next_ex (varp, starts[req], counts[req], citr, &cid, ostart, + osize)); + } + } + + // First 16 bit used as noise + for (i = 0; i < varp->nchunkrec; i++) { + ocnt[i].rank = ncchkp->rank; + ocnt[i].osize *= varp->esize; + ocnt[i].osize <<= 16; + } + + // Noise to break tie + j = (ncchkp->rank - ncchkp->assigned_chunks) % ncchkp->np; + if (j < 0) j += ncchkp->np; + if (j > varp->nchunkrec) { j = varp->nchunkrec; } + k = ncchkp->np - 1; // noise from 0 ~ np-1 + for (i = j; i < varp->nchunkrec; i++) { + ocnt[i].osize += k; + k--; + if (k < 0) { k += ncchkp->np; } + } + for (i = 0; i < j; i++) { + ocnt[i].osize += k; + k--; + if (k < 0) { k += ncchkp->np; } + } + ncchkp->assigned_chunks += varp->nchunk; + +err_out:; + NCI_Free (ostart); + return err; +} + +void ncchkioi_assign_chunk_owner (NC_chk *ncchkp, + NC_chk_var *varp, + ncchkioi_chunk_overlap_t *ocnt) { + int i, j; + for (i = 0; i < varp->nchunkrec; i++) { varp->chunk_owner[i] = ocnt[i].rank; } + if (varp->isrec) { + for (i = varp->nchunkrec; i < varp->nchunk; i += varp->nchunkrec) { + memcpy (varp->chunk_owner + i, varp->chunk_owner, sizeof (int) * varp->nchunkrec); + } + } + + // Build skip list of my own chunks + if (varp->nchunk > 0) { + varp->nmychunkrec = 0; + for (j = 0; j < varp->nchunkrec; j++) { + if (varp->chunk_owner[j] == ncchkp->rank) { varp->nmychunkrec++; } + } + varp->nmychunk = varp->nmychunkrec * varp->nrec; + varp->mychunks = (int *)NCI_Realloc (varp->mychunks, sizeof (int) * varp->nmychunkrec * varp->nrecalloc); + varp->nmychunk = 0; + for (j = 0; j < varp->nchunk; j++) { + if (varp->chunk_owner[j] == ncchkp->rank) { + varp->mychunks[varp->nmychunk++] = j; + if (varp->isnew) { // Only apply to new var, old var will be read when it is + // needed + // varp->chunk_cache[j] = (void*)NCI_Malloc(varp->chunksize); // Allocate + // buffer for blocks we own + // memset(varp->chunk_cache[j], 0 , varp->chunksize); + } + } + } + } else { + varp->nmychunk = varp->nmychunkrec = 0; + varp->mychunks = NULL; + } + + // Update global chunk count + ncchkp->nmychunks += (MPI_Offset) (varp->nmychunk); + ncchkp->cown_size += + (MPI_Offset) ((double)((MPI_Offset) (varp->nmychunk) * (MPI_Offset) (varp->chunksize)) * + ncchkp->cown_ratio); +} + +int ncchkioi_sync_ocnt_reduce (NC_chk *ncchkp, + int nchunk, + ncchkioi_chunk_overlap_t *ocnt, + ncchkioi_chunk_overlap_t *ocnt_all, + MPI_Request *req) { + int err = NC_NOERR; + int i; + + // Construct MPI type for overlap if not already constructed + if (ncchkp->overlaptype == MPI_DATATYPE_NULL) { + err = MPI_Type_contiguous (sizeof (ncchkioi_chunk_overlap_t), MPI_BYTE, + &(ncchkp->overlaptype)); + CHK_MPIERR + err = MPI_Type_commit (&(ncchkp->overlaptype)); + CHK_MPIERR + } + + if (ncchkp->max_cown_op == MPI_OP_NULL) { + err = MPI_Op_create (max_osize_rank_op, 1, &(ncchkp->max_cown_op)); + CHK_MPIERR + } + + // Apply owner penalty + for (i = 0; i < nchunk; i++) { + ocnt[i].osize -= ncchkp->cown_size << 16; // Penality for load ballance, set at 1/16 + } + + if (req) { + CHK_ERR_IALLREDUCE (ocnt, ocnt_all, nchunk, ncchkp->overlaptype, ncchkp->max_cown_op, + ncchkp->comm, req); + } else { + CHK_ERR_ALLREDUCE (ocnt, ocnt_all, nchunk, ncchkp->overlaptype, ncchkp->max_cown_op, + ncchkp->comm); + } + +err_out:; + return err; +} + +int ncchkioi_sync_ocnt_gather (NC_chk *ncchkp, + int nchunk, + ncchkioi_chunk_overlap_t *ocnt, + MPI_Offset **ocnt_all, + MPI_Request *req) { + int err = NC_NOERR; + + // Construct MPI type for overlap if not already constructed + if (ncchkp->overlaptype == MPI_DATATYPE_NULL) { + MPI_Datatype tmptype; + + err = MPI_Type_contiguous (sizeof (MPI_Offset), MPI_BYTE, &tmptype); + CHK_MPIERR + err = MPI_Type_commit (&tmptype); + CHK_MPIERR + err = MPI_Type_create_resized (tmptype, 0, sizeof (ncchkioi_chunk_overlap_t), + &(ncchkp->overlaptype)); + CHK_MPIERR + err = MPI_Type_commit (&(ncchkp->overlaptype)); + CHK_MPIERR + err = MPI_Type_free (&tmptype); + } + + if (req) { + err = MPI_Igather (ocnt, nchunk, ncchkp->overlaptype, ocnt_all[0], nchunk, MPI_LONG_LONG, 0, + ncchkp->comm, req); + } else { + err = MPI_Gather (ocnt, nchunk, ncchkp->overlaptype, ocnt_all[0], nchunk, MPI_LONG_LONG, 0, + ncchkp->comm); + } + CHK_MPIERR + +err_out:; + return err; +} + +int ncchkioi_sync_ocnt_gather_bcast (NC_chk *ncchkp, + NC_chk_var *varp, + MPI_Offset **ocnt_in, + ncchkioi_chunk_overlap_t *ocnt_all, + MPI_Request *req) { + int err = NC_NOERR; + int i, j, k; + MPI_Offset *cown_size; + + if (ncchkp->rank == 0) { + cown_size = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * ncchkp->np); + memset (cown_size, 0, sizeof (MPI_Offset) * ncchkp->np); + for (i = 0; i < varp->nchunkrec; i++) { + ocnt_all[i].rank = 0; + ocnt_all[i].osize = ocnt_in[0][i]; + k = 0; + for (j = 1; j < ncchkp->np; j++) { + if (ocnt_in[j][i] - cown_size[j] > ocnt_in[k][i] - cown_size[k]) { k = j; } + } + cown_size[k] += + (MPI_Offset) ((double)(varp->chunksize) * ncchkp->cown_ratio) * varp->nrec; + ocnt_all[i].rank = k; + ocnt_all[i].osize = ocnt_in[i][k]; + } + } + + if (req) { + err = MPI_Ibcast (ocnt_all, varp->nchunkrec, ncchkp->overlaptype, 0, ncchkp->comm, req); + } else { + err = MPI_Bcast (ocnt_all, varp->nchunkrec, ncchkp->overlaptype, 0, ncchkp->comm); + } + CHK_MPIERR + +err_out:; + return err; +} + +int ncchkioi_calc_chunk_owner_reduce ( + NC_chk *ncchkp, NC_chk_var *varp, int nreq, MPI_Offset **starts, MPI_Offset **counts) { + int err = NC_NOERR; + int i, j, k; + int cid; // Chunk iterator + int req; + double noise, noise_step; + MPI_Offset overlapsize; + ncchkioi_chunk_overlap_t *ocnt, *ocnt_all; + + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_COWN) + + ocnt = (ncchkioi_chunk_overlap_t *)NCI_Malloc (sizeof (ncchkioi_chunk_overlap_t) * + varp->nchunkrec * 2); + CHK_PTR (ocnt) + ocnt_all = ocnt + varp->nchunkrec; + + err = ncchkioi_calc_chunk_overlap (ncchkp, varp, nreq, starts, counts, ocnt); + CHK_ERR + + if (ncchkp->exact_cown) { + // err = ncchkioi_sync_ocnt_gather (ncchkp, varp->nchunkrec, ocnt, ocnt_all, NULL); + // CHK_ERR + RET_ERR (NC_ENOTSUPPORT) + } else { + err = ncchkioi_sync_ocnt_reduce (ncchkp, varp->nchunkrec, ocnt, ocnt_all, NULL); + CHK_ERR + } + + ncchkioi_assign_chunk_owner (ncchkp, varp, ocnt_all); + + ncchkioi_write_chunk_ocnt (ncchkp, varp, ocnt, sizeof (ncchkioi_chunk_overlap_t)); + + NCI_Free (ocnt); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_COWN) + +err_out:; + return err; +} + +static inline int ncchkioi_reduce_max_csize_n ( + NC_chk *ncchkp, int nvar, NC_chk_var **varps, MPI_Offset **ocnts, int **cowns) { + int err = NC_NOERR; + int i, j, k, v; + int nchunk; + MPI_Offset **ocnts_all[2]; + MPI_Offset *cown_size; + MPI_Offset *ocnt, **ocnt_all; + int *cown; + NC_chk_var *varp; + MPI_Request req; + MPI_Request *bcast_reqs; + MPI_Status stat; + + bcast_reqs = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * nvar); + CHK_PTR (bcast_reqs) + + if (ncchkp->rank == 0) { + // Size owned by each process + cown_size = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * ncchkp->np); + CHK_PTR (cown_size) + memset (cown_size, 0, sizeof (MPI_Offset) * ncchkp->np); + + // Max #chunks across vars + nchunk = 0; + for (v = 0; v < nvar; v++) { + varp = varps[v]; + if (varp->nchunkrec > nchunk) { nchunk = varp->nchunkrec; } + } + // Allocate 2 set of ocnts_all + ocnts_all[0] = (MPI_Offset **)NCI_Malloc (sizeof (MPI_Offset *) * ncchkp->np * 2); + CHK_PTR (ocnts_all[0]) + ocnts_all[1] = ocnts_all[0] + ncchkp->np; + + ocnts_all[0][0] = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * nchunk * ncchkp->np * 2); + CHK_PTR (ocnts_all[0][0]) + ocnts_all[1][0] = ocnts_all[0][0] + nchunk * ncchkp->np; + for (i = 1; i < ncchkp->np; i++) { + ocnts_all[0][i] = ocnts_all[0][i - 1] + nchunk; + ocnts_all[1][i] = ocnts_all[1][i - 1] + nchunk; + } + + err = MPI_Igather (ocnt, varp->nchunkrec, MPI_LONG_LONG, ocnt_all, varp->nchunkrec, + MPI_LONG_LONG, 0, ncchkp->comm, &req); + CHK_ERR + + for (v = 0; v < nvar; v++) { + cown = cowns[v]; + varp = varps[v]; + ocnt = ocnts[v]; + ocnt_all = ocnts_all[v & 1]; + + // Wait for comm + err = MPI_Wait (&req, &stat); + CHK_ERR + + // Post comm for next var + if (v < nvar - 1) { + err = MPI_Igather (ocnts[v + 1], varps[v + 1]->nchunkrec, MPI_LONG_LONG, + ocnts_all[(v + 1) & 1], varps[v + 1]->nchunkrec, MPI_LONG_LONG, + 0, ncchkp->comm, &req); + CHK_ERR + } + + // Compute max rank for this var + memset (cown, 0, sizeof (int) * varp->nchunkrec); + for (i = 0; i < varp->nchunk; i++) { + k = 0; + for (j = 1; j < ncchkp->np; j++) { + if (ocnt_all[j][i] - cown_size[j] > ocnt_all[k][i] - cown_size[k]) { k = j; } + } + cown_size[k] += + (MPI_Offset) ((double)(varp->chunksize) * ncchkp->cown_ratio) * varp->nrec; + cown[i] = k; + } + + // Bcast result + err = MPI_Ibcast (cown, varp->nchunkrec, MPI_INT, 0, ncchkp->comm, bcast_reqs + v); + CHK_ERR + } + } else { + for (v = 0; v < nvar; v++) { + // Send to rank 0 + err = MPI_Gather (ocnts[v], varps[v]->nchunkrec, MPI_LONG_LONG, NULL, + varps[v]->nchunkrec, MPI_LONG_LONG, 0, ncchkp->comm); + CHK_ERR + // Recv result + err = MPI_Ibcast (cowns[v], varp->nchunkrec, MPI_INT, 0, ncchkp->comm, bcast_reqs + v); + CHK_ERR + } + } + + err = MPI_Waitall (nvar, bcast_reqs, MPI_STATUS_IGNORE); + CHK_ERR + + if (ncchkp->rank == 0) { + NCI_Free (cown_size); + NCI_Free (ocnts_all[0][0]); + NCI_Free (ocnts_all[0]); + } + NCI_Free (bcast_reqs); + +err_out:; + return err; +} + +int ncchkioi_calc_chunk_owner_gather ( + NC_chk *ncchkp, int nvar, NC_chk_var **varps, int nput, int *putreqs, int nget, int *getreqs) { + int err = NC_NOERR; + int i, j, k; + int cid; // Chunk iterator + int req; + int max_ndim; + int nchunks; + MPI_Offset overlapsize; + MPI_Offset *ostart, *osize; + MPI_Offset *citr; // Bounding box for chunks overlapping my own write region + MPI_Offset **ocnts; + int **cowns; + NC_chk_var *varp; + int *idmap; + NC_chk_req *reqp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_COWN) + + // Allocate buffer for overlappinp structure + // Box of single overlap + ostart = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * ncchkp->max_ndim * 3); + osize = ostart + ncchkp->max_ndim; + citr = osize + ncchkp->max_ndim; + // Calculate total number of chunks to assign + idmap = (int *)NCI_Malloc (sizeof (int) * ncchkp->vars.cnt); + nchunks = 0; + for (i = 0; i < nvar; i++) { + idmap[varps[i]->varid] = i; + nchunks += varps[i]->nchunkrec; + } + // Overlap count struct + ocnts = (MPI_Offset **)NCI_Malloc (sizeof (MPI_Offset *) * nvar); + ocnts[0] = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * nchunks); + cowns = (int **)NCI_Malloc (sizeof (int *) * nvar); + cowns[0] = varps[0]->chunk_owner; + for (i = 1; i < nvar; i++) { + ocnts[i] = ocnts[i - 1] + varps[i - 1]->nchunkrec; + cowns[i] = varps[i]->chunk_owner; + } + + // Count overlapsize for each request + memset (ocnts[0], 0, sizeof (ncchkioi_chunk_overlap_t) * nchunks); + for (i = 0; i < nput; i++) { + reqp = ncchkp->putlist.reqs + putreqs[i]; + ncchkioi_rec_chunk_overlap (ostart, osize, citr, ncchkp->vars.data + reqp->varid, + ocnts[idmap[reqp->varid]], reqp); + } + for (i = 0; i < nget; i++) { + reqp = ncchkp->getlist.reqs + getreqs[i]; + ncchkioi_rec_chunk_overlap (ostart, osize, citr, ncchkp->vars.data + reqp->varid, + ocnts[idmap[reqp->varid]], reqp); + } + + // Calculate the max rank + ncchkioi_reduce_max_csize_n (ncchkp, nvar, varps, ocnts, cowns); + + // Copy owner to other records + for (i = 0; i < nvar; i++) { + varp = varps[i]; + if (varp->isrec) { + for (j = varp->nchunkrec; j < varp->nchunk; j += varp->nchunkrec) { + memcpy (varp->chunk_owner + j, varp->chunk_owner, sizeof (int) * varp->nchunkrec); + } + } + ncchkioi_write_chunk_ocnt (ncchkp, varp, ocnts[i], sizeof (MPI_Offset)); + } + + NCI_Free (ostart); + NCI_Free (ocnts[0]); + NCI_Free (ocnts); + NCI_Free (cowns); + NCI_Free (idmap); + +err_out:; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_COWN) + + return err; +} \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkioi_chunk_size.c b/src/drivers/ncchunkio/ncchkioi_chunk_size.c new file mode 100644 index 000000000..c9479ee1d --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_chunk_size.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ncchkio_internal.h" + +MPI_Offset gcd (MPI_Offset a, MPI_Offset b) { + if (b) { + while ((a %= b) && (b %= a)) + ; + } + return a + b; +} + +void gcd_reduce (long long *in, long long *inout, int *len, MPI_Datatype *dptr) { + int i; + + for (i = 0; i < *len; i++) { + if (*inout) + while (((*in) %= (*inout)) && ((*inout) %= (*in))) + ; + (*inout) = (*inout) + (*in); + in++; + inout++; + } +} + +int smaller (const void *a, const void *b) { return (*(MPI_Offset *)b - *(MPI_Offset *)a); } + +int ncchkioi_calc_chunk_size ( + NC_chk *ncchkp, NC_chk_var *varp, int nreq, MPI_Offset **starts, MPI_Offset **counts) { + int err = NC_NOERR; + int r, i, j; + int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, + 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}; + MPI_Offset *chunkdim; + MPI_Offset **candidates; + MPI_Offset chunksize; + MPI_Offset ub, lb; + MPI_Op gcd_op; + + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_CSIZE) + + // Upper and lower bound of reasonable chunk size + ub = (MPI_Offset)INT_MAX; // Max chunk size supported + lb = 1; + for (i = 0; i < varp->ndim; i++) { lb *= varp->dimsize[i]; } + lb /= (MPI_Offset)INT_MAX; // Max # chunks supported + if (lb < varp->ndim * 3) { // Metadata should not exceed data + lb = varp->ndim * 3; + } + if (lb < 1024) { // At least 1 KiB for efficiency + lb = 1024; + } + + /* Infer chunk size by reqs + * Assume the application is doing blocked division + * If we set chunk dim to gcd of all access boundary, no communication required + * If the pattern is completely randomized, the result will likely be 1 + */ + chunkdim = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim); + if (nreq > 0) { + candidates = (MPI_Offset **)NCI_Malloc (sizeof (MPI_Offset *) * varp->ndim); + candidates[0] = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim * nreq); + for (i = 1; i < varp->ndim; i++) { candidates[i] = candidates[i - 1] + nreq; } + for (r = 0; r < nreq; r++) { + for (i = 0; i < varp->ndim; i++) { + candidates[i][r] = gcd (starts[r][i], counts[r][i]); + } + } + for (i = 0; i < varp->ndim; i++) { + qsort (candidates[i], nreq, sizeof (MPI_Offset), smaller); + chunkdim[i] = candidates[i][0]; + for (r = 1; r < nreq / 2; r++) { // Take the top 50% to drop out fragment writes + chunkdim[i] = gcd (chunkdim[i], candidates[i][r]); + } + } + } else { + for (i = 0; i < varp->ndim; i++) { + chunkdim[i] = 0; // We have no clue, listen to other processes + } + } + + // Global gcd + MPI_Op_create ((MPI_User_function *)gcd_reduce, 1, &gcd_op); + CHK_ERR_ALLREDUCE (MPI_IN_PLACE, chunkdim, varp->ndim, MPI_LONG_LONG, gcd_op, ncchkp->comm); + MPI_Op_free (&gcd_op); + + // If we have no clue accross processes, set chunk to max + for (i = 0; i < varp->ndim; i++) { + if (chunkdim[i] == 0) { chunkdim[i] = varp->dimsize[i]; } + } + + // At least 1 for rec dim + if (varp->isrec) { + if (chunkdim[0] == 0) { chunkdim[0] = 1; } + } + + // Check if chunk size is resonable (not too large or too small) + chunksize = 1; + for (i = 0; i < varp->ndim; i++) { chunksize *= chunkdim[i]; } + + // we only support chunk size up to INT_MAX + if (chunksize > ub) { + // Can we find perffect split using small prime numbers? + j = 0; + while ((j < 25) && (chunksize > ub)) { + r = 1; + for (i = 0; i < varp->ndim; i++) { // Spliting chunks along dims + if (chunkdim[i] % primes[j] == 0) { + chunkdim[i] /= primes[j]; + chunksize /= primes[j]; + r = 0; + } + } + if (r) { // No fit, try next prime + j++; + } + } + if (j >= 25) { // If not, we still need to split even we need to introduce communication + // overhead + for (i = 0; chunksize > ub; i++) { // Merging chunks + chunkdim[i % varp->ndim] /= 2; + chunksize /= 2; + } + } + } else if (chunksize < lb) { // Data smaller than metadata + int tmp; + int *heap; + int hsize; + + // Build heap of smallest chunk dim + heap = (int *)NCI_Malloc (sizeof (int) * varp->ndim); + for (i = 0; i < varp->ndim; i++) { + heap[i] = i; + j = i; + r = (j - 1) / 2; + while (j > 0 && chunkdim[heap[j]] < chunkdim[heap[r]]) { + tmp - heap[j]; + heap[j] = heap[r]; + heap[r] = tmp; + j = r; + r = (j - 1) / 2; + } + } + + hsize = varp->ndim; + while (chunksize < lb && hsize > 0) { + j = heap[0]; + if (chunkdim[j] * 2 <= varp->dimsize[j]) { // Merge chunk along smallest dim + chunkdim[j] *= 2; + chunksize *= 2; + } else { // Already reach var dim, remove from consideration + heap[0] = heap[--hsize]; + } + // Heapify + r = 0; + i = r * 2 + 1; + j = r * 2 + 2; + while (i < hsize) { + if ((j >= hsize) || (chunkdim[heap[i]] < chunkdim[heap[j]])) { + if (chunkdim[heap[i]] < chunkdim[heap[r]]) { + tmp = heap[r]; + heap[r] = heap[i]; + heap[i] = tmp; + r = i; + } else { + break; + } + } else { + if (chunkdim[heap[j]] < chunkdim[heap[r]]) { + tmp = heap[r]; + heap[r] = heap[j]; + heap[j] = tmp; + r = j; + } else { + break; + } + } + i = r * 2 + 1; + j = r * 2 + 2; + } + } + NCI_Free (heap); + + // Still not enough after doing everything, just set to entire var + if (chunksize < lb) { + memcpy (chunkdim, varp->dimsize, sizeof (MPI_Offset) * varp->ndim); + + // At least 1 for rec dim + if (varp->isrec) { + if (chunkdim[0] == 0) { chunkdim[0] = 1; } + } + } + } + + for (i = 0; i < varp->ndim; i++) { varp->chunkdim[i] = (int)chunkdim[i]; } + +err_out:; + + NCI_Free (chunkdim); + if (nreq > 0) { + NCI_Free (candidates[0]); + NCI_Free (candidates); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_CSIZE) + + return err; +} diff --git a/src/drivers/ncchunkio/ncchkioi_convert.c b/src/drivers/ncchunkio/ncchkioi_convert.c new file mode 100644 index 000000000..d7bb304bb --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_convert.c @@ -0,0 +1,939 @@ +/* Do not edit this file. It is produced from the corresponding .m4 source */ +/* + * Copyright (C) 2018, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include +#include +#include + +int ncchkioiconvert(void *inbuf, void *outbuf, MPI_Datatype intype, MPI_Datatype outtype, int N) { + int i; + + if (intype == MPI_BYTE){ + + if (outtype == MPI_BYTE) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_CHAR) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((signed char*)outbuf)[i] = (signed char)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((unsigned char*)outbuf)[i] = (unsigned char)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SHORT) { + for(i = 0; i < N; i++){ + ((short*)outbuf)[i] = (short)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_SHORT) { + for(i = 0; i < N; i++){ + ((unsigned short*)outbuf)[i] = (unsigned short)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_INT) { + for(i = 0; i < N; i++){ + ((int*)outbuf)[i] = (int)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED) { + for(i = 0; i < N; i++){ + ((unsigned int*)outbuf)[i] = (unsigned int)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_FLOAT) { + for(i = 0; i < N; i++){ + ((float*)outbuf)[i] = (float)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_DOUBLE) { + for(i = 0; i < N; i++){ + ((double*)outbuf)[i] = (double)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_LONG_LONG_INT) { + for(i = 0; i < N; i++){ + ((long long*)outbuf)[i] = (long long)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_LONG_LONG) { + for(i = 0; i < N; i++){ + ((unsigned long long*)outbuf)[i] = (unsigned long long)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } + if (intype == MPI_CHAR){ + + if (outtype == MPI_BYTE) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_CHAR) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((signed char*)outbuf)[i] = (signed char)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((unsigned char*)outbuf)[i] = (unsigned char)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SHORT) { + for(i = 0; i < N; i++){ + ((short*)outbuf)[i] = (short)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_SHORT) { + for(i = 0; i < N; i++){ + ((unsigned short*)outbuf)[i] = (unsigned short)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_INT) { + for(i = 0; i < N; i++){ + ((int*)outbuf)[i] = (int)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED) { + for(i = 0; i < N; i++){ + ((unsigned int*)outbuf)[i] = (unsigned int)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_FLOAT) { + for(i = 0; i < N; i++){ + ((float*)outbuf)[i] = (float)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_DOUBLE) { + for(i = 0; i < N; i++){ + ((double*)outbuf)[i] = (double)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_LONG_LONG_INT) { + for(i = 0; i < N; i++){ + ((long long*)outbuf)[i] = (long long)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_LONG_LONG) { + for(i = 0; i < N; i++){ + ((unsigned long long*)outbuf)[i] = (unsigned long long)(((char*)inbuf)[i]); + } + return NC_NOERR; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } + if (intype == MPI_SIGNED_CHAR){ + + if (outtype == MPI_BYTE) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((signed char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_CHAR) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((signed char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((signed char*)outbuf)[i] = (signed char)(((signed char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((unsigned char*)outbuf)[i] = (unsigned char)(((signed char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SHORT) { + for(i = 0; i < N; i++){ + ((short*)outbuf)[i] = (short)(((signed char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_SHORT) { + for(i = 0; i < N; i++){ + ((unsigned short*)outbuf)[i] = (unsigned short)(((signed char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_INT) { + for(i = 0; i < N; i++){ + ((int*)outbuf)[i] = (int)(((signed char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED) { + for(i = 0; i < N; i++){ + ((unsigned int*)outbuf)[i] = (unsigned int)(((signed char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_FLOAT) { + for(i = 0; i < N; i++){ + ((float*)outbuf)[i] = (float)(((signed char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_DOUBLE) { + for(i = 0; i < N; i++){ + ((double*)outbuf)[i] = (double)(((signed char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_LONG_LONG_INT) { + for(i = 0; i < N; i++){ + ((long long*)outbuf)[i] = (long long)(((signed char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_LONG_LONG) { + for(i = 0; i < N; i++){ + ((unsigned long long*)outbuf)[i] = (unsigned long long)(((signed char*)inbuf)[i]); + } + return NC_NOERR; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } + if (intype == MPI_UNSIGNED_CHAR){ + + if (outtype == MPI_BYTE) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((unsigned char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_CHAR) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((unsigned char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((signed char*)outbuf)[i] = (signed char)(((unsigned char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((unsigned char*)outbuf)[i] = (unsigned char)(((unsigned char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SHORT) { + for(i = 0; i < N; i++){ + ((short*)outbuf)[i] = (short)(((unsigned char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_SHORT) { + for(i = 0; i < N; i++){ + ((unsigned short*)outbuf)[i] = (unsigned short)(((unsigned char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_INT) { + for(i = 0; i < N; i++){ + ((int*)outbuf)[i] = (int)(((unsigned char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED) { + for(i = 0; i < N; i++){ + ((unsigned int*)outbuf)[i] = (unsigned int)(((unsigned char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_FLOAT) { + for(i = 0; i < N; i++){ + ((float*)outbuf)[i] = (float)(((unsigned char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_DOUBLE) { + for(i = 0; i < N; i++){ + ((double*)outbuf)[i] = (double)(((unsigned char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_LONG_LONG_INT) { + for(i = 0; i < N; i++){ + ((long long*)outbuf)[i] = (long long)(((unsigned char*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_LONG_LONG) { + for(i = 0; i < N; i++){ + ((unsigned long long*)outbuf)[i] = (unsigned long long)(((unsigned char*)inbuf)[i]); + } + return NC_NOERR; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } + if (intype == MPI_SHORT){ + + if (outtype == MPI_BYTE) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_CHAR) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((signed char*)outbuf)[i] = (signed char)(((short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((unsigned char*)outbuf)[i] = (unsigned char)(((short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SHORT) { + for(i = 0; i < N; i++){ + ((short*)outbuf)[i] = (short)(((short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_SHORT) { + for(i = 0; i < N; i++){ + ((unsigned short*)outbuf)[i] = (unsigned short)(((short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_INT) { + for(i = 0; i < N; i++){ + ((int*)outbuf)[i] = (int)(((short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED) { + for(i = 0; i < N; i++){ + ((unsigned int*)outbuf)[i] = (unsigned int)(((short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_FLOAT) { + for(i = 0; i < N; i++){ + ((float*)outbuf)[i] = (float)(((short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_DOUBLE) { + for(i = 0; i < N; i++){ + ((double*)outbuf)[i] = (double)(((short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_LONG_LONG_INT) { + for(i = 0; i < N; i++){ + ((long long*)outbuf)[i] = (long long)(((short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_LONG_LONG) { + for(i = 0; i < N; i++){ + ((unsigned long long*)outbuf)[i] = (unsigned long long)(((short*)inbuf)[i]); + } + return NC_NOERR; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } + if (intype == MPI_UNSIGNED_SHORT){ + + if (outtype == MPI_BYTE) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((unsigned short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_CHAR) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((unsigned short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((signed char*)outbuf)[i] = (signed char)(((unsigned short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((unsigned char*)outbuf)[i] = (unsigned char)(((unsigned short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SHORT) { + for(i = 0; i < N; i++){ + ((short*)outbuf)[i] = (short)(((unsigned short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_SHORT) { + for(i = 0; i < N; i++){ + ((unsigned short*)outbuf)[i] = (unsigned short)(((unsigned short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_INT) { + for(i = 0; i < N; i++){ + ((int*)outbuf)[i] = (int)(((unsigned short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED) { + for(i = 0; i < N; i++){ + ((unsigned int*)outbuf)[i] = (unsigned int)(((unsigned short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_FLOAT) { + for(i = 0; i < N; i++){ + ((float*)outbuf)[i] = (float)(((unsigned short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_DOUBLE) { + for(i = 0; i < N; i++){ + ((double*)outbuf)[i] = (double)(((unsigned short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_LONG_LONG_INT) { + for(i = 0; i < N; i++){ + ((long long*)outbuf)[i] = (long long)(((unsigned short*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_LONG_LONG) { + for(i = 0; i < N; i++){ + ((unsigned long long*)outbuf)[i] = (unsigned long long)(((unsigned short*)inbuf)[i]); + } + return NC_NOERR; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } + if (intype == MPI_INT){ + + if (outtype == MPI_BYTE) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_CHAR) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((signed char*)outbuf)[i] = (signed char)(((int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((unsigned char*)outbuf)[i] = (unsigned char)(((int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SHORT) { + for(i = 0; i < N; i++){ + ((short*)outbuf)[i] = (short)(((int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_SHORT) { + for(i = 0; i < N; i++){ + ((unsigned short*)outbuf)[i] = (unsigned short)(((int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_INT) { + for(i = 0; i < N; i++){ + ((int*)outbuf)[i] = (int)(((int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED) { + for(i = 0; i < N; i++){ + ((unsigned int*)outbuf)[i] = (unsigned int)(((int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_FLOAT) { + for(i = 0; i < N; i++){ + ((float*)outbuf)[i] = (float)(((int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_DOUBLE) { + for(i = 0; i < N; i++){ + ((double*)outbuf)[i] = (double)(((int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_LONG_LONG_INT) { + for(i = 0; i < N; i++){ + ((long long*)outbuf)[i] = (long long)(((int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_LONG_LONG) { + for(i = 0; i < N; i++){ + ((unsigned long long*)outbuf)[i] = (unsigned long long)(((int*)inbuf)[i]); + } + return NC_NOERR; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } + if (intype == MPI_UNSIGNED){ + + if (outtype == MPI_BYTE) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((unsigned int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_CHAR) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((unsigned int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((signed char*)outbuf)[i] = (signed char)(((unsigned int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((unsigned char*)outbuf)[i] = (unsigned char)(((unsigned int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SHORT) { + for(i = 0; i < N; i++){ + ((short*)outbuf)[i] = (short)(((unsigned int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_SHORT) { + for(i = 0; i < N; i++){ + ((unsigned short*)outbuf)[i] = (unsigned short)(((unsigned int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_INT) { + for(i = 0; i < N; i++){ + ((int*)outbuf)[i] = (int)(((unsigned int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED) { + for(i = 0; i < N; i++){ + ((unsigned int*)outbuf)[i] = (unsigned int)(((unsigned int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_FLOAT) { + for(i = 0; i < N; i++){ + ((float*)outbuf)[i] = (float)(((unsigned int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_DOUBLE) { + for(i = 0; i < N; i++){ + ((double*)outbuf)[i] = (double)(((unsigned int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_LONG_LONG_INT) { + for(i = 0; i < N; i++){ + ((long long*)outbuf)[i] = (long long)(((unsigned int*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_LONG_LONG) { + for(i = 0; i < N; i++){ + ((unsigned long long*)outbuf)[i] = (unsigned long long)(((unsigned int*)inbuf)[i]); + } + return NC_NOERR; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } + if (intype == MPI_FLOAT){ + + if (outtype == MPI_BYTE) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((float*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_CHAR) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((float*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((signed char*)outbuf)[i] = (signed char)(((float*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((unsigned char*)outbuf)[i] = (unsigned char)(((float*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SHORT) { + for(i = 0; i < N; i++){ + ((short*)outbuf)[i] = (short)(((float*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_SHORT) { + for(i = 0; i < N; i++){ + ((unsigned short*)outbuf)[i] = (unsigned short)(((float*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_INT) { + for(i = 0; i < N; i++){ + ((int*)outbuf)[i] = (int)(((float*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED) { + for(i = 0; i < N; i++){ + ((unsigned int*)outbuf)[i] = (unsigned int)(((float*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_FLOAT) { + for(i = 0; i < N; i++){ + ((float*)outbuf)[i] = (float)(((float*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_DOUBLE) { + for(i = 0; i < N; i++){ + ((double*)outbuf)[i] = (double)(((float*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_LONG_LONG_INT) { + for(i = 0; i < N; i++){ + ((long long*)outbuf)[i] = (long long)(((float*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_LONG_LONG) { + for(i = 0; i < N; i++){ + ((unsigned long long*)outbuf)[i] = (unsigned long long)(((float*)inbuf)[i]); + } + return NC_NOERR; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } + if (intype == MPI_DOUBLE){ + + if (outtype == MPI_BYTE) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((double*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_CHAR) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((double*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((signed char*)outbuf)[i] = (signed char)(((double*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((unsigned char*)outbuf)[i] = (unsigned char)(((double*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SHORT) { + for(i = 0; i < N; i++){ + ((short*)outbuf)[i] = (short)(((double*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_SHORT) { + for(i = 0; i < N; i++){ + ((unsigned short*)outbuf)[i] = (unsigned short)(((double*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_INT) { + for(i = 0; i < N; i++){ + ((int*)outbuf)[i] = (int)(((double*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED) { + for(i = 0; i < N; i++){ + ((unsigned int*)outbuf)[i] = (unsigned int)(((double*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_FLOAT) { + for(i = 0; i < N; i++){ + ((float*)outbuf)[i] = (float)(((double*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_DOUBLE) { + for(i = 0; i < N; i++){ + ((double*)outbuf)[i] = (double)(((double*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_LONG_LONG_INT) { + for(i = 0; i < N; i++){ + ((long long*)outbuf)[i] = (long long)(((double*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_LONG_LONG) { + for(i = 0; i < N; i++){ + ((unsigned long long*)outbuf)[i] = (unsigned long long)(((double*)inbuf)[i]); + } + return NC_NOERR; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } + if (intype == MPI_LONG_LONG_INT){ + + if (outtype == MPI_BYTE) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_CHAR) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((signed char*)outbuf)[i] = (signed char)(((long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((unsigned char*)outbuf)[i] = (unsigned char)(((long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SHORT) { + for(i = 0; i < N; i++){ + ((short*)outbuf)[i] = (short)(((long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_SHORT) { + for(i = 0; i < N; i++){ + ((unsigned short*)outbuf)[i] = (unsigned short)(((long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_INT) { + for(i = 0; i < N; i++){ + ((int*)outbuf)[i] = (int)(((long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED) { + for(i = 0; i < N; i++){ + ((unsigned int*)outbuf)[i] = (unsigned int)(((long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_FLOAT) { + for(i = 0; i < N; i++){ + ((float*)outbuf)[i] = (float)(((long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_DOUBLE) { + for(i = 0; i < N; i++){ + ((double*)outbuf)[i] = (double)(((long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_LONG_LONG_INT) { + for(i = 0; i < N; i++){ + ((long long*)outbuf)[i] = (long long)(((long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_LONG_LONG) { + for(i = 0; i < N; i++){ + ((unsigned long long*)outbuf)[i] = (unsigned long long)(((long long*)inbuf)[i]); + } + return NC_NOERR; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } + if (intype == MPI_UNSIGNED_LONG_LONG){ + + if (outtype == MPI_BYTE) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((unsigned long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_CHAR) { + for(i = 0; i < N; i++){ + ((char*)outbuf)[i] = (char)(((unsigned long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((signed char*)outbuf)[i] = (signed char)(((unsigned long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_CHAR) { + for(i = 0; i < N; i++){ + ((unsigned char*)outbuf)[i] = (unsigned char)(((unsigned long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_SHORT) { + for(i = 0; i < N; i++){ + ((short*)outbuf)[i] = (short)(((unsigned long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_SHORT) { + for(i = 0; i < N; i++){ + ((unsigned short*)outbuf)[i] = (unsigned short)(((unsigned long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_INT) { + for(i = 0; i < N; i++){ + ((int*)outbuf)[i] = (int)(((unsigned long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED) { + for(i = 0; i < N; i++){ + ((unsigned int*)outbuf)[i] = (unsigned int)(((unsigned long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_FLOAT) { + for(i = 0; i < N; i++){ + ((float*)outbuf)[i] = (float)(((unsigned long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_DOUBLE) { + for(i = 0; i < N; i++){ + ((double*)outbuf)[i] = (double)(((unsigned long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_LONG_LONG_INT) { + for(i = 0; i < N; i++){ + ((long long*)outbuf)[i] = (long long)(((unsigned long long*)inbuf)[i]); + } + return NC_NOERR; + } + if (outtype == MPI_UNSIGNED_LONG_LONG) { + for(i = 0; i < N; i++){ + ((unsigned long long*)outbuf)[i] = (unsigned long long)(((unsigned long long*)inbuf)[i]); + } + return NC_NOERR; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + + return NC_NOERR; +} \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkioi_convert.m4 b/src/drivers/ncchunkio/ncchkioi_convert.m4 new file mode 100644 index 000000000..8f2fd9bad --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_convert.m4 @@ -0,0 +1,79 @@ +dnl Process this m4 file to produce 'C' language file. +dnl +dnl If you see this line, you can ignore the next one. +/* Do not edit this file. It is produced from the corresponding .m4 source */ +dnl +/* + * Copyright (C) 2018, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ +dnl +include(`foreach.m4')dnl +include(`utils.m4')dnl +dnl +define(`upcase', `translit(`$*', `a-z', `A-Z')')dnl +dnl +define(`SWOUT',dnl +`dnl + if (outtype == $1) { + for(i = 0; i < N; i++){ + (($2*)outbuf)[i] = ($2)((($3*)inbuf)[i]); + } + return NC_NOERR; + } +')dnl +dnl +define(`SWIN',dnl +`dnl + if (intype == $1){ + +foreach(`dt', (`(`MPI_BYTE', `char')', dnl + `(`MPI_CHAR', `char')', dnl + `(`MPI_SIGNED_CHAR', `signed char')', dnl + `(`MPI_UNSIGNED_CHAR', `unsigned char')', dnl + `(`MPI_SHORT', `short')', dnl + `(`MPI_UNSIGNED_SHORT', `unsigned short')', dnl + `(`MPI_INT', `int')', dnl + `(`MPI_UNSIGNED', `unsigned int')', dnl + `(`MPI_FLOAT', `float')', dnl + `(`MPI_DOUBLE', `double')', dnl + `(`MPI_LONG_LONG_INT', `long long')', dnl + `(`MPI_UNSIGNED_LONG_LONG', `unsigned long long')', dnl + ), `SWOUT(translit(dt, `()'), $2)')dnl + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + } +')dnl +dnl +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include +#include +#include +#include + +int ncchkioiconvert(void *inbuf, void *outbuf, MPI_Datatype intype, MPI_Datatype outtype, int N) { + int i; + +foreach(`dt', (`(`MPI_BYTE', `char')', dnl + `(`MPI_CHAR', `char')', dnl + `(`MPI_SIGNED_CHAR', `signed char')', dnl + `(`MPI_UNSIGNED_CHAR', `unsigned char')', dnl + `(`MPI_SHORT', `short')', dnl + `(`MPI_UNSIGNED_SHORT', `unsigned short')', dnl + `(`MPI_INT', `int')', dnl + `(`MPI_UNSIGNED', `unsigned int')', dnl + `(`MPI_FLOAT', `float')', dnl + `(`MPI_DOUBLE', `double')', dnl + `(`MPI_LONG_LONG_INT', `long long')', dnl + `(`MPI_UNSIGNED_LONG_LONG', `unsigned long long')', dnl + ), `SWIN(translit(dt, `()'))')dnl + DEBUG_RETURN_ERROR(NC_EBADTYPE);; + + return NC_NOERR; +} \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkioi_get_var.c b/src/drivers/ncchunkio/ncchkioi_get_var.c new file mode 100644 index 000000000..5d9456247 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_get_var.c @@ -0,0 +1,879 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ncchkio_internal.h" + +int ncchkioi_get_var_cb_chunk (NC_chk *ncchkp, + NC_chk_var *varp, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + void *buf) { + int err = NC_NOERR; + int i, j, k; + int cid; // Chunk iterator + + MPI_Offset *ostart = NULL, *osize; + int *tsize = NULL, *tssize, *tstart, *tsizep, *tssizep, *tstartp; // Size for sub-array type + MPI_Offset *citr; // Chunk iterator + + int *rcnt_local = NULL, *rcnt_all = NULL; // Number of processes that writes to each chunk + + int overlapsize; // Size of overlaping region of request and chunk + char *cbuf = NULL; // Intermediate continuous buffer + + int packoff; // Pack offset + MPI_Datatype ptype; // Pack datatype + + int nread; // # chunks to read form file + int *rids = NULL; // Id of chunks to read from file + + int nsend, nrecv; // Number of send and receive + MPI_Request *sreqs = NULL, *rreqs = NULL; // Send and recv req + MPI_Status *sstats = NULL, *rstats = NULL; // Send and recv status + char **sbufs = NULL, **rbufs = NULL; // Send and recv buffer + int *rsizes = NULL; // recv size of each message + MPI_Message rmsg; // Receive message + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_INIT) + + // Allocate buffering for write count + rcnt_local = (int *)NCI_Malloc (sizeof (int) * varp->nchunk * 2); + rcnt_all = rcnt_local + varp->nchunk; + + // Allocate buffering for overlaping index + tsize = (int *)NCI_Malloc (sizeof (int) * varp->ndim * 3); + tssize = tsize + varp->ndim; + tstart = tssize + varp->ndim; + ostart = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim * 3); + osize = ostart + varp->ndim; + + // Chunk iterator + citr = osize + varp->ndim; + + // We need to calculate the size of message of each chunk + // This is just for allocating send buffer + // We do so by iterating through all request and all chunks they cover + // If we are not the owner of a chunk, we need to send message + memset (rcnt_local, 0, sizeof (int) * varp->nchunk); + nsend = 0; + + // Iterate through chunks + ncchkioi_chunk_itr_init (varp, start, count, citr, &cid); + do { + rcnt_local[cid] = 1; + + if (varp->chunk_owner[cid] != ncchkp->rank) { + // Count number of mnessage we need to send + nsend++; + } + } while (ncchkioi_chunk_itr_next (varp, start, count, citr, &cid)); + + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET_CB_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SYNC) + + // Sync number of messages of each chunk + CHK_ERR_ALLREDUCE (rcnt_local, rcnt_all, varp->nchunk, MPI_INT, MPI_SUM, ncchkp->comm); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SYNC) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_IO_INIT) + + // We need to prepare chunk in the chunk cache + // For chunks not yet allocated, we need to read them form file collectively + // We collect chunk id of those chunks + // Calculate number of recv request + // This is for all the chunks + rids = (int *)NCI_Malloc (sizeof (int) * varp->nmychunk); + nread = 0; + nrecv = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + // We don't need message for our own data + nrecv += rcnt_all[cid] - rcnt_local[cid]; + // Count number of chunks we need to prepare + // We read only chunks that is required + + if (rcnt_all[cid] || rcnt_local[cid]) { + if (varp->chunk_cache[cid] == NULL) { + // err = ncchkioi_cache_alloc(ncchkp, varp->chunksize, varp->chunk_cache + cid); + if (varp->chunk_index[cid].len > 0) { rids[nread++] = cid; } + } else { + // ncchkioi_cache_visit(ncchkp, varp->chunk_cache[cid]); + } + } + } + + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET_CB) // I/O time count separately + +#ifdef PNETCDF_PROFILING + MPI_Barrier (ncchkp->comm); +#endif + // Decompress chunks into chunk cache + err = ncchkioi_load_var (ncchkp, varp, nread, rids); + CHK_ERR + // Increase batch number to indicate allocated chunk buffer can be freed for future allocation + (ncchkp->cache_serial)++; + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB) + + // Allocate buffer for send and recv + // We need to accept nrecv requests and receive nsend of replies + rreqs = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * (nrecv + nsend)); + CHK_PTR (rreqs) + rstats = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * (nrecv + nsend)); + CHK_PTR (rstats) + rbufs = (char **)NCI_Malloc (sizeof (char *) * (nrecv + nsend)); + CHK_PTR (rbufs) + rsizes = (int *)NCI_Malloc (sizeof (int) * (nrecv + nsend)); + CHK_PTR (rsizes) + // We need to send nsend requests and reply nrecv of requests + sbufs = (char **)NCI_Malloc (sizeof (char *) * (nrecv + nsend)); + CHK_PTR (sbufs) + sreqs = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * (nrecv + nsend)); + CHK_PTR (sreqs) + sstats = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * (nrecv + nsend)); + CHK_PTR (sstats) + + // Post send + k = 0; + // Initialize chunk iterator + ncchkioi_chunk_itr_init_ex (varp, start, count, citr, &cid, ostart, osize); + // Iterate through chunks + do { + // We got something to send if we are not owner + if (varp->chunk_owner[cid] != ncchkp->rank) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_PACK_REQ) + + // Calculate chunk overlap + overlapsize = varp->esize; + for (j = 0; j < varp->ndim; j++) { overlapsize *= osize[j]; } + + // Allocate buffer + sbufs[k] = (char *)NCI_Malloc (sizeof (int) * varp->ndim * 2); // For request + CHK_PTR (sbufs[k]) + rbufs[k + nrecv] = + (char *)NCI_Malloc (overlapsize); // For reply, first nrecv are for request + CHK_PTR (rbufs[k + nrecv]) + + // Metadata + tstartp = (int *)sbufs[k]; + packoff = varp->ndim * sizeof (int); + tsizep = (int *)(sbufs[k] + packoff); + packoff += varp->ndim * sizeof (int); + for (j = 0; j < varp->ndim; j++) { + tstartp[j] = (int)(ostart[j] - citr[j]); + tsizep[j] = (int)osize[j]; + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_PACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Send request + CHK_ERR_ISEND (sbufs[k], packoff, MPI_BYTE, varp->chunk_owner[cid], cid, ncchkp->comm, + sreqs + k); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REP) + + // Post recv reply + CHK_ERR_IRECV (rbufs[k + nrecv], overlapsize, MPI_BYTE, varp->chunk_owner[cid], + cid + 1024, ncchkp->comm, rreqs + nrecv + k); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REP) + + k++; + } + } while (ncchkioi_chunk_itr_next_ex (varp, start, count, citr, &cid, ostart, osize)); + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // Post recv + k = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + // We are the owner of the chunk + // Receive data from other process + for (j = 0; j < rcnt_all[cid] - rcnt_local[cid]; j++) { + // Get message size, including metadata + CHK_ERR_MPROBE (MPI_ANY_SOURCE, cid, ncchkp->comm, &rmsg, rstats); + CHK_ERR_GET_COUNT (rstats, MPI_BYTE, rsizes + k); + + // Allocate buffer + rbufs[k] = (char *)NCI_Malloc (rsizes[k]); + CHK_PTR (rbufs[k]) + + // Post irecv + CHK_ERR_IMRECV (rbufs[k], rsizes[k], MPI_BYTE, &rmsg, rreqs + k); + k++; + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // Allocate intermediate buffer + cbuf = (char *)NCI_Malloc (varp->chunksize); + CHK_PTR (cbuf) + + // For each chunk we own, we need to receive incoming data + k = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SELF) + + // Handle our own data first if we have any + if (rcnt_local[cid] > 0) { + // Convert chunk id to iterator + get_chunk_itr (varp, cid, citr); + + // Calculate overlapping region + get_chunk_overlap (varp, citr, start, count, ostart, osize); + + // Pack type from chunk buffer to (contiguous) intermediate buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - citr[j]); + tsize[j] = varp->chunkdim[j]; + tssize[j] = (int)osize[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data into intermediate buffer + packoff = 0; + CHK_ERR_PACK (varp->chunk_cache[cid]->buf, 1, ptype, cbuf, varp->chunksize, &packoff, + ncchkp->comm); + overlapsize = packoff; + MPI_Type_free (&ptype); + + // Pack type from (contiguous) intermediate buffer to user buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - start[j]); + tsize[j] = (int)count[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data into user buffer + packoff = 0; + CHK_ERR_UNPACK (cbuf, overlapsize, &packoff, buf, 1, ptype, ncchkp->comm); + MPI_Type_free (&ptype); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SELF) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // Wait for all send requests related to this chunk + // We remove the impact of -1 mark in rcnt_local[cid] + // printf("Rank: %d, CHK_ERR_WAITALL_recv(%d, %d)\n", ncchkp->rank, rcnt_all[cid] - + // rcnt_local[cid], k); fflush(stdout); + CHK_ERR_WAITALL (rcnt_all[cid] - rcnt_local[cid], rreqs + k, rstats + k); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // Now, it is time to process data from other processes + for (j = 0; j < varp->ndim; j++) { tsize[j] = varp->chunkdim[j]; } + + // Process data received + // printf("nrecv = %d, rcnt_all = %d, rcnt_local = %d\n", nrecv, rcnt_all[cid], + // rcnt_local[cid]); fflush(stdout); + for (j = k; j < k + rcnt_all[cid] - rcnt_local[cid]; j++) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_UNPACK_REQ) + + // Metadata + tstartp = (int *)rbufs[j]; + packoff = varp->ndim * sizeof (int); + tssizep = (int *)(rbufs[j] + packoff); + packoff += varp->ndim * sizeof (int); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_UNPACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_PACK_REP) + + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssizep, tstartp, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Allocate buffer + MPI_Type_size (ptype, &overlapsize); + sbufs[j + nsend] = (char *)NCI_Malloc (overlapsize); // For reply + + // Data + packoff = 0; + CHK_ERR_PACK (varp->chunk_cache[cid]->buf, 1, ptype, sbufs[j + nsend], overlapsize, + &packoff, ncchkp->comm); + MPI_Type_free (&ptype); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_PACK_REP) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REP) + + // Send reply + CHK_ERR_ISEND (sbufs[j + nsend], packoff, MPI_BYTE, rstats[j].MPI_SOURCE, cid + 1024, + ncchkp->comm, sreqs + j + nsend); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REP) + } + k += rcnt_all[cid] - rcnt_local[cid]; + + // princbuf(ncchkp->rank, varp->chunk_cache[cid], varp->chunksize); + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Wait for all send request + // printf("Rank: %d, CHK_ERR_WAITALL_send(%d, %d)\n", ncchkp->rank, nsend, 0); fflush(stdout); + CHK_ERR_WAITALL (nsend, sreqs, sstats); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Receive replies from the owners and update the user buffer + k = 0; + // Initialize chunk iterator + ncchkioi_chunk_itr_init_ex (varp, start, count, citr, &cid, ostart, osize); + // Iterate through chunks + do { + // We got something to recv if we are not owner + if (varp->chunk_owner[cid] != ncchkp->rank) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_UNPACK_REP) + + // Pack type from recv buffer to user buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - start[j]); + tsize[j] = (int)count[j]; + tssize[j] = (int)osize[j]; + } + // printf("Rank: %d, ostart=[%lld, %lld], osize=[%lld, %lld]\n", ncchkp->rank, + // ostart[0], ostart[1], osize[0], osize[1]); fflush(stdout); printf("Rank: %d, + // CHK_ERR_TYPE_CREATE_SUBARRAY4([%d, %d], [%d, %d], [%d, %d]\n", ncchkp->rank, + // tsize[0], tsize[1], tssize[0], tssize[1], tstart[0], tstart[1]); fflush(stdout); + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + // printf("Rank: %d, commit\n", ncchkp->rank); fflush(stdout); + CHK_ERR_TYPE_COMMIT (&ptype); + MPI_Type_size (ptype, &overlapsize); + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REP) + + // printf("Rank: %d, wait recv, nrecv = %d, k = %d, nsend = %d\n", ncchkp->rank, nrecv, + // k, nsend); fflush(stdout); + // Wait for reply + // printf("Rank: %d, MPI_Wait_recv(%d)\n", ncchkp->rank, nrecv + k); fflush(stdout); + MPI_Wait (rreqs + nrecv + k, rstats + nrecv + k); + + NC_CHK_TIMER_STOPEX (NC_CHK_TIMER_GET_CB_RECV_REP, NC_CHK_TIMER_GET_CB_UNPACK_REP) + + // Pack data + // printf("Rank: %d, pack\n", ncchkp->rank); fflush(stdout); + packoff = 0; + CHK_ERR_UNPACK (rbufs[nrecv + k], overlapsize, &packoff, buf, 1, ptype, ncchkp->comm); + MPI_Type_free (&ptype); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_UNPACK_REP) + + k++; + } + } while (ncchkioi_chunk_itr_next_ex (varp, start, count, citr, &cid, ostart, osize)); + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REP) + + // printf("Rank: %d, wait_final\n", ncchkp->rank); fflush(stdout); + // Wait for all send replies + // printf("Rank: %d, CHK_ERR_WAITALL_send(%d, %d)\n", ncchkp->rank, nrecv, nsend); + // fflush(stdout); + CHK_ERR_WAITALL (nrecv, sreqs + nsend, sstats + nsend); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REP) + + // printf("Rank: %d, exiting\n", ncchkp->rank); fflush(stdout); + +err_out:; + + // Free buffers + NCI_Free (rcnt_local); + + NCI_Free (rids); + + NCI_Free (tsize); + + NCI_Free (ostart); + + for (i = 0; i < nsend + nrecv; i++) { + NCI_Free (sbufs[i]); + NCI_Free (rbufs[i]); + } + NCI_Free (sreqs); + NCI_Free (sstats); + NCI_Free (sbufs); + NCI_Free (rreqs); + NCI_Free (rstats); + NCI_Free (rbufs); + NCI_Free (rsizes); + + if (cbuf != NULL) { NCI_Free (cbuf); } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REP) + + return err; +} + +int ncchkioi_get_var_cb_proc (NC_chk *ncchkp, + NC_chk_var *varp, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + void *buf) { + int err = NC_NOERR; + int i, j, k; + int cid, cown; // Chunk iterator + + MPI_Offset *ostart= NULL , *osize; + int *tsize = NULL, *tssize, *tstart, *tssizep, *tstartp; // Size for sub-array type + MPI_Offset *citr; // Chunk iterator + + int *rcnt_local = NULL, *rcnt_all; // Number of processes that writes to each proc + + int rrange_local[2], rrange_all[2]; // Number of processes that writes to each chunk + + int overlapsize; // Size of overlaping region of request and chunk + int max_tbuf = 0; // Size of intermediate buffer + char *tbuf = NULL; // Intermediate buffer + + int packoff; // Pack offset + MPI_Datatype ptype; // Pack datatype + + int nread; // # chunks to read form file + int *rids = NULL; // Id of chunks to read from file + + int nsend, nrecv; // Number of send and receive + MPI_Request *sreq = NULL, *rreq, *sreq_re, *rreq_re; // Send and recv req + MPI_Status *sstat = NULL, rstat, *sstat_re; // Send and recv status + char **sbuf = NULL, **rbuf, **sbufp, **rbufp, **sbuf_re, **rbuf_re; // Send and recv buffer + int *rsize, *ssize = NULL, *rsize_re, *ssize_re; // recv size of each message + int *sdst = NULL; // recv size of each message + int *smap = NULL; + MPI_Message rmsg; // Receive message + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_INIT) + + // Allocate buffering for write count + rcnt_local = (int *)NCI_Malloc (sizeof (int) * (ncchkp->np * 2 + varp->nchunk * 1)); + CHK_PTR(rcnt_local) + rcnt_all = rcnt_local + ncchkp->np; + smap = rcnt_all + ncchkp->np; + + // Allocate buffering for overlaping index + tsize = (int *)NCI_Malloc (sizeof (int) * varp->ndim * 3); + CHK_PTR(tsize) + tssize = tsize + varp->ndim; + tstart = tssize + varp->ndim; + ostart = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim * 3); + CHK_PTR(ostart) + osize = ostart + varp->ndim; + + // Chunk iterator + citr = osize + varp->ndim; + + // We need to calculate the size of message of each chunk + // This is just for allocating send buffer + // We do so by iterating through all request and all chunks they cover + // If we are not the owner of a chunk, we need to send message + memset (rcnt_local, 0, sizeof (int) * (ncchkp->np + varp->nchunk)); + nsend = 0; + + // Count total number of messages and build a map of accessed chunk to list of comm + // datastructure + rrange_local[0] = varp->nchunk; + rrange_local[1] = 0; + ncchkioi_chunk_itr_init (varp, start, count, citr, &cid); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + + // Mapping to skip list of send requests + if (rcnt_local[cown] == 0 && cown != ncchkp->rank) { smap[cown] = nsend++; } + rcnt_local[cown] = 1; // Need to send message if not owner + + // Record lowest and highest chunk accessed + if (rrange_local[0] > cid) { rrange_local[0] = cid; } + if (rrange_local[1] < cid) { rrange_local[1] = cid; } + } while (ncchkioi_chunk_itr_next (varp, start, count, citr, &cid)); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SYNC) + + // Sync number of messages of each chunk and access range + CHK_ERR_ALLREDUCE (rcnt_local, rcnt_all, ncchkp->np, MPI_INT, MPI_SUM, ncchkp->comm); + nrecv = rcnt_all[ncchkp->rank] - + rcnt_local[ncchkp->rank]; // We don't need to receive request form self + + rrange_local[1] *= -1; + CHK_ERR_ALLREDUCE (rrange_local, rrange_all, 2, MPI_INT, MPI_MIN, ncchkp->comm); + rrange_all[1] *= -1; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SYNC) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_PACK_REQ) + + // Allocate data structure for messaging + sbuf = (char **)NCI_Malloc (sizeof (char *) * (2 * nsend + nrecv)); + CHK_PTR (sbuf) + ssize = (int *)NCI_Malloc (sizeof (int) * (nsend * 2 + nrecv * 1)); + CHK_PTR (ssize) + sdst = ssize + (nsend + nrecv); + sreq = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * (nsend + nrecv)); + CHK_PTR (sreq) + sstat = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * (nsend + nrecv)); + CHK_PTR (sstat) + + rbuf = (char **)NCI_Malloc (sizeof (char *) * (nsend + nrecv * 2)); + CHK_PTR (rbuf) + rsize = (int *)NCI_Malloc (sizeof (int) * (nsend + nrecv)); + CHK_PTR (rsize) + rreq = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * (nsend + nrecv)); + CHK_PTR (rreq) + + sbuf_re = sbuf + nsend; + sbufp = sbuf_re + nrecv; + ssize_re = ssize + nsend; + sreq_re = sreq + nsend; + sstat_re = sstat + nsend; + + rbuf_re = rbuf + nrecv; + rbufp = rbuf_re + nsend; + rsize_re = rsize + nrecv; + rreq_re = rreq + nrecv; + + // Count size of each request + memset (ssize, 0, sizeof (int) * nsend); + memset (rsize_re, 0, sizeof (int) * nsend); + ncchkioi_chunk_itr_init_ex (varp, start, count, citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + if (cown != ncchkp->rank) { + j = smap[cown]; + sdst[j] = cown; // Record a reverse map by the way + + // Count overlap + overlapsize = varp->esize; + for (i = 0; i < varp->ndim; i++) { overlapsize *= osize[i]; } + ssize[j] += sizeof (int) * (varp->ndim * 2 + 1); + rsize_re[j] += overlapsize; + } + } while (ncchkioi_chunk_itr_next_ex (varp, start, count, citr, &cid, ostart, osize)); + + // Allocate buffer for send + for (i = 0; i < nsend; i++) { + ssize[i] += sizeof (int); + sbuf[i] = sbufp[i] = (char *)NCI_Malloc (ssize[i]); + CHK_PTR (sbuf[i]) + *((int *)sbufp[i]) = rsize_re[i]; + sbufp[i] += sizeof (int); + rbuf_re[i] = (char *)NCI_Malloc (rsize_re[i]); + CHK_PTR (rbuf_re[i]) + } + + // Pack requests + ncchkioi_chunk_itr_init_ex (varp, start, count, citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + if (cown != ncchkp->rank) { + j = smap[cown]; + + // Metadata + *((int *)sbufp[j]) = cid; + sbufp[j] += sizeof (int); + tstartp = (int *)sbufp[j]; + sbufp[j] += sizeof (int) * varp->ndim; + tssizep = (int *)sbufp[j]; + sbufp[j] += sizeof (int) * varp->ndim; + for (i = 0; i < varp->ndim; i++) { + tstartp[i] = (int)(ostart[i] - citr[i]); + tssizep[i] = (int)osize[i]; + } + } + } while (ncchkioi_chunk_itr_next_ex (varp, start, count, citr, &cid, ostart, osize)); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_PACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Post send + for (i = 0; i < nsend; i++) { + CHK_ERR_ISEND (sbuf[i], ssize[i], MPI_BYTE, sdst[i], 0, ncchkp->comm, sreq + i); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REP) + + // Post receive + for (i = 0; i < nsend; i++) { + CHK_ERR_IRECV (rbuf_re[i], rsize_re[i], MPI_BYTE, sdst[i], 1, ncchkp->comm, rreq_re + i); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REP) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // Post recv + for (i = 0; i < nrecv; i++) { + // Get message size, including metadata + CHK_ERR_MPROBE (MPI_ANY_SOURCE, 0, ncchkp->comm, &rmsg, &rstat); + CHK_ERR_GET_COUNT (&rstat, MPI_BYTE, rsize + i); + + // Allocate buffer + rbuf[i] = rbufp[i] = (char *)NCI_Malloc (rsize[i]); + CHK_PTR (rbuf[i]) + + // Post irecv + CHK_ERR_IMRECV (rbuf[i], rsize[i], MPI_BYTE, &rmsg, rreq + i); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REQ) + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_IO_INIT) + + // We need to prepare chunk in the chunk cache + // For chunks not yet allocated, we need to read them from file collectively + // We collect chunk id of those chunks + // Calculate number of recv request + // This is for all the chunks + for (j = 0; j < varp->nmychunk && varp->mychunks[j] < rrange_all[0]; j++) + ; + for (k = j; k < varp->nmychunk && varp->mychunks[k] <= rrange_all[1]; k++) + ; + rids = (int *)NCI_Malloc (sizeof (int) * (k - j)); + nread = 0; + for (i = j; i < k; i++) { + cid = varp->mychunks[i]; + printf("checking chunk %d, size is %d\n",cid, varp->chunk_index[cid].len); + if (varp->chunk_cache[cid] == NULL) { + // err = ncchkioi_cache_alloc(ncchkp, varp->chunksize, varp->chunk_cache + cid); + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + if (varp->chunk_index[cid].len > 0) { rids[nread++] = cid; printf("chunk %d need read\n",cid);} + } else { + // ncchkioi_cache_visit(ncchkp, varp->chunk_cache[cid]); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_IO_INIT) + + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET_CB) // I/O time count separately + +#ifdef PNETCDF_PROFILING + MPI_Barrier (ncchkp->comm); +#endif + // Decompress chunks into chunk cache + err = ncchkioi_load_var (ncchkp, varp, nread, rids); + CHK_ERR + // Increase batch number to indicate allocated chunk buffer can be freed for future allocation + (ncchkp->cache_serial)++; + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB) + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SELF) + + tbuf = (char *)NCI_Malloc (varp->chunksize); + + // Handle our own data + ncchkioi_chunk_itr_init_ex (varp, start, count, citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + if (varp->chunk_owner[cid] == ncchkp->rank) { + // Pack type from chunk cache to (contiguous) intermediate buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - citr[j]); + tsize[j] = varp->chunkdim[j]; + tssize[j] = (int)osize[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data into intermediate buffer + packoff = 0; + CHK_ERR_PACK (varp->chunk_cache[cid]->buf, 1, ptype, tbuf, varp->chunksize, &packoff, + ncchkp->comm); + MPI_Type_free (&ptype); + overlapsize = packoff; + + // Pack type from (contiguous) intermediate buffer to chunk buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - start[j]); + tsize[j] = (int)count[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Unpack data into chunk buffer + packoff = 0; + CHK_ERR_UNPACK (tbuf, overlapsize, &packoff, buf, 1, ptype, ncchkp->comm); + MPI_Type_free (&ptype); + } + } while (ncchkioi_chunk_itr_next_ex (varp, start, count, citr, &cid, ostart, osize)); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SELF) + + // Handle incoming requests + for (i = 0; i < varp->ndim; i++) { tsize[i] = varp->chunkdim[i]; } + for (i = 0; i < nrecv; i++) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // Will wait any provide any benefit? + MPI_Waitany (nrecv, rreq, &j, &rstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REQ) + + packoff = 0; + ssize_re[j] = *((int *)rbufp[j]); + rbufp[j] += sizeof (int); + sbuf_re[j] = (char *)NCI_Malloc (ssize_re[j]); + CHK_PTR (sbuf_re[j]) + while (rbufp[j] < rbuf[j] + rsize[j]) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_UNPACK_REQ) + + // Metadata + cid = *((int *)rbufp[j]); + rbufp[j] += sizeof (int); + tstartp = (int *)rbufp[j]; + rbufp[j] += sizeof (int) * varp->ndim; + tssizep = (int *)rbufp[j]; + rbufp[j] += sizeof (int) * varp->ndim; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_UNPACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_PACK_REP) + + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssizep, tstartp, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Data + CHK_ERR_PACK (varp->chunk_cache[cid]->buf, 1, ptype, sbuf_re[j], ssize_re[j], &packoff, + ncchkp->comm); + MPI_Type_free (&ptype); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_PACK_REP) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Send Response + CHK_ERR_ISEND (sbuf_re[j], packoff, MPI_BYTE, rstat.MPI_SOURCE, 1, ncchkp->comm, + sreq_re + j); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REQ) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Wait for all request + CHK_ERR_WAITALL (nsend, sreq, sstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Handle reply + for (i = 0; i < varp->ndim; i++) { tsize[i] = count[i]; } + for (i = 0; i < nsend; i++) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REP) + + // Will wait any provide any benefit? + MPI_Waitany (nsend, rreq_re, &j, &rstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REP) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_UNPACK_REP) + + sbufp[j] = sbuf[j] + sizeof (int); // Skip reply size + packoff = 0; + while (packoff < rsize_re[j]) { + // Retrieve metadata from the request we sent + cid = *((int *)sbufp[j]); + sbufp[j] += sizeof (int); + tstartp = (int *)sbufp[j]; + sbufp[j] += sizeof (int) * varp->ndim; + tssizep = (int *)sbufp[j]; + sbufp[j] += sizeof (int) * varp->ndim; + + // Bring back the request + get_chunk_itr (varp, cid, citr); + for (k = 0; k < varp->ndim; k++) { tstartp[k] += (int)(citr[k] - start[k]); } + + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssizep, tstartp, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data + CHK_ERR_UNPACK (rbuf_re[j], rsize_re[j], &packoff, buf, 1, ptype, ncchkp->comm); + MPI_Type_free (&ptype); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_UNPACK_REP) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REP) + + // Wait for all Response + CHK_ERR_WAITALL (nrecv, sreq_re, sstat_re); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REP) + +err_out:; + + // Free buffers + NCI_Free (rcnt_local); + + NCI_Free (rids); + + NCI_Free (tsize); + + NCI_Free (ostart); + + NCI_Free (sreq); + NCI_Free (sstat); + NCI_Free (ssize); + for (i = 0; i < nsend + nrecv; i++) { + NCI_Free (sbuf[i]); + NCI_Free (rbuf[i]); + } + NCI_Free (sbuf); + + NCI_Free (rreq); + NCI_Free (rbuf); + NCI_Free (rsize); + + if (tbuf != NULL) { NCI_Free (tbuf); } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB) + + return err; +} diff --git a/src/drivers/ncchunkio/ncchkioi_get_varn.c b/src/drivers/ncchunkio/ncchkioi_get_varn.c new file mode 100644 index 000000000..04b30b409 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_get_varn.c @@ -0,0 +1,943 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ncchkio_internal.h" + +int ncchkioi_get_varn_cb_chunk (NC_chk *ncchkp, + NC_chk_var *varp, + int nreq, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + MPI_Offset *const *strides, + void **bufs) { + int err = NC_NOERR; + int i, j, k, l; + int cid, req; // Chunk iterator + + MPI_Offset *ostart, *osize; + int *tsize, *tssize, *tstart, *tsizep, *tssizep, *tstartp; // Size for sub-array type + MPI_Offset *citr; // Chunk iterator + + int *rcnt_local, *rcnt_all; // Number of processes that writes to each chunk + + int overlapsize; // Size of overlaping region of request and chunk + int overlapsize_total, overlapcnt; + char *cbuf = NULL; // Intermediate continuous buffer + + int packoff, unpackoff; // Pack offset + MPI_Datatype ptype; // Pack datatype + + int nread; // # chunks to read form file + int *rids; // Id of chunks to read from file + + int nsend, nrecv; // Number of send and receive + MPI_Request *sreqs, *rreqs; // Send and recv req + MPI_Status *sstats, *rstats; // Send and recv status + char **sbufs, **rbufs; // Send and recv buffer + int *rsizes; // recv size of each message + MPI_Message rmsg; // Receive message + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_INIT) + + // Allocate buffering for write count + rcnt_local = (int *)NCI_Malloc (sizeof (int) * varp->nchunk * 2); + rcnt_all = rcnt_local + varp->nchunk; + + // Allocate buffering for overlaping index + tsize = (int *)NCI_Malloc (sizeof (int) * varp->ndim * 3); + tssize = tsize + varp->ndim; + tstart = tssize + varp->ndim; + ostart = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim * 3); + osize = ostart + varp->ndim; + + // Chunk iterator + citr = osize + varp->ndim; + + // We need to calculate the size of message of each chunk + // This is just for allocating send buffer + // We do so by iterating through all request and all chunks they cover + // If we are not the owner of a chunk, we need to send message + memset (rcnt_local, 0, sizeof (int) * varp->nchunk); + nsend = 0; + for (req = 0; req < nreq; req++) { + // Iterate through chunks + ncchkioi_chunk_itr_init (varp, starts[req], counts[req], citr, &cid); + do { + if (varp->chunk_owner[cid] != ncchkp->rank && rcnt_local[cid] == 0) { + // Count number of mnessage we need to send + nsend++; + } + + rcnt_local[cid] = 1; + } while (ncchkioi_chunk_itr_next (varp, starts[req], counts[req], citr, &cid)); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SYNC) + + // Sync number of messages of each chunk + CHK_ERR_ALLREDUCE (rcnt_local, rcnt_all, varp->nchunk, MPI_INT, MPI_SUM, ncchkp->comm); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SYNC) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_IO_INIT) + + // We need to prepare chunk in the chunk cache + // For chunks not yet allocated, we need to read them form file collectively + // We collect chunk id of those chunks + // Calculate number of recv request + // This is for all the chunks + rids = (int *)NCI_Malloc (sizeof (int) * varp->nmychunk); + nread = 0; + nrecv = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + // We don't need message for our own data + nrecv += rcnt_all[cid] - rcnt_local[cid]; + // Count number of chunks we need to prepare + // We read only chunks that is required + if (rcnt_all[cid] || rcnt_local[cid]) { + if (varp->chunk_cache[cid] == NULL) { + // err = ncchkioi_cache_alloc(ncchkp, varp->chunksize, varp->chunk_cache + cid); + // varp->chunk_cache[cid] = (NC_chk_cache*)NCI_Malloc(varp->chunksize); + if (varp->chunk_index[cid].len > 0) { rids[nread++] = cid; } + } else { + // ncchkioi_cache_visit(ncchkp, varp->chunk_cache[cid]); + } + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_IO_INIT) + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET_CB) // I/O time count separately + +#ifdef PNETCDF_PROFILING + MPI_Barrier (ncchkp->comm); +#endif + // Decompress chunks into chunk cache + err = ncchkioi_load_var (ncchkp, varp, nread, rids); + CHK_ERR + + // Increase batch number to indicate allocated chunk buffer can be freed for future allocation + (ncchkp->cache_serial)++; + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB) + + // Allocate buffer for send and recv + // We need to accept nrecv requests and receive nsend of replies + rreqs = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * (nrecv + nsend)); + rstats = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * (nrecv + nsend)); + rbufs = (char **)NCI_Malloc (sizeof (char *) * (nrecv + nsend)); + rsizes = (int *)NCI_Malloc (sizeof (int) * (nrecv + nsend)); + // We need to send nsend requests and reply nrecv of requests + sbufs = (char **)NCI_Malloc (sizeof (char *) * (nrecv + nsend)); + sreqs = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * (nrecv + nsend)); + sstats = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * (nrecv + nsend)); + + // Post send + k = l = 0; + for (cid = 0; cid < varp->nchunk; cid++) { + if (varp->chunk_owner[cid] == ncchkp->rank) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // We are the owner of the chunk + // Receive data from other process + for (j = 0; j < rcnt_all[cid] - rcnt_local[cid]; j++) { + // Get message size, including metadata + CHK_ERR_MPROBE (MPI_ANY_SOURCE, cid, ncchkp->comm, &rmsg, rstats); + CHK_ERR_GET_COUNT (rstats, MPI_BYTE, rsizes + k); + + // Allocate buffer + rbufs[k] = (char *)NCI_Malloc (rsizes[k]); + + // Post irecv + CHK_ERR_IMRECV (rbufs[k], rsizes[k], MPI_BYTE, &rmsg, rreqs + k); + k++; + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REQ) + } else { + // We have some request to send + if (rcnt_local[cid] > 0) { + get_chunk_itr (varp, cid, citr); + rsizes[nrecv + l] = overlapcnt = 0; + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_PACK_REQ) + + // Calculate send buffer size + for (req = 0; req < nreq; req++) { + // Calculate chunk overlap + overlapsize = + get_chunk_overlap (varp, citr, starts[req], counts[req], ostart, osize); + + rsizes[nrecv + l] += overlapsize; + + if (overlapsize > 0) { overlapcnt++; } + } + + // Allocate buffer + // Faster to request the entire chunk + if (rsizes[nrecv + l] >= varp->chunksize) { + rsizes[nrecv + l] = varp->chunksize; + overlapcnt = 1; + } + sbufs[l] = (char *)NCI_Malloc (sizeof (int) * (overlapcnt * varp->ndim * 2) + 1); + rbufs[nrecv + l] = (char *)NCI_Malloc (rsizes[nrecv + l]); + + // Metadata + *((int *)sbufs[l]) = rsizes[nrecv + l]; + packoff = sizeof (int); + if (rsizes[nrecv + l] == + varp->chunksize) { // Request the entire chunk directly if need more than that + tstartp = (int *)(sbufs[l] + packoff); + packoff += varp->ndim * sizeof (int); + tsizep = (int *)(sbufs[l] + packoff); + packoff += varp->ndim * sizeof (int); + memset (tstartp, 0, sizeof (int) * varp->ndim); + memcpy (tsizep, varp->chunkdim, sizeof (int) * varp->ndim); + } else { + for (req = 0; req < nreq; req++) { + // Calculate chunk overlap + overlapsize = + get_chunk_overlap (varp, citr, starts[req], counts[req], ostart, osize); + + if (overlapsize > 0) { + tstartp = (int *)(sbufs[l] + packoff); + packoff += varp->ndim * sizeof (int); + tsizep = (int *)(sbufs[l] + packoff); + packoff += varp->ndim * sizeof (int); + // Metadata + for (j = 0; j < varp->ndim; j++) { + tstartp[j] = (int)(ostart[j] - citr[j]); + tsizep[j] = (int)osize[j]; + } + } + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_PACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Send request + CHK_ERR_ISEND (sbufs[l], packoff, MPI_BYTE, varp->chunk_owner[cid], cid, + ncchkp->comm, sreqs + l); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REP) + + // printf("Rank: %d, CHK_ERR_IRECV(%d, %d, %d, %d)\n", ncchkp->rank, overlapsize, + // varp->chunk_owner[cid], cid + 1024, nrecv + k); fflush(stdout); + CHK_ERR_IRECV (rbufs[l + nrecv], rsizes[nrecv + l], MPI_BYTE, + varp->chunk_owner[cid], cid + 1024, ncchkp->comm, rreqs + nrecv + l); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REP) + + l++; + } + } + } + + // Allocate intermediate buffer + cbuf = (char *)NCI_Malloc (varp->chunksize); + + // For each chunk we own, we need to reply to incoming reqeust + k = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SELF) + + // Handle our own data first if we have any + if (rcnt_local[cid] > 0) { + // Convert chunk id to iterator + get_chunk_itr (varp, cid, citr); + + for (req = 0; req < nreq; req++) { + // Calculate overlapping region + overlapsize = + get_chunk_overlap (varp, citr, starts[req], counts[req], ostart, osize); + + if (overlapsize > 0) { + // Pack type from chunk buffer to (contiguous) intermediate buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - citr[j]); + tsize[j] = varp->chunkdim[j]; + tssize[j] = (int)osize[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data into intermediate buffer + packoff = 0; + CHK_ERR_PACK (varp->chunk_cache[cid]->buf, 1, ptype, cbuf, varp->chunksize, + &packoff, ncchkp->comm); + overlapsize = packoff; + MPI_Type_free (&ptype); + + // Pack type from (contiguous) intermediate buffer to user buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - starts[req][j]); + tsize[j] = (int)counts[req][j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data into user buffer + packoff = 0; + CHK_ERR_UNPACK (cbuf, overlapsize, &packoff, bufs[req], 1, ptype, ncchkp->comm); + MPI_Type_free (&ptype); + } + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SELF) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // Wait for all send requests related to this chunk + // We remove the impact of -1 mark in rcnt_local[cid] + CHK_ERR_WAITALL (rcnt_all[cid] - rcnt_local[cid], rreqs + k, rstats + k); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // Now, it is time to process data from other processes + for (j = 0; j < varp->ndim; j++) { tsize[j] = varp->chunkdim[j]; } + // Process data received + for (j = k; j < k + rcnt_all[cid] - rcnt_local[cid]; j++) { + packoff = 0; + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_UNPACK_REQ) + + // Allocate buffer + overlapsize = *((int *)rbufs[j]); + unpackoff = sizeof (int); + sbufs[j + nsend] = (char *)NCI_Malloc (overlapsize); // For reply + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_UNPACK_REQ) + + // Pack data + while (unpackoff < rsizes[j]) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_UNPACK_REQ) + + // Get metadata + tstartp = (int *)(rbufs[j] + unpackoff); + unpackoff += varp->ndim * sizeof (int); + tssizep = (int *)(rbufs[j] + unpackoff); + unpackoff += varp->ndim * sizeof (int); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_UNPACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_PACK_REP) + + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssizep, tstartp, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data + CHK_ERR_PACK (varp->chunk_cache[cid]->buf, 1, ptype, sbufs[j + nsend], overlapsize, + &packoff, ncchkp->comm); + MPI_Type_free (&ptype); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_PACK_REP) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REP) + + // Send reply + // printf("Rank: %d, CHK_ERR_ISEND(%d, %d, %d, %d)\n", ncchkp->rank, packoff, + // varp->chunk_owner[cid], cid + 1024, k + nsend); fflush(stdout); + CHK_ERR_ISEND (sbufs[j + nsend], packoff, MPI_BYTE, rstats[j].MPI_SOURCE, cid + 1024, + ncchkp->comm, sreqs + j + nsend); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REP) + } + k += rcnt_all[cid] - rcnt_local[cid]; + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Wait for all request sent + // printf("Rank: %d, CHK_ERR_WAITALL_send(%d, %d)\n", ncchkp->rank, nsend, 0); fflush(stdout); + CHK_ERR_WAITALL (nsend, sreqs, sstats); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Receive replies from the owners and update the user buffer + k = 0; + for (cid = 0; cid < varp->nchunk; cid++) { + if (rcnt_local[cid] > 0 && varp->chunk_owner[cid] != ncchkp->rank) { + get_chunk_itr (varp, cid, citr); + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REP) + + // Wait for reply + // printf("Rank: %d, MPI_Wait_recv(%d)\n", ncchkp->rank, nrecv + k); fflush(stdout); + MPI_Wait (rreqs + nrecv + k, rstats + nrecv + k); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REP) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_UNPACK_REP) + + packoff = 0; + for (req = 0; req < nreq; req++) { + // Calculate chunk overlap + overlapsize = + get_chunk_overlap (varp, citr, starts[req], counts[req], ostart, osize); + + if (overlapsize > 0) { + // Pack type from recv buffer to user buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - starts[req][j]); + tsize[j] = (int)counts[req][j]; + tssize[j] = (int)osize[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data + CHK_ERR_UNPACK (rbufs[nrecv + k], rsizes[nrecv + k], &packoff, bufs[req], 1, + ptype, ncchkp->comm); + MPI_Type_free (&ptype); + } + } + k++; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_UNPACK_REP) + } + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REP) + + // Wait for all send replies + CHK_ERR_WAITALL (nrecv, sreqs + nsend, sstats + nsend); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REP) + +err_out:; + + // Free buffers + NCI_Free (rcnt_local); + + NCI_Free (rids); + + NCI_Free (tsize); + + NCI_Free (ostart); + + for (i = 0; i < nsend + nrecv; i++) { + NCI_Free (sbufs[i]); + NCI_Free (rbufs[i]); + } + NCI_Free (sreqs); + NCI_Free (sstats); + NCI_Free (sbufs); + NCI_Free (rreqs); + NCI_Free (rstats); + NCI_Free (rbufs); + NCI_Free (rsizes); + + if (cbuf != NULL) { NCI_Free (cbuf); } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB) + + return err; +} + +int ncchkioi_get_varn_cb_proc (NC_chk *ncchkp, + NC_chk_var *varp, + int nreq, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + void **bufs) { + int err = NC_NOERR; + int i, j, k; + int cid, cown; // Chunk iterator + int req, **reqs; + + MPI_Offset *ostart, *osize; + int *tsize, *tssize, *tstart, *tssizep, *tstartp; // Size for sub-array type + MPI_Offset *citr; // Chunk iterator + + int *rcnt_local, *rcnt_all; // Number of processes that writes to each proc + + int rrange_local[2], rrange_all[2]; // Number of processes that writes to each chunk + + int overlapsize; // Size of overlaping region of request and chunk + int max_tbuf = 0; // Size of intermediate buffer + char *tbuf = NULL; // Intermediate buffer + + int packoff; // Pack offset + MPI_Datatype ptype; // Pack datatype + + int nread; // # chunks to read form file + int *rids; // Id of chunks to read from file + + int nsend, nrecv; // Number of send and receive + MPI_Request *sreq, *rreq, *sreq_re, *rreq_re; // Send and recv req + MPI_Status *sstat, rstat, *sstat_re; // Send and recv status + char **sbuf, **rbuf, **sbufp, **rbufp, **sbuf_re, **rbuf_re; // Send and recv buffer + int *rsize, *ssize, *rsize_re, *ssize_re; // recv size of each message + int *sdst; // recv size of each message + int *smap; + MPI_Message rmsg; // Receive message + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_INIT) + + // Allocate buffering for write count + rcnt_local = (int *)NCI_Malloc (sizeof (int) * (ncchkp->np * 2 + varp->nchunk * 1)); + rcnt_all = rcnt_local + ncchkp->np; + smap = rcnt_all + ncchkp->np; + + // Allocate buffering for overlaping index + tsize = (int *)NCI_Malloc (sizeof (int) * varp->ndim * 3); + tssize = tsize + varp->ndim; + tstart = tssize + varp->ndim; + ostart = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim * 3); + osize = ostart + varp->ndim; + + // Chunk iterator + citr = osize + varp->ndim; + + // We need to calculate the size of message of each chunk + // This is just for allocating send buffer + // We do so by iterating through all request and all chunks they cover + // If we are not the owner of a chunk, we need to send message + memset (rcnt_local, 0, sizeof (int) * (ncchkp->np + varp->nchunk)); + nsend = 0; + + // counts[req] total number of messages and build a map of accessed chunk to list of comm + // datastructure + for (req = 0; req < nreq; req++) { + ncchkioi_chunk_itr_init (varp, starts[req], counts[req], citr, + &cid); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + + // Mapping to skip list of send requests + if (rcnt_local[cown] == 0 && cown != ncchkp->rank) { smap[cown] = nsend++; } + rcnt_local[cown] = 1; // Need to send message if not owner + + // Record lowest and highest chunk accessed + if (rrange_local[0] > cid) { rrange_local[0] = cid; } + if (rrange_local[1] < cid) { rrange_local[1] = cid; } + } while (ncchkioi_chunk_itr_next (varp, starts[req], counts[req], citr, &cid)); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SYNC) + + // Sync number of messages of each chunk + CHK_ERR_ALLREDUCE (rcnt_local, rcnt_all, ncchkp->np, MPI_INT, MPI_SUM, ncchkp->comm); + nrecv = rcnt_all[ncchkp->rank] - + rcnt_local[ncchkp->rank]; // We don't need to receive request form self + + rrange_local[1] *= -1; + CHK_ERR_ALLREDUCE (rrange_local, rrange_all, 2, MPI_INT, MPI_MIN, ncchkp->comm); + rrange_all[1] *= -1; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SYNC) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_IO_INIT) + + // We need to prepare chunk in the chunk cache + // For chunks not yet allocated, we need to read them form file collectively + // We collect chunk id of those chunks + // Calculate number of recv request + // This is for all the chunks + for (j = 0; j < varp->nmychunk && varp->mychunks[j] < rrange_all[0]; j++) + ; + for (k = j; k < varp->nmychunk && varp->mychunks[k] <= rrange_all[1]; k++) + ; + rids = (int *)NCI_Malloc (sizeof (int) * (k - j)); + nread = 0; + for (i = j; i < k; i++) { + cid = varp->mychunks[i]; + if (varp->chunk_cache[cid] == NULL) { + // err = ncchkioi_cache_alloc(ncchkp, varp->chunksize, varp->chunk_cache + cid); + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + if (varp->chunk_index[cid].len > 0) { rids[nread++] = cid; } + } else { + // ncchkioi_cache_visit(ncchkp, varp->chunk_cache[cid]); + } + } + + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET_CB) // I/O time count separately + +#ifdef PNETCDF_PROFILING + MPI_Barrier (ncchkp->comm); +#endif + // Decompress chunks into chunk cache + ncchkioi_load_var (ncchkp, varp, nread, rids); + // Increase batch number to indicate allocated chunk buffer can be freed for future allocation + (ncchkp->cache_serial)++; + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_PACK_REQ) + + // Allocate data structure for messaging + sbuf = (char **)NCI_Malloc (sizeof (char *) * (nsend * 2 + nrecv)); + ssize = (int *)NCI_Malloc (sizeof (int) * (nsend * 2 + nrecv * 1)); + sdst = ssize + (nsend + nrecv); + sreq = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * (nsend + nrecv)); + sstat = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * (nsend + nrecv)); + reqs = (int **)NCI_Malloc (sizeof (int *) * nsend); + + rbuf = (char **)NCI_Malloc (sizeof (char *) * (nsend + nrecv * 2)); + rsize = (int *)NCI_Malloc (sizeof (int) * (nsend + nrecv)); + rreq = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * (nsend + nrecv)); + + sbuf_re = sbuf + nsend; + sbufp = sbuf_re + nrecv; + ssize_re = ssize + nsend; + sreq_re = sreq + nsend; + sstat_re = sstat + nsend; + + rbuf_re = rbuf + nrecv; + rbufp = rbuf_re + nsend; + rsize_re = rsize + nrecv; + rreq_re = rreq + nrecv; + + // counts[req] size of each request + memset (ssize, 0, sizeof (int) * nsend); + memset (rsize_re, 0, sizeof (int) * nsend); + memset (rcnt_local, 0, sizeof (int) * nsend); + for (req = 0; req < nreq; req++) { + ncchkioi_chunk_itr_init_ex (varp, starts[req], counts[req], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + if (cown != ncchkp->rank) { + j = smap[cown]; + sdst[j] = cown; // Record a reverse map by the way + + // counts[req] overlap + overlapsize = varp->esize; + for (i = 0; i < varp->ndim; i++) { overlapsize *= osize[i]; } + ssize[j] += sizeof (int) * (varp->ndim * 2 + 1); + rsize_re[j] += overlapsize; + rcnt_local[j]++; + } + } while ( + ncchkioi_chunk_itr_next_ex (varp, starts[req], counts[req], citr, &cid, ostart, osize)); + } + + // Allocate buffer for send + for (i = 0; i < nsend; i++) { + ssize[i] += sizeof (int); + sbuf[i] = sbufp[i] = (char *)NCI_Malloc (ssize[i]); + *((int *)sbufp[i]) = rsize_re[i]; + sbufp[i] += sizeof (int); + rbuf_re[i] = (char *)NCI_Malloc (rsize_re[i]); + reqs[i] = (int *)NCI_Malloc (sizeof (int) * rcnt_local[i]); + } + + // Pack requests + memset (rcnt_local, 0, sizeof (int) * nsend); + for (req = 0; req < nreq; req++) { + ncchkioi_chunk_itr_init_ex (varp, starts[req], counts[req], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + if (cown != ncchkp->rank) { + j = smap[cown]; + + // Metadata + *((int *)sbufp[j]) = cid; + sbufp[j] += sizeof (int); + tstartp = (int *)sbufp[j]; + sbufp[j] += sizeof (int) * varp->ndim; + tssizep = (int *)sbufp[j]; + sbufp[j] += sizeof (int) * varp->ndim; + for (i = 0; i < varp->ndim; i++) { + tstartp[i] = (int)(ostart[i] - citr[i]); + tssizep[i] = (int)osize[i]; + } + + // Record source of the request + reqs[j][rcnt_local[j]++] = req; + } + } while ( + ncchkioi_chunk_itr_next_ex (varp, starts[req], counts[req], citr, &cid, ostart, osize)); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_PACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Post send + for (i = 0; i < nsend; i++) { + CHK_ERR_ISEND (sbuf[i], ssize[i], MPI_BYTE, sdst[i], 0, ncchkp->comm, sreq + i); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REP) + + // Post receive + for (i = 0; i < nsend; i++) { + CHK_ERR_IRECV (rbuf_re[i], rsize_re[i], MPI_BYTE, sdst[i], 1, ncchkp->comm, rreq_re + i); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REP) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // Post recv + for (i = 0; i < nrecv; i++) { + // Get message size, including metadata + CHK_ERR_MPROBE (MPI_ANY_SOURCE, 0, ncchkp->comm, &rmsg, &rstat); + CHK_ERR_GET_COUNT (&rstat, MPI_BYTE, rsize + i); + + // Allocate buffer + rbuf[i] = rbufp[i] = (char *)NCI_Malloc (rsize[i]); + + // Post irecv + CHK_ERR_IMRECV (rbuf[i], rsize[i], MPI_BYTE, &rmsg, rreq + i); + } + + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET_CB_RECV_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SELF) + + tbuf = (char *)NCI_Malloc (varp->chunksize); + + // Handle our own data + for (req = 0; req < nreq; req++) { + ncchkioi_chunk_itr_init_ex (varp, starts[req], counts[req], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + if (varp->chunk_owner[cid] == ncchkp->rank) { + // Pack type from chunk cache to (contiguous) intermediate buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - citr[j]); + tsize[j] = varp->chunkdim[j]; + tssize[j] = (int)osize[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data into intermediate buffer + packoff = 0; + CHK_ERR_PACK (varp->chunk_cache[cid]->buf, 1, ptype, tbuf, varp->chunksize, + &packoff, ncchkp->comm); + MPI_Type_free (&ptype); + overlapsize = packoff; + + // Pack type from (contiguous) intermediate buffer to chunk buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - starts[req][j]); + tsize[j] = (int)counts[req][j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Unpack data into chunk buffer + packoff = 0; + CHK_ERR_UNPACK (tbuf, overlapsize, &packoff, bufs[req], 1, ptype, ncchkp->comm); + MPI_Type_free (&ptype); + } + } while ( + ncchkioi_chunk_itr_next_ex (varp, starts[req], counts[req], citr, &cid, ostart, osize)); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SELF) + + // Handle incoming requests + for (i = 0; i < varp->ndim; i++) { tsize[i] = varp->chunkdim[i]; } + for (i = 0; i < nrecv; i++) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // Will wait any provide any benefit? + MPI_Waitany (nrecv, rreq, &j, &rstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REQ) + + packoff = 0; + ssize_re[j] = *((int *)rbufp[j]); + rbufp[j] += sizeof (int); + sbuf_re[j] = (char *)NCI_Malloc (ssize_re[j]); + while (rbufp[j] < rbuf[j] + rsize[j]) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_UNPACK_REQ) + + // Metadata + cid = *((int *)rbufp[j]); + rbufp[j] += sizeof (int); + tstartp = (int *)rbufp[j]; + rbufp[j] += sizeof (int) * varp->ndim; + tssizep = (int *)rbufp[j]; + rbufp[j] += sizeof (int) * varp->ndim; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_UNPACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_PACK_REP) + + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssizep, tstartp, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Data + CHK_ERR_PACK (varp->chunk_cache[cid]->buf, 1, ptype, sbuf_re[j], ssize_re[j], &packoff, + ncchkp->comm); + MPI_Type_free (&ptype); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_PACK_REP) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Send Response + CHK_ERR_ISEND (sbuf_re[j], packoff, MPI_BYTE, rstat.MPI_SOURCE, 1, ncchkp->comm, + sreq_re + j); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REQ) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Wait for all request + CHK_ERR_WAITALL (nsend, sreq, sstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Handle reply + memset (rcnt_local, 0, sizeof (int) * nsend); + for (i = 0; i < nsend; i++) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REP) + + // Will wait any provide any benefit? + MPI_Waitany (nsend, rreq_re, &j, &rstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REP) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_UNPACK_REP) + + sbufp[j] = sbuf[j] + sizeof (int); // Skip reply size + packoff = 0; + while (packoff < rsize_re[j]) { + // Retrieve metadata from the request we sent + cid = *((int *)sbufp[j]); + sbufp[j] += sizeof (int); + tstartp = (int *)sbufp[j]; + sbufp[j] += sizeof (int) * varp->ndim; + tssizep = (int *)sbufp[j]; + sbufp[j] += sizeof (int) * varp->ndim; + + // Bring up the request + req = reqs[j][rcnt_local[j]++]; + get_chunk_itr (varp, cid, citr); + for (k = 0; k < varp->ndim; k++) { + tstartp[k] += (int)(citr[k] - starts[req][k]); + tsize[k] = counts[req][k]; + } + + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssizep, tstartp, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data + CHK_ERR_UNPACK (rbuf_re[j], rsize_re[j], &packoff, bufs[req], 1, ptype, ncchkp->comm); + MPI_Type_free (&ptype); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_UNPACK_REP) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REP) + + // Wait for all Response + CHK_ERR_WAITALL (nrecv, sreq_re, sstat_re); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REP) + +err_out:; + + // Free buffers + NCI_Free (rcnt_local); + + NCI_Free (rids); + + NCI_Free (tsize); + + NCI_Free (ostart); + + NCI_Free (sreq); + NCI_Free (sstat); + NCI_Free (ssize); + for (i = 0; i < nsend; i++) { NCI_Free (reqs[i]); } + for (i = 0; i < nsend + nrecv; i++) { + NCI_Free (sbuf[i]); + NCI_Free (rbuf[i]); + } + NCI_Free (sbuf); + NCI_Free (reqs); + + NCI_Free (rreq); + NCI_Free (rbuf); + NCI_Free (rsize); + + if (tbuf != NULL) { NCI_Free (tbuf); } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB) + + return err; +} + +int ncchkioi_get_varn (NC_chk *ncchkp, + NC_chk_var *varp, + int nreq, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + const void *buf) { + int i, j; + MPI_Offset rsize; + char *bptr = (char *)buf; + char **bufs; + + // Calculate buffer offset of each request + bufs = (char **)NCI_Malloc (sizeof (char *) * nreq); + for (i = 0; i < nreq; i++) { + bufs[i] = bptr; + rsize = varp->esize; + for (j = 0; j < varp->ndim; j++) { rsize *= counts[i][j]; } + bptr += rsize; + } + + // Collective buffer + switch (ncchkp->comm_unit) { + case NC_CHK_COMM_CHUNK: + ncchkioi_get_varn_cb_chunk (ncchkp, varp, nreq, starts, counts, NULL, (void **)bufs); + break; + case NC_CHK_COMM_PROC: + ncchkioi_get_varn_cb_proc (ncchkp, varp, nreq, starts, counts, (void **)bufs); + break; + } + NCI_Free (bufs); + + return NC_NOERR; +} \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkioi_iget.c b/src/drivers/ncchunkio/ncchkioi_iget.c new file mode 100644 index 000000000..8548686c4 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_iget.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_get_var__all() : dispatcher->get_var() + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "ncchkio_internal.h" + +static inline int +ncchkioi_init_get_req( NC_chk *ncchkp, + NC_chk_req *req, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype) { + int err; + int *tsize, *tssize, *tstart; // Size for sub-array type + int overlapsize, packoff; + MPI_Datatype ptype; // Pack datatype + NC_chk_var *varp = ncchkp->vars.data + varid; + + // Zero out the request + memset(req, 0, sizeof(NC_chk_req)); + + // Record request + req->starts = (MPI_Offset**)NCI_Malloc(sizeof(MPI_Offset*)); + req->start = (MPI_Offset*)NCI_Malloc(sizeof(MPI_Offset) * varp->ndim); + req->starts[0] = req->start; + memcpy(req->start, start, sizeof(MPI_Offset) * varp->ndim); + req->counts = (MPI_Offset**)NCI_Malloc(sizeof(MPI_Offset*)); + req->count = (MPI_Offset*)NCI_Malloc(sizeof(MPI_Offset) * varp->ndim); + req->counts[0] = req->count; + memcpy(req->count, count, sizeof(MPI_Offset) * varp->ndim); + if (stride != NULL){ + req->stride = (MPI_Offset*)NCI_Malloc(sizeof(MPI_Offset) * varp->ndim); + memcpy(req->stride, stride, sizeof(MPI_Offset) * varp->ndim); + } + + req->varid = varid; + req->buf = (void*)buf; + req->nreq = 1; + req->buftype = buftype; + if (varp->etype != buftype){ + if (bufcount > 0){ + req->bufcount = bufcount; + } + else{ + int i; + + req->bufcount = 1; + for(i = 0; i < varp->ndim; i++){ + req->bufcount *= count[i]; + } + } + + req->xbuf = (char*)NCI_Malloc(req->bufcount * varp->esize); + } + else{ + req->xbuf = req->buf; + } + + req->xbufs = (char**)NCI_Malloc(sizeof(char*)); + req->xbufs[0] = req->xbuf; + + return NC_NOERR; +} + +int +ncchkioi_iget_var(NC_chk *ncchkp, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *reqid) +{ + int err; + int req_id; + NC_chk_req req; + + // Init request + err = ncchkioi_init_get_req(ncchkp, &req, varid, start, count, stride, imap, buf, bufcount, buftype); + + // Add to req list + ncchkioi_req_list_add(&(ncchkp->getlist), &req_id); + ncchkp->getlist.reqs[req_id] = req; + + if (reqid != NULL){ + *reqid = req_id * 2; + } + + return NC_NOERR; +} + +static inline int +ncchkioi_init_get_varn_req( NC_chk *ncchkp, + NC_chk_req *req, + int varid, + int nreq, + MPI_Offset *const*starts, + MPI_Offset *const*counts, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype) { + int i, j; + MPI_Offset rsize, boff; + NC_chk_var *varp = ncchkp->vars.data + varid; + + // Zero out the request + memset(req, 0, sizeof(NC_chk_req)); + + // Record request + req->starts = (MPI_Offset**)NCI_Malloc(sizeof(MPI_Offset*) * nreq); + req->start = (MPI_Offset*)NCI_Malloc(sizeof(MPI_Offset) * varp->ndim * nreq); + for(i = 0; i < nreq; i++){ + req->starts[i] = req->start + i * varp->ndim; + memcpy(req->starts[i], starts[i], sizeof(MPI_Offset) * varp->ndim); + } + req->counts = (MPI_Offset**)NCI_Malloc(sizeof(MPI_Offset*) * nreq); + req->count = (MPI_Offset*)NCI_Malloc(sizeof(MPI_Offset) * varp->ndim * nreq); + for(i = 0; i < nreq; i++){ + req->counts[i] = req->count + i * varp->ndim; + memcpy(req->counts[i], counts[i], sizeof(MPI_Offset) * varp->ndim); + } + + req->varid = varid; + req->buf = (void*)buf; + req->xbuf = (void*)buf; + req->nreq = nreq; + req->buftype = buftype; + if (varp->etype != buftype){ + if (bufcount > 0){ + req->bufcount = bufcount; + } + else{ + req->bufcount = 0; + for(i = 0; i < nreq; i++){ + rsize = 1; + for(j = 0; j < varp->ndim; j++){ + rsize *= counts[i][j]; + } + req->bufcount += rsize; + } + } + + req->xbuf = (char*)NCI_Malloc(req->bufcount * varp->esize); + } + else{ + req->xbuf = req->buf; + } + + // Calculate buffer for each individual request + req->xbufs = (char**)NCI_Malloc(sizeof(char*) * nreq); + boff = 0; + for(i = 0; i < nreq; i++){ + req->xbufs[i] = (req->xbuf + boff); + + // Advance pointer by size of the request + rsize = varp->esize; + for(j = 0; j < varp->ndim; j++){ + rsize *= counts[i][j]; + } + boff += rsize; + } + + return NC_NOERR; +} + +int +ncchkioi_iget_varn(NC_chk *ncchkp, + int varid, + int nreq, + MPI_Offset * const*starts, + MPI_Offset * const*counts, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int *reqid) +{ + int err; + int req_id; + NC_chk_req req; + + if (nreq > 1){ + err = ncchkioi_init_get_varn_req(ncchkp, &req, varid, nreq, starts, counts, buf, bufcount, buftype); + } + else{ + err = ncchkioi_init_get_req(ncchkp, &req, varid, starts[0], counts[0], NULL, NULL, buf, bufcount, buftype); + } + + // Add to req list + ncchkioi_req_list_add(&(ncchkp->getlist), &req_id); + ncchkp->getlist.reqs[req_id] = req; + + if (reqid != NULL){ + *reqid = req_id * 2; + } + + return NC_NOERR; +} diff --git a/src/drivers/ncchunkio/ncchkioi_iget_cb.c b/src/drivers/ncchunkio/ncchkioi_iget_cb.c new file mode 100644 index 000000000..9c55414da --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_iget_cb.c @@ -0,0 +1,686 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_get_var__all() : dispatcher->get_var() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ncchkio_internal.h" + +/* Out drive currently can handle only one variable at a time + * We pack all request as a large varn request + */ +int ncchkioi_iget_cb_chunk (NC_chk *ncchkp, int nreq, int *reqids, int *stats) { + int err; + int i, j; + int nvar; + int vid; // Iterators for variable id + int *varids; + int *nreqs; // Number of reqids in each variable + int *nums; // Number of reqs in each varn + int **vreqids; + int num, maxnum = 0; + MPI_Offset **starts, **counts, **strides; + MPI_Offset rsize; + char **bufs; + NC_chk_req *req; + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_INIT) + + // Count total number of request in per variable for packed varn request + nums = (int *)NCI_Malloc (sizeof (int) * ncchkp->vars.cnt * 2); + nreqs = nums + ncchkp->vars.cnt; + memset (nums, 0, sizeof (int) * ncchkp->vars.cnt); + memset (nreqs, 0, sizeof (int) * ncchkp->vars.cnt); + for (i = 0; i < nreq; i++) { + req = ncchkp->getlist.reqs + reqids[i]; + nreqs[req->varid]++; + nums[req->varid] += req->nreq; + } + + /* Allocate a skip list of reqids for each vriable + * At the same time, we find out the number of starts and counts we need to allocate + */ + vreqids = (int **)NCI_Malloc (sizeof (int *) * ncchkp->vars.cnt); + vreqids[0] = (int *)NCI_Malloc (sizeof (int) * nreq); + maxnum = 0; + i = 0; + nvar = 0; + for (vid = 0; vid < ncchkp->vars.cnt; vid++) { + if (nreqs[vid] > 0) { + // Assign buffer to reqid skip list + vreqids[vid] = vreqids[0] + i; + i += nreqs[vid]; + + // maximum number of starts and counts we need across all variables + if (maxnum < nums[vid]) { maxnum = nums[vid]; } + + // Number of variable that has request to write + nvar++; + } + } + + varids = (int *)NCI_Malloc (sizeof (int) * nvar); + + // Fill up the skip list + memset (nreqs, 0, sizeof (int) * ncchkp->vars.cnt); + for (i = 0; i < nreq; i++) { + req = ncchkp->getlist.reqs + reqids[i]; + vreqids[req->varid][nreqs[req->varid]++] = reqids[i]; + } + + // Allocate parameters + starts = (MPI_Offset **)NCI_Malloc (sizeof (MPI_Offset *) * maxnum * 2); + counts = starts + maxnum; + bufs = (char **)NCI_Malloc (sizeof (char *) * maxnum); + + /* Pack requests variable by variable + */ + nvar = 0; + for (vid = 0; vid < ncchkp->vars.cnt; vid++) { + if (nreqs[vid] > 0) { + // Fill varid in the skip list + varids[nvar++] = vid; + + // Collect parameters + num = 0; + for (j = 0; j < nreqs[vid]; j++) { + req = ncchkp->getlist.reqs + vreqids[vid][j]; + + if (req->nreq > 1) { + for (i = 0; i < req->nreq; i++) { + starts[num] = req->starts[i]; + counts[num] = req->counts[i]; + bufs[num++] = req->xbufs[i]; + } + } else { + starts[num] = req->start; + counts[num] = req->count; + bufs[num++] = req->xbuf; + } + } + + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET_CB) + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET_CB_INIT) + + // Perform collective buffering + ncchkioi_get_varn_cb_chunk (ncchkp, ncchkp->vars.data + vid, num, starts, counts, NULL, + (void **)bufs); + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_INIT) + } + } + + // Free buffers + NCI_Free (nums); + + NCI_Free (vreqids[0]); + NCI_Free (vreqids); + + NCI_Free (varids); + + NCI_Free (starts); + NCI_Free (bufs); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_INIT) + + return NC_NOERR; +} + +int ncchkioi_iget_cb_proc (NC_chk *ncchkp, int nreq, int *reqids, int *stats) { + int err; + int i, j, k; + int cid, cown; // Chunk iterator + int vid; + int r, **reqs; + + MPI_Offset *ostart, *osize; + int *tsize, *tssize, *tstart, *tssizep, *tstartp; // Size for sub-array type + MPI_Offset *citr; // Bounding box for chunks overlapping my own write region + + int *rcnt_local, *rcnt_all; // Number of processes that writes to each proc + + int nread; + int *rlo_local, *rhi_local; + int *rlo_all, *rhi_all; + int *rids; + + int overlapsize; // Size of overlaping region of request and chunk + char *tbuf = NULL; // Intermediate buffer + + int packoff; // Pack offset + MPI_Datatype ptype; // Pack datatype + MPI_Offset poff; // Offset of buffer to pack to/ from + int plen; + + int nsend, nrecv; // Number of send and receive + MPI_Request *sreq, *rreq, *sreq_re, *rreq_re; // Send and recv req + MPI_Status *sstat, rstat, *sstat_re; // Send and recv status + char **sbuf, **sbufp, **rbuf, **rbufp, **sbuf_re, **rbuf_re; // Send and recv buffer + int *rsize, *ssize, *rsize_re, *ssize_re; // recv size of each message + int *roff, *roff_re; // recv size of each message + int *sdst; // recv size of each message + int *smap; + MPI_Message rmsg; // Receive message + NC_chk_var *varp; + NC_chk_req *req; + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_INIT) + + // Allocate buffering for write count + rcnt_local = (int *)NCI_Malloc (sizeof (int) * ncchkp->np * 3); + rcnt_all = rcnt_local + ncchkp->np; + smap = rcnt_all + ncchkp->np; + + // Intermediate buffer for our own data + tbuf = (char *)NCI_Malloc (ncchkp->max_chunk_size); + + // Allocate buffering for overlaping index + tsize = (int *)NCI_Malloc (sizeof (int) * ncchkp->max_ndim * 3); + tssize = tsize + ncchkp->max_ndim; + tstart = tssize + ncchkp->max_ndim; + ostart = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * ncchkp->max_ndim * 3); + osize = ostart + ncchkp->max_ndim; + + // Chunk iterator + citr = osize + ncchkp->max_ndim; + + // Access range + rlo_local = (int *)NCI_Malloc (sizeof (int) * ncchkp->vars.cnt * 5); + rhi_local = rlo_local + ncchkp->vars.cnt; + rlo_all = rhi_local + ncchkp->vars.cnt; + rhi_all = rlo_all + ncchkp->vars.cnt; + rids = rhi_all + ncchkp->vars.cnt; + + for (i = 0; i < ncchkp->vars.cnt; i++) { + rlo_local[i] = 2147483647; + rhi_local[i] = -1; + } + + // We need to calculate the size of message of each chunk + // This is just for allocating send buffer + // We do so by iterating through all request and all chunks they cover + // If we are not the owner of a chunk, we need to send message + memset (rcnt_local, 0, sizeof (int) * ncchkp->np); + nsend = 0; + + // count total number of messages and build a map of accessed chunk to list of comm + // datastructure + for (i = 0; i < nreq; i++) { + req = ncchkp->getlist.reqs + reqids[i]; + varp = ncchkp->vars.data + req->varid; + for (r = 0; r < req->nreq; r++) { + ncchkioi_chunk_itr_init (varp, req->starts[r], req->counts[r], citr, + &cid); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + + // Mapping to skip list of send requests + if (rcnt_local[cown] == 0 && cown != ncchkp->rank) { smap[cown] = nsend++; } + rcnt_local[cown] = 1; // Need to send message if not owner + + if (rlo_local[req->varid] > cid) { rlo_local[req->varid] = cid; } + if (rhi_local[req->varid] < cid) { rhi_local[req->varid] = cid; } + } while (ncchkioi_chunk_itr_next (varp, req->starts[r], req->counts[r], citr, &cid)); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SYNC) + + // Sync number of messages of each chunk + CHK_ERR_ALLREDUCE (rcnt_local, rcnt_all, ncchkp->np, MPI_INT, MPI_SUM, ncchkp->comm); + nrecv = rcnt_all[ncchkp->rank] - + rcnt_local[ncchkp->rank]; // We don't need to receive request form self + +#ifdef PNETCDF_PROFILING + ncchkp->nsend += nrecv + nsend; + ncchkp->nrecv += nrecv + nsend; +#endif + + for (i = 0; i < ncchkp->vars.cnt; i++) { rhi_local[i] *= -1; } + CHK_ERR_ALLREDUCE (rlo_local, rlo_all, ncchkp->vars.cnt * 2, MPI_INT, MPI_MIN, ncchkp->comm); + for (i = 0; i < ncchkp->vars.cnt; i++) { rhi_all[i] *= -1; } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SYNC) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_PACK_REQ) + + // Allocate data structure for messaging + sbuf = (char **)NCI_Malloc (sizeof (char *) * (nsend * 2 + nrecv)); + sbufp = sbuf + (nsend + nrecv); + ssize = (int *)NCI_Malloc (sizeof (int) * (nsend * 2 + nrecv * 1)); + sdst = ssize + (nsend + nrecv); + sreq = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * (nsend + nrecv)); + sstat = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * (nsend + nrecv)); + reqs = (int **)NCI_Malloc (sizeof (int *) * nsend); + + rbuf = (char **)NCI_Malloc (sizeof (char *) * (nsend + nrecv * 2)); + rbufp = rbuf + (nsend + nrecv); + rsize = (int *)NCI_Malloc (sizeof (int) * (nsend + nrecv)); + rreq = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * (nsend + nrecv)); + + sbuf_re = sbuf + nsend; + ssize_re = ssize + nsend; + sreq_re = sreq + nsend; + sstat_re = sstat + nsend; + + rbuf_re = rbuf + nrecv; + rsize_re = rsize + nrecv; + rreq_re = rreq + nrecv; + + // req->counts[r] size of each request + memset (ssize, 0, sizeof (int) * nsend); + memset (rsize_re, 0, sizeof (int) * nsend); + memset (rcnt_local, 0, sizeof (int) * nsend); + for (i = 0; i < nreq; i++) { + req = ncchkp->getlist.reqs + reqids[i]; + varp = ncchkp->vars.data + req->varid; + for (r = 0; r < req->nreq; r++) { + ncchkioi_chunk_itr_init_ex (varp, req->starts[r], req->counts[r], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + if (cown != ncchkp->rank) { + j = smap[cown]; + sdst[j] = cown; // Record a reverse map by the way + + // Count overlap + overlapsize = varp->esize; + for (k = 0; k < varp->ndim; k++) { overlapsize *= osize[k]; } + ssize[j] += sizeof (int) * (varp->ndim * 2 + 2); + rsize_re[j] += overlapsize; + rcnt_local[j]++; + } + } while (ncchkioi_chunk_itr_next_ex (varp, req->starts[r], req->counts[r], citr, &cid, + ostart, osize)); + } + } + + // Allocate buffer for send + for (i = 0; i < nsend; i++) { + ssize[i] += sizeof (int); +#ifdef PNETCDF_DEBUG + assert (ssize[i] >= 0); +#endif + sbuf[i] = sbufp[i] = (char *)NCI_Malloc (ssize[i]); + *((int *)sbufp[i]) = rsize_re[i]; + sbufp[i] += sizeof (int); + rbuf_re[i] = (char *)NCI_Malloc (rsize_re[i]); + reqs[i] = (int *)NCI_Malloc (sizeof (int) * rcnt_local[i] * 2); +#ifdef PNETCDF_PROFILING + ncchkp->sendsize += ssize[i]; + ncchkp->recvsize += rsize_re[i]; +#endif + } + + // Pack requests + memset (rcnt_local, 0, sizeof (int) * nsend); + for (i = 0; i < nreq; i++) { + req = ncchkp->getlist.reqs + reqids[i]; + varp = ncchkp->vars.data + req->varid; + for (r = 0; r < req->nreq; r++) { + ncchkioi_chunk_itr_init_ex (varp, req->starts[r], req->counts[r], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + if (cown != ncchkp->rank) { + j = smap[cown]; + + // Pack metadata + *((int *)sbufp[j]) = varp->varid; + sbufp[j] += sizeof (int); + *((int *)sbufp[j]) = cid; + sbufp[j] += sizeof (int); + tstartp = (int *)sbufp[j]; + sbufp[j] += sizeof (int) * varp->ndim; + tssizep = (int *)sbufp[j]; + sbufp[j] += sizeof (int) * varp->ndim; + for (k = 0; k < varp->ndim; k++) { + tstartp[k] = (int)(ostart[k] - citr[k]); + tssizep[k] = (int)osize[k]; + } + + // Record source of the request + reqs[j][rcnt_local[j]++] = i; + reqs[j][rcnt_local[j]++] = r; + +#ifdef PNETCDF_PROFILING + ncchkp->nremote++; +#endif + } + } while (ncchkioi_chunk_itr_next_ex (varp, req->starts[r], req->counts[r], citr, &cid, + ostart, osize)); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_PACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Post send + for (i = 0; i < nsend; i++) { + CHK_ERR_ISEND (sbuf[i], ssize[i], MPI_BYTE, sdst[i], 0, ncchkp->comm, sreq + i); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REP) + + // Post receive + for (i = 0; i < nsend; i++) { + CHK_ERR_IRECV (rbuf_re[i], rsize_re[i], MPI_BYTE, sdst[i], 1, ncchkp->comm, rreq_re + i); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REP) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // Post recv + for (i = 0; i < nrecv; i++) { + // Get message size, including metadata + CHK_ERR_MPROBE (MPI_ANY_SOURCE, 0, ncchkp->comm, &rmsg, &rstat); + CHK_ERR_GET_COUNT (&rstat, MPI_BYTE, rsize + i); + + // Allocate buffer + rbuf[i] = rbufp[i] = (char *)NCI_Malloc (rsize[i]); +#ifdef PNETCDF_PROFILING + ncchkp->recvsize += rsize[i]; +#endif + // Post irecv + CHK_ERR_IMRECV (rbuf[i], rsize[i], MPI_BYTE, &rmsg, rreq + i); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REQ) + + nread = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + if (rhi_all[i] >= rlo_all[i]) { + varp = ncchkp->vars.data + i; + rids[nread] = i; + for (j = 0; j < varp->nmychunk && varp->mychunks[j] < rlo_all[i]; j++) + ; + for (k = j; k < varp->nmychunk && varp->mychunks[k] <= rhi_all[i]; k++) + ; + rlo_all[nread] = j; + rhi_all[nread++] = k; + } + } + + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET_CB) +#ifdef PNETCDF_PROFILING + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_BARR) + MPI_Barrier (ncchkp->comm); + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_BARR) +#endif + err = ncchkioi_load_nvar (ncchkp, nread, rids, rlo_all, rhi_all); + CHK_ERR + // Increase batch number to indicate allocated chunk buffer can be freed for future allocation + (ncchkp->cache_serial)++; + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB) + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SELF) + + // Handle our own data + for (i = 0; i < nreq; i++) { + req = ncchkp->getlist.reqs + reqids[i]; + varp = ncchkp->vars.data + req->varid; + for (r = 0; r < req->nreq; r++) { + ncchkioi_chunk_itr_init_ex (varp, req->starts[r], req->counts[r], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + if (varp->chunk_owner[cid] == ncchkp->rank) { + // Pack type from chunk cache to (contiguous) intermediate buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - citr[j]); + tsize[j] = varp->chunkdim[j]; + tssize[j] = (int)osize[j]; + } + err = + ncchkioi_subarray_off_len (varp->ndim, tsize, tssize, tstart, &poff, &plen); + if (err == 0) { + plen *= varp->esize; + poff *= varp->esize; + memcpy (tbuf, varp->chunk_cache[cid]->buf + poff, plen); + overlapsize = plen; + } else { + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, + MPI_ORDER_C, varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data into intermediate buffer + packoff = 0; + CHK_ERR_PACK (varp->chunk_cache[cid]->buf, 1, ptype, tbuf, varp->chunksize, + &packoff, ncchkp->comm); + MPI_Type_free (&ptype); + overlapsize = packoff; + } + + // Pack type from (contiguous) intermediate buffer to chunk buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - req->starts[r][j]); + tsize[j] = (int)req->counts[r][j]; + } + err = + ncchkioi_subarray_off_len (varp->ndim, tsize, tssize, tstart, &poff, &plen); + if (err == 0) { + plen *= varp->esize; + poff *= varp->esize; + memcpy (req->xbufs[r] + poff, tbuf, plen); + } else { + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, + MPI_ORDER_C, varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Unpack data into chunk buffer + packoff = 0; + CHK_ERR_UNPACK (tbuf, overlapsize, &packoff, req->xbufs[r], 1, ptype, + ncchkp->comm); + MPI_Type_free (&ptype); + } +#ifdef PNETCDF_PROFILING + ncchkp->nlocal++; +#endif + } + } while (ncchkioi_chunk_itr_next_ex (varp, req->starts[r], req->counts[r], citr, &cid, + ostart, osize)); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SELF) + + // Handle incoming requests + for (i = 0; i < nrecv; i++) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REQ) + + // Will wait any provide any benefit? + MPI_Waitany (nrecv, rreq, &j, &rstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REQ) + + packoff = 0; + ssize_re[j] = *((int *)rbufp[j]); + rbufp[j] += sizeof (int); +#ifdef PNETCDF_DEBUG + assert (ssize_re[j] >= 0); +#endif + sbuf_re[j] = (char *)NCI_Malloc (ssize_re[j]); + while (rbufp[j] < rbuf[j] + rsize[j]) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_UNPACK_REQ) + + // Retrieve metadata + vid = *((int *)rbufp[j]); + rbufp[j] += sizeof (int); + cid = *((int *)rbufp[j]); + rbufp[j] += sizeof (int); + varp = ncchkp->vars.data + vid; + tstartp = (int *)rbufp[j]; + rbufp[j] += sizeof (int) * varp->ndim; + tssizep = (int *)rbufp[j]; + rbufp[j] += sizeof (int) * varp->ndim; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_UNPACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_PACK_REP) + + err = ncchkioi_subarray_off_len (varp->ndim, varp->chunkdim, tssizep, tstartp, &poff, + &plen); + if (err == 0) { + plen *= varp->esize; + poff *= varp->esize; + memcpy (sbuf_re[j] + packoff, varp->chunk_cache[cid]->buf + poff, plen); + packoff += plen; + } else { + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, varp->chunkdim, tssizep, tstartp, + MPI_ORDER_C, varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data + CHK_ERR_PACK (varp->chunk_cache[cid]->buf, 1, ptype, sbuf_re[j], ssize_re[j], + &packoff, ncchkp->comm); + MPI_Type_free (&ptype); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_PACK_REP) +#ifdef PNETCDF_PROFILING + ncchkp->nreq++; +#endif + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Send Response + CHK_ERR_ISEND (sbuf_re[j], packoff, MPI_BYTE, rstat.MPI_SOURCE, 1, ncchkp->comm, + sreq_re + j); +#ifdef PNETCDF_PROFILING + ncchkp->sendsize += packoff; +#endif + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_GET_CB_SEND_REQ) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Wait for all request + CHK_ERR_WAITALL (nsend, sreq, sstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REQ) + + // Handle reply + memset (rcnt_local, 0, sizeof (int) * nsend); + for (i = 0; i < nsend; i++) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_RECV_REP) + + // Will wait any provide any benefit? + MPI_Waitany (nsend, rreq_re, &j, &rstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_RECV_REP) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_UNPACK_REP) + + sbufp[j] = sbuf[j] + sizeof (int); // Skip reply size + packoff = 0; + while (packoff < rsize_re[j]) { + // Retrieve metadata from the request we sent + vid = *((int *)sbufp[j]); + sbufp[j] += sizeof (int); + cid = *((int *)sbufp[j]); + sbufp[j] += sizeof (int); + varp = ncchkp->vars.data + vid; + tstartp = (int *)sbufp[j]; + sbufp[j] += sizeof (int) * varp->ndim; + tssizep = (int *)sbufp[j]; + sbufp[j] += sizeof (int) * varp->ndim; + + k = reqs[j][rcnt_local[j]++]; + r = reqs[j][rcnt_local[j]++]; + req = ncchkp->getlist.reqs + reqids[k]; + get_chunk_itr (varp, cid, citr); + for (k = 0; k < varp->ndim; k++) { + tstartp[k] += (int)(citr[k] - req->starts[r][k]); + tsize[k] = req->counts[r][k]; + } + + err = ncchkioi_subarray_off_len (varp->ndim, tsize, tssizep, tstartp, &poff, &plen); + if (err == 0) { + plen *= varp->esize; + poff *= varp->esize; + memcpy (req->xbufs[r] + poff, rbuf_re[j] + packoff, plen); + packoff += plen; + } else { + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssizep, tstartp, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data + CHK_ERR_UNPACK (rbuf_re[j], rsize_re[j], &packoff, req->xbufs[r], 1, ptype, + ncchkp->comm); + MPI_Type_free (&ptype); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_UNPACK_REP) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CB_SEND_REP) + + // Wait for all Response + CHK_ERR_WAITALL (nrecv, sreq_re, sstat_re); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB_SEND_REP) + + // Free buffers + NCI_Free (rcnt_local); + + NCI_Free (tsize); + + NCI_Free (ostart); + + NCI_Free (tbuf); + + NCI_Free (sreq); + NCI_Free (sstat); + NCI_Free (ssize); + for (i = 0; i < nsend; i++) { NCI_Free (reqs[i]); } + for (i = 0; i < nsend + nrecv; i++) { + NCI_Free (sbuf[i]); + NCI_Free (rbuf[i]); + } + NCI_Free (sbuf); + NCI_Free (reqs); + + NCI_Free (rreq); + NCI_Free (rbuf); + NCI_Free (rsize); + + NCI_Free (rlo_local); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CB) + +err_out:; + return err; +} diff --git a/src/drivers/ncchunkio/ncchkioi_iput.c b/src/drivers/ncchunkio/ncchkioi_iput.c new file mode 100644 index 000000000..92891520f --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_iput.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ncchkio_internal.h" + +static inline int ncchkioi_init_put_req (NC_chk *ncchkp, + NC_chk_req *req, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const void *xbuf, + const void *buf) { + int err = NC_NOERR; + int i, j, k, l; + int *tsize, *tssize, *tstart; // Size for sub-array type + int overlapsize, packoff; + MPI_Datatype ptype; // Pack datatype + NC_chk_var *varp = ncchkp->vars.data + varid; + + // Zero out the request + memset (req, 0, sizeof (NC_chk_req)); + + // Record request + req->starts = (MPI_Offset **)NCI_Malloc (sizeof (MPI_Offset *)); + req->start = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim); + req->starts[0] = req->start; + memcpy (req->start, start, sizeof (MPI_Offset) * varp->ndim); + req->counts = (MPI_Offset **)NCI_Malloc (sizeof (MPI_Offset *)); + req->count = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim); + req->counts[0] = req->count; + memcpy (req->count, count, sizeof (MPI_Offset) * varp->ndim); + if (stride != NULL) { + req->stride = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim); + memcpy (req->stride, stride, sizeof (MPI_Offset) * varp->ndim); + } + + req->varid = varid; + req->buf = (void *)buf; + req->xbuf = (void *)xbuf; + req->xbufs = (char **)NCI_Malloc (sizeof (char *)); + req->xbufs[0] = req->xbuf; + req->nreq = 1; + + return err; +} + +int ncchkioi_iput_var (NC_chk *ncchkp, + int varid, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const void *xbuf, + const void *buf, + int *reqid) { + int err; + int req_id; + NC_chk_req req; + + err = ncchkioi_init_put_req (ncchkp, &req, varid, start, count, stride, xbuf, buf); + + // Add to req list + ncchkioi_req_list_add (&(ncchkp->putlist), &req_id); + ncchkp->putlist.reqs[req_id] = req; + + if (reqid != NULL) { *reqid = req_id * 2 + 1; } + + return NC_NOERR; +} + +static inline int ncchkioi_init_put_varn_req (NC_chk *ncchkp, + NC_chk_req *req, + int varid, + int nreq, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + const void *xbuf, + const void *buf) { + int err = NC_NOERR; + int i, j; + MPI_Offset rsize, boff; + NC_chk_var *varp = ncchkp->vars.data + varid; + + // Zero out the request + memset (req, 0, sizeof (NC_chk_req)); + + // Record request + req->starts = (MPI_Offset **)NCI_Malloc (sizeof (MPI_Offset *) * nreq); + CHK_PTR (req->starts) + req->start = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim * nreq); + CHK_PTR (req->start) + for (i = 0; i < nreq; i++) { + req->starts[i] = req->start + i * varp->ndim; + memcpy (req->starts[i], starts[i], sizeof (MPI_Offset) * varp->ndim); + } + req->counts = (MPI_Offset **)NCI_Malloc (sizeof (MPI_Offset *) * nreq); + CHK_PTR (req->counts) + req->count = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim * nreq); + CHK_PTR (req->count) + for (i = 0; i < nreq; i++) { + req->counts[i] = req->count + i * varp->ndim; + memcpy (req->counts[i], counts[i], sizeof (MPI_Offset) * varp->ndim); + } + + // Calculate buffer for each individual request + req->xbufs = (char **)NCI_Malloc (sizeof (char *) * nreq); + CHK_PTR (req->xbufs) + boff = 0; + for (i = 0; i < nreq; i++) { + req->xbufs[i] = (((char *)xbuf) + boff); + + // Advance pointer by size of the request + rsize = varp->esize; + for (j = 0; j < varp->ndim; j++) { rsize *= counts[i][j]; } + boff += rsize; + } + + req->varid = varid; + req->buf = (void *)buf; + req->xbuf = (void *)xbuf; + req->nreq = nreq; + +err_out:; + return err; +} + +int ncchkioi_iput_varn (NC_chk *ncchkp, + int varid, + int nreq, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + const void *xbuf, + const void *buf, + int *reqid) { + int err = NC_NOERR; + int req_id; + NC_chk_req req; + + if (nreq > 1) { + err = ncchkioi_init_put_varn_req (ncchkp, &req, varid, nreq, starts, counts, xbuf, buf); + } else { + err = ncchkioi_init_put_req (ncchkp, &req, varid, starts[0], counts[0], NULL, xbuf, buf); + } + CHK_ERR + + // Add to req list + err = ncchkioi_req_list_add (&(ncchkp->putlist), &req_id); + CHK_ERR + ncchkp->putlist.reqs[req_id] = req; + + if (reqid != NULL) { *reqid = req_id * 2 + 1; } + +err_out:; + return err; +} diff --git a/src/drivers/ncchunkio/ncchkioi_iput_cb.c b/src/drivers/ncchunkio/ncchkioi_iput_cb.c new file mode 100644 index 000000000..41d5cf874 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_iput_cb.c @@ -0,0 +1,622 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ncchkio_internal.h" + +/* Out drive currently can handle only one variable at a time + * We pack all request as a large varn request + */ +int ncchkioi_iput_cb_chunk (NC_chk *ncchkp, int nreq, int *reqids, int *stats) { + int err; + int i, j; + int vid; // Iterators for variable id + int *nreqs; // Number of reqids in each variable + int *nums; // Number of reqs in each varn + int **vreqids; + int num, maxnum = 0; + MPI_Offset **starts, **counts, **strides; + MPI_Offset rsize; + char **bufs; + NC_chk_req *req; + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_INIT) + + // Count total number of request in per variable for packed varn request + nums = (int *)NCI_Malloc (sizeof (int) * ncchkp->vars.cnt * 2); + nreqs = nums + ncchkp->vars.cnt; + memset (nums, 0, sizeof (int) * ncchkp->vars.cnt); + memset (nreqs, 0, sizeof (int) * ncchkp->vars.cnt); + for (i = 0; i < nreq; i++) { + req = ncchkp->putlist.reqs + reqids[i]; + nreqs[req->varid]++; + nums[req->varid] += req->nreq; + } + + /* Allocate a skip list of reqids for each vriable + * At the same time, we find out the number of starts and counts we need to allocate + */ + vreqids = (int **)NCI_Malloc (sizeof (int *) * ncchkp->vars.cnt); + vreqids[0] = (int *)NCI_Malloc (sizeof (int) * nreq); + maxnum = 0; + i = 0; + for (vid = 0; vid < ncchkp->vars.cnt; vid++) { + if (nreqs[vid] > 0) { + // Assign buffer to reqid skip list + vreqids[vid] = vreqids[0] + i; + i += nreqs[vid]; + + // maximum number of starts and counts we need across all variables + if (maxnum < nums[vid]) { maxnum = nums[vid]; } + } + } + + // Fill up the skip list + memset (nreqs, 0, sizeof (int) * ncchkp->vars.cnt); + for (i = 0; i < nreq; i++) { + req = ncchkp->putlist.reqs + reqids[i]; + vreqids[req->varid][nreqs[req->varid]++] = reqids[i]; + } + + // Allocate parameters + starts = (MPI_Offset **)NCI_Malloc (sizeof (MPI_Offset *) * maxnum * 2); + counts = starts + maxnum; + bufs = (char **)NCI_Malloc (sizeof (char *) * maxnum); + + /* Pack requests variable by variable + */ + for (vid = 0; vid < ncchkp->vars.cnt; vid++) { + if (nreqs[vid] > 0) { + // Collect parameters + num = 0; + for (j = 0; j < nreqs[vid]; j++) { + req = ncchkp->putlist.reqs + vreqids[vid][j]; + + for (i = 0; i < req->nreq; i++) { + starts[num] = req->starts[i]; + counts[num] = req->counts[i]; + bufs[num++] = req->xbufs[i]; + } + } + + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_PUT_CB) + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_PUT_CB_INIT) + + // Perform collective buffering + ncchkioi_put_varn_cb_chunk (ncchkp, ncchkp->vars.data + vid, num, starts, counts, NULL, + (void **)bufs); + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_INIT) + } + } + + // Free buffers + NCI_Free (nums); + + NCI_Free (vreqids[0]); + NCI_Free (vreqids); + + NCI_Free (starts); + NCI_Free (bufs); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_INIT) + + return NC_NOERR; +} + +/* Out drive currently can handle only one variable at a time + * We pack all request as a large varn request + */ +int ncchkioi_iput_cb_proc (NC_chk *ncchkp, int nreq, int *reqids, int *stats) { + int err; + int i, j, k; + int cid, cown; // Chunk iterator and owner + int vid; + int r; + MPI_Offset *ostart = NULL, *osize; + int *tsize, *tssize, *tstart = NULL, *tssizep, *tstartp; // Size for sub-array type + MPI_Offset *citr; // Bounding box for chunks overlapping my own write region + + int *wcnt_local = NULL, *wcnt_all; // Number of processes that writes to each chunk + + int nread; + int *rlo_local, *rhi_local; + int *rlo_all, *rhi_all; + int *rids; + + int overlapsize; // Size of overlaping region of request and chunk + char *tbuf = NULL; // Intermediate buffer + + int packoff; // Pack offset + MPI_Offset pboff; // Offset of buffer to pack to/ from + MPI_Datatype ptype; // Pack datatype + int plen; + + int nsend, nrecv; // Number of send and receive + MPI_Request *sreq = NULL, *rreq = NULL; // Send and recv req + MPI_Status *sstat = NULL, rstat; // Send and recv status + char **sbuf = NULL, **rbuf = NULL; // Send and recv buffer + char **sbufp, **rbufp; // Send and recv buffer pointer + int *rsize = NULL, *ssize = NULL; // Send and recv size of each message + MPI_Offset totalsize; + int *sdst; // recv size of each message + int *smap; + MPI_Message rmsg; // Receive message + NC_chk_var *varp; + NC_chk_req *req; + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_INIT) + + // Allocate buffering for write count + wcnt_local = (int *)NCI_Malloc (sizeof (int) * ncchkp->np * 3); + CHK_PTR (wcnt_local) + wcnt_all = wcnt_local + ncchkp->np; + smap = wcnt_all + ncchkp->np; + + // Intermediate buffer for our own data + tbuf = (char *)NCI_Malloc (ncchkp->max_chunk_size); + CHK_PTR (tbuf) + + // Allocate buffering for overlaping index + tstart = (int *)NCI_Malloc (sizeof (int) * ncchkp->max_ndim * 3); + CHK_PTR (tstart) + tssize = tstart + ncchkp->max_ndim; + tsize = tssize + ncchkp->max_ndim; + ostart = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * ncchkp->max_ndim * 3); + CHK_PTR (ostart) + osize = ostart + ncchkp->max_ndim; + + // Chunk iterator + citr = osize + ncchkp->max_ndim; + + // Access range + rlo_local = (int *)NCI_Malloc (sizeof (int) * ncchkp->vars.cnt * 5); + CHK_PTR (rlo_local) + rhi_local = rlo_local + ncchkp->vars.cnt; + rlo_all = rhi_local + ncchkp->vars.cnt; + rhi_all = rlo_all + ncchkp->vars.cnt; + rids = rhi_all + ncchkp->vars.cnt; + + for (i = 0; i < ncchkp->vars.cnt; i++) { + rlo_local[i] = 2147483647; + rhi_local[i] = -1; + } + + // We need to calculate the size of message of each processes + // This is just for allocating send buffer + // We do so by iterating through all request and all chunks they cover + // If we are not the owner of a chunk, we need to send message + memset (wcnt_local, 0, sizeof (int) * ncchkp->np); + nsend = 0; + + // Count total number of messages and build a map of accessed chunk to list of comm + // datastructure + for (i = 0; i < nreq; i++) { + req = ncchkp->putlist.reqs + reqids[i]; + varp = ncchkp->vars.data + req->varid; + for (r = 0; r < req->nreq; r++) { + ncchkioi_chunk_itr_init (varp, req->starts[r], req->counts[r], citr, + &cid); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + + // Mapping to skip list of send requests + if (wcnt_local[cown] == 0 && cown != ncchkp->rank) { smap[cown] = nsend++; } + wcnt_local[cown] = 1; // Need to send message if not owner + + if (rlo_local[req->varid] > cid) { rlo_local[req->varid] = cid; } + if (rhi_local[req->varid] < cid) { rhi_local[req->varid] = cid; } + } while (ncchkioi_chunk_itr_next (varp, req->starts[r], req->counts[r], citr, &cid)); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SYNC) + + // Sync number of messages of each chunk + CHK_ERR_ALLREDUCE (wcnt_local, wcnt_all, ncchkp->np, MPI_INT, MPI_SUM, ncchkp->comm); + nrecv = wcnt_all[ncchkp->rank] - + wcnt_local[ncchkp->rank]; // We don't need to receive request form self + + for (i = 0; i < ncchkp->vars.cnt; i++) { rhi_local[i] *= -1; } + CHK_ERR_ALLREDUCE (rlo_local, rlo_all, ncchkp->vars.cnt * 2, MPI_INT, MPI_MIN, ncchkp->comm); + for (i = 0; i < ncchkp->vars.cnt; i++) { rhi_all[i] *= -1; } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SYNC) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_PACK_REQ) + + // Allocate data structure for messaging + sbuf = (char **)NCI_Malloc (sizeof (char *) * nsend * 2); + CHK_PTR (sbuf) + sbufp = sbuf + nsend; + ssize = (int *)NCI_Malloc (sizeof (int) * nsend * 2); + CHK_PTR (ssize) + sdst = ssize + nsend; + sreq = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * nsend); + CHK_PTR (sreq) + sstat = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * nsend); + CHK_PTR (sstat) + + rbuf = (char **)NCI_Malloc (sizeof (char *) * nrecv * 2); + CHK_PTR (rbuf) + rbufp = rbuf + nrecv; + rsize = (int *)NCI_Malloc (sizeof (int) * nrecv); + CHK_PTR (rsize) + rreq = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * nrecv); + CHK_PTR (rreq) + + // Count size of each request + memset (ssize, 0, sizeof (int) * nsend); + for (k = 0; k < nreq; k++) { + req = ncchkp->putlist.reqs + reqids[k]; + varp = ncchkp->vars.data + req->varid; + + for (r = 0; r < req->nreq; r++) { + ncchkioi_chunk_itr_init_ex (varp, req->starts[r], req->counts[r], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk index and owner + cown = varp->chunk_owner[cid]; + if (cown != ncchkp->rank) { + j = smap[cown]; + sdst[j] = cown; // Record a reverse map by the way + + // Count overlap + overlapsize = varp->esize; + for (i = 0; i < varp->ndim; i++) { overlapsize *= osize[i]; } + ssize[j] += overlapsize + sizeof (int) * (varp->ndim * 2 + 2); +#ifdef PNETCDF_DEBUG + if (ssize[j] < 0) { RET_ERR (NC_EAINT_TOO_SMALL) } +#endif + } + } while (ncchkioi_chunk_itr_next_ex (varp, req->starts[r], req->counts[r], citr, &cid, + ostart, osize)); + } + } + + // Allocate buffer for send + totalsize = 0; + for (i = 0; i < nsend; i++) { +#ifdef PNETCDF_DEBUG + assert (ssize[i] >= 0); +#endif + totalsize += ssize[i]; + } + if (nsend > 0) { + sbuf[0] = sbufp[0] = (char *)NCI_Malloc (totalsize); + CHK_PTR (sbuf[0]) + for (i = 1; i < nsend; i++) { sbuf[i] = sbufp[i] = sbuf[i - 1] + ssize[i - 1]; } + } +#ifdef PNETCDF_PROFILING + ncchkp->nsend += nsend; + ncchkp->sendsize += totalsize; +#endif + + // Pack requests + for (k = 0; k < nreq; k++) { + req = ncchkp->putlist.reqs + reqids[k]; + varp = ncchkp->vars.data + req->varid; + + for (r = 0; r < req->nreq; r++) { + ncchkioi_chunk_itr_init_ex (varp, req->starts[r], req->counts[r], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk index and owner + cown = varp->chunk_owner[cid]; + + if (cown != ncchkp->rank) { + j = smap[cown]; + + // Pack metadata + *((int *)(sbufp[j])) = req->varid; + sbufp[j] += sizeof (int); + *((int *)(sbufp[j])) = cid; + sbufp[j] += sizeof (int); + tstartp = (int *)sbufp[j]; + sbufp[j] += varp->ndim * sizeof (int); + tssizep = (int *)sbufp[j]; + sbufp[j] += varp->ndim * sizeof (int); + + for (i = 0; i < varp->ndim; i++) { + tstartp[i] = (int)(ostart[i] - citr[i]); + tssizep[i] = (int)osize[i]; + } + + // Pack type from user buffer to send buffer + for (i = 0; i < varp->ndim; i++) { + tsize[i] = (int)req->counts[r][i]; + tstart[i] = (int)(ostart[i] - req->starts[r][i]); + } + err = ncchkioi_subarray_off_len (varp->ndim, tsize, tssizep, tstart, &pboff, + &plen); + if (err == 0) { + plen *= varp->esize; + pboff *= varp->esize; +#ifdef PNETCDF_DEBUG + if (sbufp[j] - sbuf[j] + plen > ssize[j]) { RET_ERR (NC_EINTERNAL) } +#endif + memcpy (sbufp[j], req->xbufs[r] + pboff, plen); + sbufp[j] += plen; + } else { + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssizep, tstart, + MPI_ORDER_C, varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data + packoff = 0; + CHK_ERR_PACK (req->xbufs[r], 1, ptype, sbufp[j], ssize[j], &packoff, + ncchkp->comm); + sbufp[j] += packoff; + MPI_Type_free (&ptype); + } + +#ifdef PNETCDF_PROFILING + ncchkp->nremote++; +#endif + } + } while (ncchkioi_chunk_itr_next_ex (varp, req->starts[r], req->counts[r], citr, &cid, + ostart, osize)); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_PACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SEND_REQ) + + // Post send + for (i = 0; i < nsend; i++) { + CHK_ERR_ISEND (sbuf[i], ssize[i], MPI_BYTE, sdst[i], 0, ncchkp->comm, sreq + i); + if (ssize[i] == 24 && sdst[i] == 983) { + printf ("rank %d: wrong ssize to 983\n", ncchkp->rank); + abort (); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SEND_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_RECV_REQ) + + // Post recv + for (i = 0; i < nrecv; i++) { + // Get message size, including metadata + CHK_ERR_MPROBE (MPI_ANY_SOURCE, 0, ncchkp->comm, &rmsg, &rstat); + CHK_ERR_GET_COUNT (&rstat, MPI_BYTE, rsize + i); + + // Allocate buffer + rbuf[i] = rbufp[i] = (char *)NCI_Malloc (rsize[i]); + CHK_PTR (rbuf[i]) + +#ifdef PNETCDF_PROFILING + ncchkp->recvsize += rsize[i]; +#endif + + // Post irecv + CHK_ERR_IMRECV (rbuf[i], rsize[i], MPI_BYTE, &rmsg, rreq + i); + } +#ifdef PNETCDF_PROFILING + ncchkp->nrecv += nrecv; +#endif + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_RECV_REQ) + + nread = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + if (rhi_all[i] >= rlo_all[i]) { + varp = ncchkp->vars.data + i; + rids[nread] = i; + for (j = 0; j < varp->nmychunk && varp->mychunks[j] < rlo_all[i]; j++) + ; + for (k = j; k < varp->nmychunk && varp->mychunks[k] <= rhi_all[i]; k++) + ; + rlo_all[nread] = j; + rhi_all[nread++] = k; + } + } + +#ifdef PNETCDF_PROFILING + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_BARR) + MPI_Barrier (ncchkp->comm); + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_BARR) +#endif + + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_PUT_CB) + err = ncchkioi_load_nvar_bg (ncchkp, nread, rids, rlo_all, rhi_all); + CHK_ERR + // Increase batch number to indicate allocated chunk buffer can be freed for future + // allocation + (ncchkp->cache_serial) + ++; + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SELF) + + // Handle our own data + for (k = 0; k < nreq; k++) { + req = ncchkp->putlist.reqs + reqids[k]; + varp = ncchkp->vars.data + req->varid; + + for (r = 0; r < req->nreq; r++) { + ncchkioi_chunk_itr_init_ex (varp, req->starts[r], req->counts[r], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk index and owner + if (varp->chunk_owner[cid] == ncchkp->rank) { + // Pack type from user buffer to (contiguous) intermediate buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - req->starts[r][j]); + tsize[j] = (int)req->counts[r][j]; + tssize[j] = (int)osize[j]; + } + err = ncchkioi_subarray_off_len (varp->ndim, tsize, tssize, tstart, &pboff, + &plen); + if (err == 0) { + plen *= varp->esize; + pboff *= varp->esize; + memcpy (tbuf, req->xbufs[r] + pboff, plen); + overlapsize = plen; + } else { + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, + MPI_ORDER_C, varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data into intermediate buffer + packoff = 0; + CHK_ERR_PACK (req->xbufs[r], 1, ptype, tbuf, varp->chunksize, &packoff, + ncchkp->comm); + MPI_Type_free (&ptype); + overlapsize = packoff; + } + + // Pack type from (contiguous) intermediate buffer to chunk buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - citr[j]); + tsize[j] = varp->chunkdim[j]; + } + err = ncchkioi_subarray_off_len (varp->ndim, tsize, tssize, tstart, &pboff, + &plen); + if (err == 0) { + plen *= varp->esize; + pboff *= varp->esize; + memcpy (varp->chunk_cache[cid]->buf + pboff, tbuf, plen); + } else { + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, + MPI_ORDER_C, varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Unpack data into chunk buffer + packoff = 0; + CHK_ERR_UNPACK (tbuf, overlapsize, &packoff, varp->chunk_cache[cid]->buf, 1, + ptype, ncchkp->comm); + MPI_Type_free (&ptype); + } + + // Mark chunk as dirty + varp->dirty[cid] = 1; +#ifdef PNETCDF_PROFILING + ncchkp->nlocal++; +#endif + } + } while (ncchkioi_chunk_itr_next_ex (varp, req->starts[r], req->counts[r], citr, &cid, + ostart, osize)); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SELF) + + // Handle incoming requests + for (i = 0; i < nrecv; i++) { + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_RECV_REQ) + + // Will wait any provide any benefit? + MPI_Waitany (nrecv, rreq, &j, &rstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_RECV_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_UNPACK_REQ) + + packoff = 0; + while (rbufp[j] - rbuf[j] < rsize[j]) { + // Retrieve metadata + vid = *((int *)(rbufp[j])); + rbufp[j] += sizeof (int); + cid = *((int *)(rbufp[j])); + rbufp[j] += sizeof (int); + varp = ncchkp->vars.data + vid; + tstartp = (int *)rbufp[j]; + rbufp[j] += varp->ndim * sizeof (int); + tssizep = (int *)rbufp[j]; + rbufp[j] += varp->ndim * sizeof (int); + + err = ncchkioi_subarray_off_len (varp->ndim, varp->chunkdim, tssizep, tstartp, &pboff, + &plen); + if (err == 0) { + plen *= varp->esize; + pboff *= varp->esize; +#ifdef PNETCDF_DEBUG + if (rbufp[j] - rbuf[j] + plen > rsize[j]) { RET_ERR (NC_EINTERNAL) } +#endif + memcpy (varp->chunk_cache[cid]->buf + pboff, rbufp[j], plen); + rbufp[j] += plen; + } else { + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, varp->chunkdim, tssizep, tstartp, + MPI_ORDER_C, varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data + packoff = 0; + CHK_ERR_UNPACK (rbufp[j], rsize[j], &packoff, varp->chunk_cache[cid]->buf, 1, ptype, + ncchkp->comm); + rbufp[j] += packoff; + MPI_Type_free (&ptype); + } + + // Mark chunk as dirty + varp->dirty[cid] = 1; + +#ifdef PNETCDF_PROFILING + ncchkp->nreq++; +#endif + } + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_UNPACK_REQ) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SEND_REQ) + + CHK_ERR_WAITALL (nsend, sreq, sstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SEND_REQ) + +err_out:; + // Free buffers + NCI_Free (wcnt_local); + + NCI_Free (tstart); + + NCI_Free (ostart); + + NCI_Free (sreq); + NCI_Free (sstat); + NCI_Free (ssize); + if (nsend > 0) { NCI_Free (sbuf[0]); } + NCI_Free (sbuf); + + NCI_Free (rreq); + for (i = 0; i < nrecv; i++) { NCI_Free (rbuf[i]); } + NCI_Free (rbuf); + NCI_Free (rsize); + + NCI_Free (tbuf); + + NCI_Free (rlo_local); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB) + + return err; +} diff --git a/src/drivers/ncchunkio/ncchkioi_lagacy.c b/src/drivers/ncchunkio/ncchkioi_lagacy.c new file mode 100644 index 000000000..743ff75e1 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_lagacy.c @@ -0,0 +1,719 @@ +/* + * Copyright (C) 2017, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "ncchkio_internal.h" + +#define min(a,b) (((a)<(b))?(a):(b)) +#define max(a,b) (((a)>(b))?(a):(b)) + +int +ncchkioi_get_var_old(NC_chk *ncchkp, + NC_chk_var *varp, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + const MPI_Offset *imap, + void *buf, + MPI_Offset bufcount, + MPI_Datatype buftype, + int reqMode) +{ + int i, j, err; + nc_type xtype; + int *cstart, *cend, *ccord; + int nb, bsize; + int datavarid; + int *bidx; + int *tsize, *tssize, *tstart; + int tpos; + MPI_Datatype subarytype; + char *rbuffer, *cbuffer; + MPI_Offset cbsize; + MPI_Offset **starts, **counts; + + // Boundary of chunks involved + cstart = (int*)NCI_Malloc(sizeof(int) * varp->ndim); + ccord = (int*)NCI_Malloc(sizeof(int) * varp->ndim); + cend = (int*)NCI_Malloc(sizeof(int) * varp->ndim); + for(i = 0; i < varp->ndim; i++){ + cstart[i] = start[i] / varp->chunkdim[i]; + if (stride == NULL){ + cend[i] = (start[i] + count[i] - 1) / varp->chunkdim[i]; + } + else{ + cend[i] = (start[i] + (count[i] - 1) * stride[i]) / varp->chunkdim[i] + 1; + } + } + + // Number of chunks involved + nb = 1; + for(i = 0; i < varp->ndim; i++){ + nb *= cend[i] - cstart[i]; + } + + /* Use a varn call to read all compressed chunk involved + * Generate one request for each chunk + */ + + bidx = (int*)NCI_Malloc(sizeof(int) * nb); + starts = (MPI_Offset**)NCI_Malloc(sizeof(MPI_Offset*) * nb); + counts = (MPI_Offset**)NCI_Malloc(sizeof(MPI_Offset*) * nb); + // Iterate through all chunks involved + i = 0; + cbsize = 0; + memcpy(ccord, cstart, sizeof(int) * varp->ndim); + for(i = 0; i < nb; i++){ + j = get_chunk_idx(varp, ccord); + bidx[i] = j; // chunk idx + cbsize += varp->data_lens[j]; // total buffer size of compressed data + starts[i] = varp->chunk_index + j; // start of the chunk + counts[i] = varp->data_lens + j; // count of the chunk + + // move on to next chunk + ccord[varp->ndim - 1]++; + for(j = varp->ndim - 1; j > 0; j--){ + if (ccord[j] >= cend[j]){ + ccord[j - 1]++; + ccord[j] = cstart[j]; + } + } + } + + // Allocate buffers + cbuffer = (char*)NCI_Malloc(cbsize); // Compressed data + + // Locate data var + err = ncchkp->driver->get_var(ncchkp->ncp, varp->varid, NULL, NULL, NULL, NULL, &datavarid, 1, MPI_INT, reqMode); + if (err != NC_NOERR) return err; + + // read compressed data + err = ncchkp->driver->get_varn(ncchkp->ncp, datavarid, nb, starts, counts, cbuffer, cbsize, MPI_BYTE, reqMode); + if (err != NC_NOERR) return err; + + // Decompression + + // Calculate chunk size + // Original datatype + err = ncchkp->driver->get_att(ncchkp->ncp, varp->varid, "_datatype", &xtype, MPI_INT); + if (err != NC_NOERR) return err; + + // Calculate chunk size + bsize = (int)NC_Type_size(xtype); + for(i = 0; i < varp->ndim; i++){ + bsize *= varp->chunkdim[i]; + } + + // Allocate buffers + rbuffer = NCI_Malloc(bsize * nb); // Decompressed data + + // Decompress chunks + cbsize = 0; + for(i = 0; i < nb; i++){ + j = bidx[i]; + if (varp->data_lens[j] > 0){ + varp->filter_driver->decompress(cbuffer + cbsize, varp->data_lens[j], rbuffer + bsize * i, NULL, varp->ndim, varp->dimsize, ncmpii_nc2mpitype(xtype)); + } + else{ + memset(rbuffer + bsize * i, 0, bsize); + } + cbsize += varp->data_lens[j]; // move to next chunk location + } + + // Copy data into user buffer + + // Create datatype of querying domain in the decompressed domain + tsize = NCI_Malloc(sizeof(int) * varp->ndim); + tssize = NCI_Malloc(sizeof(int) * varp->ndim); + tstart = NCI_Malloc(sizeof(int) * varp->ndim); + for(i = 0; i < varp->ndim; i++){ + tsize[i] = (cend[i] - cstart[i]) * varp->chunkdim[i]; + tssize[i] = (int)count[i]; + tstart[i] = start[i] % varp->chunkdim[i]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY(varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, ncmpii_nc2mpitype(xtype), &subarytype); + CHK_ERR_TYPE_COMMIT(&subarytype); + + // Pack data into user buffer + tpos = 0; + CHK_ERR_PACK(rbuffer, bsize * nb, subarytype, buf, bsize * nb, &tpos, ncchkp->comm); + + // Free datatype + MPI_Type_free(&subarytype); + + return NC_NOERR; +} + +int +ncchkioi_put_var_old(NC_chk *ncchkp, + NC_chk_var *varp, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + void *buf) +{ + int i, j, k, err; + nc_type xtype; // Variable data type in NC + MPI_Datatype etype; // Variable element type in MPI + int esize; // Variable element size + int *cstart, *cend, *ccord; // Bounding box for chunks overlapping my own write region + int nb, bsize; //number of chunks this process write to and chunk size + int datavarid; // Id of data variable + int *tsize, *tssize, *tstart; // Size for sub-array type + int nmychunks, *mychunks; // chunk count and id this process handles + int *sendcounts, *sdispls; // Send count and displacements in buffer + int *recvcounts, *rdispls; // Receive count and displacement in buffer + int *packoff; // Offset in mpi packing + int *zipsize, *zdispls; // Compressed count and displacement of my chunks in buffer + int *zsize_local, *zsize_all; // Compressed size of all chunks at local and global (all processes) + int *zdispls_all; // Compressed displacement of all chunks (all processes) + int overlapsize; // Size of overlapping region between a chunk and write region + MPI_Datatype ptype; // Pack datatype + char *zbuf, *xbuf; // Compressed and uncompressed data buffer + char *sbuf, *rbuf; // Send and receive buffer + MPI_Offset **start_all, **count_all, **stride_all; // Start, count, stride of all processes + char name[128]; // Name of objects + int zdimid; // dimension id for compressed data variable + MPI_Offset **zstarts, **zcounts; // Starts and counts in the varn call for compressed data + + // Original datatype and size + err = ncchkp->driver->get_att(ncchkp->ncp, varp->varid, "_datatype", &xtype, MPI_INT); + if (err != NC_NOERR) return err; + esize = NC_Type_size(xtype); + etype = ncmpii_nc2mpitype(xtype); + + // Calculate chunk size + bsize = esize; + for(i = 0; i < varp->ndim; i++){ + bsize *= varp->chunkdim[i]; + } + + // Allocate buffering for overlaping index + tsize = (int*)NCI_Malloc(sizeof(int) * varp->ndim); + tssize = (int*)NCI_Malloc(sizeof(int) * varp->ndim); + tstart = (int*)NCI_Malloc(sizeof(int) * varp->ndim); + + /* + * Gather start, count, stride to all processes + */ + + // Allocate buffer + + start_all = NCI_Malloc(sizeof(MPI_Offset*) * ncchkp->np); + count_all = NCI_Malloc(sizeof(MPI_Offset*) * ncchkp->np); + stride_all = NCI_Malloc(sizeof(MPI_Offset*) * ncchkp->np); + + start_all[0] = NCI_Malloc(sizeof(MPI_Offset) * ncchkp->np * varp->ndim); + count_all[0] = NCI_Malloc(sizeof(MPI_Offset) * ncchkp->np * varp->ndim); + stride_all[0] = NCI_Malloc(sizeof(MPI_Offset) * ncchkp->np * varp->ndim); + + for(i = 1; i < ncchkp->np; i++){ + start_all[i] = start_all[0] + i * varp->ndim; + count_all[i] = count_all[0] + i * varp->ndim; + stride_all[i] = stride_all[0] + i * varp->ndim; + } + + // Call allgather + + err = MPI_Allgather(start, varp->ndim, MPI_LONG_LONG_INT, start_all[0], varp->ndim, MPI_LONG_LONG_INT, ncchkp->comm); + if (err != MPI_SUCCESS){ + err = ncmpii_error_mpi2nc(err, "MPI_Allgather"); + DEBUG_RETURN_ERROR(err); + } + + if (count != NULL){ + err = MPI_Allgather(count, varp->ndim, MPI_LONG_LONG_INT, count_all[0], varp->ndim, MPI_LONG_LONG_INT, ncchkp->comm); + if (err != MPI_SUCCESS){ + err = ncmpii_error_mpi2nc(err, "MPI_Allgather"); + DEBUG_RETURN_ERROR(err); + } + } + + if (stride != NULL){ + err = MPI_Allgather(stride, varp->ndim, MPI_LONG_LONG_INT, stride_all[0], varp->ndim, MPI_LONG_LONG_INT, ncchkp->comm); + if (err != MPI_SUCCESS){ + err = ncmpii_error_mpi2nc(err, "MPI_Allgather"); + DEBUG_RETURN_ERROR(err); + } + } + + /* + * Now, we need to send data to the chunk owner as well as receive data for our own chunk + */ + + // First, compute chunk boundary, find overlapping chunks + cstart = (int*)NCI_Malloc(sizeof(int) * varp->ndim); + ccord = (int*)NCI_Malloc(sizeof(int) * varp->ndim); + cend = (int*)NCI_Malloc(sizeof(int) * varp->ndim); + for(i = 0; i < varp->ndim; i++){ + cstart[i] = start[i] / varp->chunkdim[i]; + if (stride == NULL){ + cend[i] = (start[i] + count[i] - 1) / varp->chunkdim[i] + 1; + } + else{ + cend[i] = (start[i] + (count[i] - 1) * stride[i]) / varp->chunkdim[i] + 1; + } + } + + // Calculate the amount we need to send to other process + sendcounts = (int*)NCI_Malloc(sizeof(int) * ncchkp->np); + sdispls = (int*)NCI_Malloc(sizeof(int) * ncchkp->np); + packoff = (int*)NCI_Malloc(sizeof(int) * ncchkp->np); + memset(sendcounts, 0, sizeof(int) * ncchkp->np); + memset(packoff, 0, sizeof(int) * ncchkp->np); + + // Iterate through all chunks involved to count send size + i = 0; + overlapsize = 0; + memcpy(ccord, cstart, sizeof(int) * varp->ndim); + while(ccord[0] < cend[0]){ + j = varp->chunk_owner[get_chunk_idx(varp, ccord)]; + + // Overlapping size of this chunk + overlapsize = get_chunk_overlap(varp, ccord, start, count, stride, tstart, tssize); + sendcounts[j] += overlapsize; + + // move on to next chunk + ccord[varp->ndim - 1]++; + for(j = varp->ndim - 1; j > 0; j--){ + if (ccord[j] >= cend[j]){ + ccord[j - 1]++; + ccord[j] = cstart[j]; + } + } + } + + // Buffer displacement + sdispls[0] = 0; + for(i = 1; i < ncchkp->np; i++){ + sdispls[i] = sendcounts[i - 1] + sdispls[i - 1]; + } + + // Allocate send buffer + sbuf = (char*)NCI_Malloc(sdispls[ncchkp->np - 1] + sendcounts[ncchkp->np - 1]); + + // Pack data into send buffer + + // Iterate through all chunks involved again, this time actually pack the data + for(i = 0; i < varp->ndim; i++){ + tsize[i] = (int)count[i]; + } + i = 0; + overlapsize = 0; + memcpy(ccord, cstart, sizeof(int) * varp->ndim); + while(ccord[0] < cend[0]){ + j = varp->chunk_owner[get_chunk_idx(varp, ccord)]; + + // Overlapping region of this chunk + get_chunk_overlap(varp, ccord, start, count, stride, tstart, tssize); + for(k = 0; k < varp->ndim; k++){ + tstart[k] -= (int)start[k]; + } + + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY(varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, ncmpii_nc2mpitype(xtype), &ptype); + CHK_ERR_TYPE_COMMIT(&ptype); + + // Pack data + CHK_ERR_PACK(buf, 1, ptype, sbuf + sdispls[j], sendcounts[j], packoff + j, ncchkp->comm); + + // Free datatype + MPI_Type_free(&ptype); + + // move on to next chunk + ccord[varp->ndim - 1]++; + for(j = varp->ndim - 1; j > 0; j--){ + if (ccord[j] >= cend[j]){ + ccord[j - 1]++; + ccord[j] = cstart[j]; + } + } + } + + /* + * Determine chunk ownership + * Find my chunks + */ + nmychunks = 0; + for(i = 0; i < varp->nchunk; i++){ + if (varp->chunk_owner[i] == ncchkp->rank){ + nmychunks++; + } + } + + // Gather chunk id this process handled to prevent a search in the future + mychunks = (int*)NCI_Malloc(sizeof(int) * nmychunks); + nmychunks = 0; + for(i = 0; i < varp->nchunk; i++){ + if (varp->chunk_owner[i] == ncchkp->rank){ + mychunks[nmychunks] = i; + nmychunks++; + } + } + + /* + * Compute size to receive + * We only need size here, packing will happen after receving + */ + + // Calculate the amount we need to receive from other process + recvcounts = (int*)NCI_Malloc(sizeof(int) * ncchkp->np); + rdispls = (int*)NCI_Malloc(sizeof(int) * ncchkp->np); + memset(recvcounts, 0, sizeof(int) * ncchkp->np); + memset(packoff, 0, sizeof(int) * ncchkp->np); + for(i = 0; i < varp->nchunk; i++){ + if (varp->chunk_owner[i] == ncchkp->rank){ + get_chunk_cord(varp, i, ccord); + + for(j = 0; j < ncchkp->np; j++){ + // Overlapping region of this chunk + get_chunk_overlap(varp, ccord, start_all[j], count_all[j], stride_all[j], tstart, tssize); + + overlapsize = esize; + for(k = 0; k < varp->ndim; k++){ + overlapsize *= tssize[k]; + } + recvcounts[j] += overlapsize; + } + } + } + + // Buffer displacement + rdispls[0] = 0; + for(i = 1; i < ncchkp->np; i++){ + rdispls[i] = recvcounts[i - 1] + rdispls[i - 1]; + } + + // Allocate receive buffer + rbuf = (char*)NCI_Malloc(rdispls[ncchkp->np - 1] + recvcounts[ncchkp->np - 1]); + + // Send the data to destination + MPI_Alltoallv(sbuf, sendcounts, sdispls, MPI_BYTE, rbuf, recvcounts, rdispls, MPI_BYTE, ncchkp->comm); + +/* +#ifdef PNETCDF_DEBUG + if (ncchkp->rank == 0){ + printf("Rank %d: sendcount = {", ncchkp->rank); + for(i = 0; i < ncchkp->np; i++){ + printf("%d, ", sendcounts[i]); + } + printf("}, sdispls = {"); + for(i = 0; i < ncchkp->np; i++){ + printf("%d, ", sdispls[i]); + } + printf("}, recvcounts = {"); + for(i = 0; i < ncchkp->np; i++){ + printf("%d, ", recvcounts[i]); + } + printf("}, rdispls = {"); + for(i = 0; i < ncchkp->np; i++){ + printf("%d, ", rdispls[i]); + } + printf("}, sbuf = {"); + for(i = 0; i < sdispls[ncchkp->np - 1] + sendcounts[ncchkp->np - 1]; i++){ + printf("%x ", sbuf[i]); + } + printf("}, rbuf = {"); + for(i = 0; i < rdispls[ncchkp->np - 1] + recvcounts[ncchkp->np - 1]; i++){ + printf("%x ", rbuf[i]); + } + printf("}\n"); + fflush(stdout); + } +#endif +*/ + + /* + * Next step is to pack data to chunk buffer + */ + + // Allocate buffer + xbuf = (char*)NCI_Malloc(nmychunks * bsize); + + // Main array is the whole chunk + for(i = 0; i < varp->ndim; i++){ + tsize[i] = varp->chunkdim[i]; + } + + // Pack data + memset(packoff, 0, sizeof(int) * ncchkp->np); + for(i = 0; i < nmychunks; i++){ + get_chunk_cord(varp, mychunks[i], ccord); + + for(j = 0; j < ncchkp->np; j++){ + // Overlapping region of this chunk + overlapsize = get_chunk_overlap(varp, ccord, start_all[j], count_all[j], stride_all[j], tstart, tssize); + + if (overlapsize > 0){ + // Overlap size + //overlapsize = esize; + //for(k = 0; k < varp->ndim; k++){ + // overlapsize *= tssize[k]; + //} + + // The chunk is the main array, overlapping region is the subarray + for(k = 0; k < varp->ndim; k++){ + tstart[k] -= ccord[k] * varp->chunkdim[k]; + } + + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY(varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, ncmpii_nc2mpitype(xtype), &ptype); + CHK_ERR_TYPE_COMMIT(&ptype); + + // Pack data + CHK_ERR_UNPACK(rbuf + rdispls[j], overlapsize, packoff + j, xbuf + bsize * i, 1, ptype, ncchkp->comm); + + // Free datatype + MPI_Type_free(&ptype); + } + } + } + +/* +#ifdef PNETCDF_DEBUG + if (ncchkp->rank == 0){ + printf("Rank %d: xbuf = {", ncchkp->rank); + for(i = 0; i < nmychunks * bsize; i++){ + printf("%x ", xbuf[i]); + } + printf("}\n"); + fflush(stdout); + } +#endif +*/ + + /* + * The buffer is now filled with data coming from all processes, it's time to compress + */ + + // compressed size and displacement + zipsize = (int*)NCI_Malloc(sizeof(int) * nmychunks); + zdispls = (int*)NCI_Malloc(sizeof(int) * (nmychunks + 1)); + memset(zipsize, 0, sizeof(int) * nmychunks); + memset(zdispls, 0, sizeof(int) * (nmychunks + 1)); + + // Calculate compressed data size + for(i = 0; i < nmychunks; i++){ + // Calculate compressed size + // This is just estimate + varp->filter_driver->compress(xbuf + bsize * i, bsize, NULL, zipsize + i, varp->ndim, varp->chunkdim, etype); + } + + // Calculate total size + for(i = 1; i < nmychunks; i++){ + zdispls[0] += zipsize[i]; + } + + // Allocate buffer + zbuf = (char*)NCI_Malloc(zdispls[0]); + + // Perform real compression + for(i = 0; i < nmychunks; i++){ + // Compressed the data + // We get real size here + varp->filter_driver->compress(xbuf + bsize * i, bsize, zbuf + zdispls[i], zipsize + i, varp->ndim, varp->chunkdim, etype); + + // Calculate offset + zdispls[i + 1] = zdispls[i] + zipsize[i]; + } + +/* +#ifdef PNETCDF_DEBUG + if (ncchkp->rank == 0){ + printf("Rank %d: zipsize = {", ncchkp->rank); + for(i = 0; i < nmychunks; i++){ + printf("%x ", zipsize[i]); + } + printf("}, zdispls = {"); + for(i = 0; i < nmychunks; i++){ + printf("%d, ", zdispls[i]); + } + printf("}, zbuf = {"); + for(i = 0; i < zdispls[nmychunks- 1] + zipsize[nmychunks - 1]; i++){ + printf("%x ", zbuf[i]); + } + printf("}\n"); + fflush(stdout); + } +#endif +*/ + + /* + * Now it is time for a collective write + * We start by syncing compressed size on all processes + * Then, we can create variable large enough to store compressed data + * Finally, we do collective write to store the data + */ + + // First sync on compressed chunk size + // We use a all MAX reduce on all chunks + // An alternative is to allgather and unpack the info + + // Allocate buffer + zsize_local = (int*)NCI_Malloc(sizeof(int) * varp->nchunk); + zsize_all = (int*)NCI_Malloc(sizeof(int) * varp->nchunk); + zdispls_all = (int*)NCI_Malloc(sizeof(int) * varp->nchunk); + memset(zsize_local, 0, sizeof(int) * varp->nchunk); + memset(zsize_all, 0, sizeof(int) * varp->nchunk); + memset(zdispls_all, 0, sizeof(int) * varp->nchunk); + + // Fill up local size + for(i = 0; i < nmychunks; i++){ + zsize_local[mychunks[i]] = zipsize[i]; + } + + // All reduce + CHK_ERR_ALLREDUCE(zsize_local, zsize_all, varp->nchunk, MPI_INT, MPI_MAX, ncchkp->comm); + + // Calculate variable displacement + zdispls_all[0] = 0; + for(i = 1; i < varp->nchunk; i++){ + zdispls_all[i] = zsize_all[i - 1] + zdispls_all[i - 1]; + } + +/* +#ifdef PNETCDF_DEBUG + if (ncchkp->rank == 0){ + printf("Rank %d: zsize_all = {", ncchkp->rank); + for(i = 0; i < varp->nchunk; i++){ + printf("%x ", zsize_all[i]); + } + printf("}, zdispls_all = {"); + for(i = 0; i < varp->nchunk; i++){ + printf("%d, ", zdispls_all[i]); + } + printf("}, varid = { %d", varp->varid); + printf("}, datavarid = { %d", varp->datavarid); + printf("}\n"); + fflush(stdout); + } +#endif +*/ + + // Enter redefine mode + ncchkp->driver->redef(ncchkp->ncp); + + // Define dimension for data variable + sprintf(name, "_compressed_data_dim_%d", varp->varid); + err = ncchkp->driver->def_dim(ncchkp->ncp, name, zdispls_all[varp->nchunk - 1] + zsize_all[varp->nchunk - 1], &zdimid); + if (err != NC_NOERR) return err; + + // Define variable + sprintf(name, "_compressed_data_%d", varp->varid); + err = ncchkp->driver->def_var(ncchkp->ncp, name, NC_BYTE, 1, &zdimid, &(varp->datavarid)); + if (err != NC_NOERR) return err; + + // Record offset in data variable + err = ncchkp->driver->put_att(ncchkp->ncp, varp->varid, "_chunkoffset", NC_INT, varp->nchunk, zdispls_all, MPI_INT); // Original datatype + if (err != NC_NOERR) return err; + + // Switch to data mode + err = ncchkp->driver->enddef(ncchkp->ncp); + if (err != NC_NOERR) return err; + + //Now, we generate a varn call to write out compressed data + zstarts = (MPI_Offset**)NCI_Malloc(sizeof(MPI_Offset*) * nmychunks); + zcounts = (MPI_Offset**)NCI_Malloc(sizeof(MPI_Offset*) * nmychunks); + zstarts[0] = (MPI_Offset*)NCI_Malloc(sizeof(MPI_Offset) * nmychunks); + zcounts[0] = (MPI_Offset*)NCI_Malloc(sizeof(MPI_Offset) * nmychunks); + for(i = 0; i < nmychunks; i++){ + zstarts[i] = zstarts[0] + i; + zcounts[i] = zcounts[0] + i; + zstarts[i][0] = zdispls_all[mychunks[i]]; + zcounts[i][0] = zsize_all[mychunks[i]]; + } + err = ncchkp->driver->put_varn(ncchkp->ncp, varp->datavarid, nmychunks, zstarts, zcounts, zbuf, zdispls[nmychunks - 1] + zipsize[nmychunks - 1], MPI_UNSIGNED_CHAR, NC_REQ_WR | NC_REQ_BLK | NC_REQ_FLEX | NC_REQ_COLL); + if (err != NC_NOERR) return err; + + // Record datavar id + err = ncchkp->driver->put_var(ncchkp->ncp, varp->varid, NULL, NULL, NULL, NULL, &(varp->datavarid), 1, MPI_INT, NC_REQ_WR | NC_REQ_BLK | NC_REQ_FLEX | NC_REQ_COLL); + if (err != NC_NOERR) return err; + + // Free up buffers + NCI_Free(cstart); + NCI_Free(cend); + NCI_Free(ccord); + NCI_Free(tsize); + NCI_Free(tssize); + NCI_Free(tstart); + NCI_Free(mychunks); + NCI_Free(sendcounts); + NCI_Free(sdispls); + NCI_Free(recvcounts); + NCI_Free(rdispls); + NCI_Free(packoff); + NCI_Free(zipsize); + NCI_Free(zdispls); + NCI_Free(zsize_local); + NCI_Free(zsize_all); + NCI_Free(zdispls_all); + NCI_Free(zbuf); + NCI_Free(xbuf); + NCI_Free(sbuf); + NCI_Free(rbuf); + NCI_Free(start_all[0]); + NCI_Free(count_all[0]); + NCI_Free(stride_all[0]); + NCI_Free(start_all); + NCI_Free(count_all); + NCI_Free(stride_all); + NCI_Free(zstarts[0]); + NCI_Free(zcounts[0]); + NCI_Free(zstarts); + NCI_Free(zcounts); + + return NC_NOERR; +} + +void profile(){ + /* Profiling information */ + ncchkp->profile.total_data += t9 - t0; + ncchkp->profile.total_meta += t9 - t0; + ncchkp->profile.max_buffer += t9 - t0; + ncchkp->profile.total_time += t9 - t0; + ncchkp->profile.cb_time += t9 - t0; + ncchkp->profile.io_time += t9 - t0; + + ncchkp->profile.cb_init_time += t9 - t0; // Calculate number of req + ncchkp->profile.cb_sync_time += t9 - t0; // Syncing number of req + ncchkp->profile.cb_pack_req_time += t9 - t0; // Pack request and reply + ncchkp->profile.cb_pack_rep_time += t9 - t0; // Pack request and reply + ncchkp->profile.cb_unpack_req_time += t9 - t0; // Unpack incoming request + ncchkp->profile.cb_unpack_rep_time += t9 - t0; // Unpack incoming request + ncchkp->profile.cb_send_req_time += t9 - t0; // Posting and waiting send + ncchkp->profile.cb_send_rep_time += t9 - t0; // Posting and waiting send + ncchkp->profile.cb_recv_req_time += t9 - t0; // Time posting and waiting recv + ncchkp->profile.cb_recv_rep_time += t9 - t0; // Time posting and waiting recv + ncchkp->profile.cb_self_time += t9 - t0; // Time handling our own data + + ncchkp->profile.io_wr_time += t9 - t0; + ncchkp->profile.io_rd_time += t9 - t0; + ncchkp->profile.io_com_time += t9 - t0; + ncchkp->profile.io_decom_time += t9 - t0; + ncchkp->profile.io_sync_time += t9 - t0; +} \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkioi_lists.c b/src/drivers/ncchunkio/ncchkioi_lists.c new file mode 100644 index 000000000..537eec4ed --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_lists.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include "ncchkio_internal.h" + +int ncchkioi_var_list_init(NC_chk_var_list *list) { + list->cnt = 0; + list->nalloc = 0; + return NC_NOERR; +} + +int ncchkioi_var_list_free(NC_chk_var_list *list) { + int i, j; + if (list->nalloc > 0){ + for(i = 0; i < list->cnt; i++){ + ncchkioi_var_free(list->data + i); + } + NCI_Free(list->data); + } + return NC_NOERR; +} + +int ncchkioi_var_list_add(NC_chk_var_list *list) { + if (list->nalloc == 0){ + list->nalloc = 16; + list->data = NCI_Malloc(list->nalloc * sizeof(NC_chk_var)); + CHK_ALLOC(list->data) + } + else if (list->nalloc == list->cnt){ + list->nalloc *= 2; + list->data = NCI_Realloc(list->data, list->nalloc * sizeof(NC_chk_var)); + CHK_ALLOC(list->data) + } + + return ((list->cnt)++); +} diff --git a/src/drivers/ncchunkio/ncchkioi_nonblocking.c b/src/drivers/ncchunkio/ncchkioi_nonblocking.c new file mode 100644 index 000000000..8e994ef1b --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_nonblocking.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2017, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define PUT_ARRAY_SIZE 128 /* Size of initial put list */ +#define SIZE_MULTIPLIER 2 /* When metadata buffer is full, we'll NCI_Reallocate it to META_BUFFER_MULTIPLIER times the original size*/ + +/* getlist is a module in ADIOS driver that manage nonblocking get request object + * It consist of a pool of request object (reqs) and request ids (ids) + * It's implemented by 3 array of the same number of entries + * The id i corresponds to the i-th request object + * We issue request object by issuing the corresponding request id + * ids is initialized with increasing id, ie. ids[i] = i + * ids are issued from the begining of ids array + * We keep track of location of id in ids array in pos array. Initially, pos[i] = i + * A pointer nused keep track of issued ids, it also marks the position of next unused ready to be issued + * ids[0:nused] => active (used) request ids + * ids[nused:nalloc] => available (unused) request ids + * When issuing an id, we take from ids from the position marked by nused and increase nused by 1 + * When recycling an id, we swap if with the right before position marked by nused and decrease nused by 1 so that it falls to unused pool + * NOTE: We does not guarantee to issue id in continuous and increasing order + * NOTE: ids is simply a pool housing reqeust ids, the position od id within ids is not fixed and has no meaning + * + * Eaxmple: + * Initial: + * ids = 0 1 2 3 + * ^ + * nused = 0 + * After issuing 2 ids: + * undefined|Avaiable ids ---> + * ids = 0 1 2 3 + * ^ + * nused = 2 + * Recycling id 0 + * |Avaiable ids ---> + * ids = 1 0 2 3 + * ^ + * nused = 1 +* Recycling id 1 + * |Avaiable ids ---> + * ids = 1 0 2 3 + * ^ + * nused = 0 + */ + +/* + * Initialize the put list + * ids[0:nused] => active (used) request ids + * ids[nused:nalloc] => available (unused) request ids + */ +int ncchkioi_req_list_init(NC_chk_req_list *lp) { + int err=NC_NOERR; + int i; + + /* Initialize parameter and allocate the array */ + lp->nused = 0; + lp->nalloc = PUT_ARRAY_SIZE; + lp->reqs = (NC_chk_req*)NCI_Malloc(lp->nalloc * sizeof(NC_chk_req)); + lp->ids = (int*)NCI_Malloc(lp->nalloc * SIZEOF_INT); + CHK_PTR(lp->ids) + lp->pos = (int*)NCI_Malloc(lp->nalloc * SIZEOF_INT); + CHK_PTR(lp->pos) + if (lp->reqs == NULL || lp->ids == NULL) { + DEBUG_RETURN_ERROR(NC_ENOMEM); + } + + /* Initialize values of ids and reqs + * Assign increasing unique id + */ + for (i=0; inalloc; i++) { + lp->ids[i] = i; // Unique ids + lp->pos[i] = i; // Not in use + } + +err_out:; + return err; +} + +/* + * Enlarge the put list + * When there are no more unused ids to issue, we must add more ids to the pool + * We simply enlarge ids and reqs array + * We initialize the extended part as usual + */ +static int ncchkioi_req_list_resize(NC_chk_req_list *lp) +{ + int i; + size_t nsize; + void *ptr; + + /* Calculate new size */ + nsize = lp->nalloc * SIZE_MULTIPLIER; + + /* Realloc reqs and ids */ + ptr = NCI_Realloc(lp->reqs, nsize * sizeof(NC_chk_req)); + if (ptr == NULL) DEBUG_RETURN_ERROR(NC_ENOMEM); + lp->reqs = (NC_chk_req*)ptr; + + ptr = NCI_Realloc(lp->ids, nsize * SIZEOF_INT); + if (ptr == NULL) DEBUG_RETURN_ERROR(NC_ENOMEM); + lp->ids = (int*)ptr; + + ptr = NCI_Realloc(lp->pos, nsize * SIZEOF_INT); + if (ptr == NULL) DEBUG_RETURN_ERROR(NC_ENOMEM); + lp->pos = (int*)ptr; + + /* Initialize values of ids and reqs + * Assign increasing unique id + */ + for (i=lp->nalloc; iids[i] = i; // Unique ids + lp->pos[i] = i; // Default position + } + + lp->nalloc = nsize; + + return NC_NOERR; +} + +/* + * Clean up the put list + */ +int ncchkioi_req_list_free(NC_chk_req_list *lp) +{ + NCI_Free(lp->reqs); + NCI_Free(lp->ids); + NCI_Free(lp->pos); + + return NC_NOERR; +} + +/* + * Allocate a new request object from the getlist with id + * We first check if there are unused ids + * We increase the size of pool, bringing in new ids if there aren't + * Then we issue the ids at position nused and increase it by 1 + */ +int ncchkioi_req_list_add(NC_chk_req_list *lp, int *id) +{ + int err; + + /* Increase size if necessary */ + if (lp->nused == lp->nalloc) { + err = ncchkioi_req_list_resize(lp); + if (err != NC_NOERR) return err; + } + + /* Get the first unused id marked by nused */ + *id = lp->ids[lp->nused++]; + + return NC_NOERR; +} + +/* + * Recycle a request object in the put list + * We need to maintain the position of each request id in the ids list + * ids[0:nused] => active (used) request ids + * ids[nused:nalloc] => available (unused) request ids + */ +int ncchkioi_req_list_remove(NC_chk_req_list *lp, int reqid) { + NC_chk_req * req = lp->reqs + reqid; + + /* Clean up request */ + if (req->start != NULL){ + NCI_Free(req->start); + } + if (req->count != NULL){ + NCI_Free(req->count); + } + if (req->starts != NULL){ + NCI_Free(req->starts); + } + if (req->counts != NULL){ + NCI_Free(req->counts); + } + if (req->stride != NULL){ + NCI_Free(req->stride); + } + if (req->xbufs != NULL){ + NCI_Free(req->xbufs); + } + if (req->xbuf != req->buf){ + NCI_Free(req->xbuf); + } + + /* Return id to the list */ + lp->nused--; + lp->ids[lp->pos[reqid]] = lp->ids[lp->nused]; + lp->pos[lp->ids[lp->nused]] = lp->pos[reqid]; + lp->ids[lp->nused] = reqid; + lp->pos[reqid] = lp->nused; + + return NC_NOERR; +} diff --git a/src/drivers/ncchunkio/ncchkioi_profile.m4 b/src/drivers/ncchunkio/ncchkioi_profile.m4 new file mode 100644 index 000000000..aab69b38c --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_profile.m4 @@ -0,0 +1,98 @@ +dnl Process this m4 file to produce 'C' language file. +dnl +dnl If you see this line, you can ignore the next one. +/* Do not edit this file. It is produced from the corresponding .m4 source */ +dnl +/* + * Copyright (C) 2021, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ +dnl +include(`foreach.m4')`'dnl +include(`foreach_idx.m4')`'dnl +include(`list_len.m4')`'dnl +include(`utils.m4')`'dnl +include(`ncchkioi_profile_timers.m4')`'dnl +define(`upcase', `translit(`$*', `a-z', `A-Z')')`'dnl +define(`CONCATE',`$1$2')`'dnl +changecom(`##', `')`'dnl +dnl +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "ncchkio_internal.h" +#include "ncchkioi_profile.h" + +/* + * Report performance profiling + */ +#ifdef PNETCDF_PROFILING + +static double tmax[NC_CHK_NTIMER], tmin[NC_CHK_NTIMER], tmean[NC_CHK_NTIMER], tvar[NC_CHK_NTIMER], tvar_local[NC_CHK_NTIMER]; + +const char * const tname[NC_CHK_NTIMER]={ +foreach(`t', NC_CHK_TIMERS, `"CONCATE(`nc_chk_timer_', t)", +')dnl +}; + +void ncchkioi_profile_add_time (NC_chk *ncchkp, int id, double t) { + assert (id >= 0 && id < NC_CHK_NTIMER); + ncchkp->profile.tt[id] += t; + ncchkp->profile.cnt[id]++; +} + +int ncchkioi_print_profile(NC_chk *ncchkp){ + int i; + + MPI_Reduce (ncchkp->profile.tt, tmax, NC_CHK_NTIMER, MPI_DOUBLE, MPI_MAX, 0, ncchkp->comm); + MPI_Reduce (ncchkp->profile.tt, tmin, NC_CHK_NTIMER, MPI_DOUBLE, MPI_MIN, 0, ncchkp->comm); + MPI_Allreduce (ncchkp->profile.tt, tmean, NC_CHK_NTIMER, MPI_DOUBLE, MPI_SUM, ncchkp->comm); + for (i = 0; i < NC_CHK_NTIMER; i++) { + tmean[i] /= ncchkp->np; + tvar_local[i] = (ncchkp->profile.tt[i] - tmean[i]) * (ncchkp->profile.tt[i] - tmean[i]); + } + MPI_Reduce (tvar_local, tvar, NC_CHK_NTIMER, MPI_DOUBLE, MPI_SUM, 0, ncchkp->comm); + + if (ncchkp->rank == 0) { + for (i = 0; i < NC_CHK_NTIMER; i++) { + printf ("#%%$: %s_time_mean: %lf\n", tname[i], tmean[i]); + printf ("#%%$: %s_time_max: %lf\n", tname[i], tmax[i]); + printf ("#%%$: %s_time_min: %lf\n", tname[i], tmin[i]); + printf ("#%%$: %s_time_var: %lf\n\n", tname[i], tvar[i]); + } + } + + MPI_Reduce (ncchkp->profile.cnt, tmax, NC_CHK_NTIMER, MPI_DOUBLE, MPI_MAX, 0, ncchkp->comm); + MPI_Reduce (ncchkp->profile.cnt, tmin, NC_CHK_NTIMER, MPI_DOUBLE, MPI_MIN, 0, ncchkp->comm); + MPI_Allreduce (ncchkp->profile.cnt, tmean, NC_CHK_NTIMER, MPI_DOUBLE, MPI_SUM, ncchkp->comm); + for (i = 0; i < NC_CHK_NTIMER; i++) { + tmean[i] /= ncchkp->np; + tvar_local[i] = (ncchkp->profile.cnt[i] - tmean[i]) * (ncchkp->profile.cnt[i] - tmean[i]); + } + MPI_Reduce (tvar_local, tvar, NC_CHK_NTIMER, MPI_DOUBLE, MPI_SUM, 0, ncchkp->comm); + + if (ncchkp->rank == 0) { + for (i = 0; i < NC_CHK_NTIMER; i++) { + printf ("#%%$: %s_count_mean: %lf\n", tname[i], tmean[i]); + printf ("#%%$: %s_count_max: %lf\n", tname[i], tmax[i]); + printf ("#%%$: %s_count_min: %lf\n", tname[i], tmin[i]); + printf ("#%%$: %s_count_var: %lf\n\n", tname[i], tvar[i]); + } + } +} +#endif + + + + diff --git a/src/drivers/ncchunkio/ncchkioi_profile.m4h b/src/drivers/ncchunkio/ncchkioi_profile.m4h new file mode 100644 index 000000000..a07fbb0f2 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_profile.m4h @@ -0,0 +1,75 @@ +dnl Process this m4 file to produce 'C' language file. +dnl +dnl If you see this line, you can ignore the next one. +/* Do not edit this file. It is produced from the corresponding .m4 source */ +dnl +/* + * Copyright (C) 2021, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ +dnl +include(`foreach.m4')`'dnl +include(`foreach_idx.m4')`'dnl +include(`list_len.m4')`'dnl +include(`utils.m4')`'dnl +include(`ncchkioi_profile_timers.m4')`'dnl +define(`upcase', `translit(`$*', `a-z', `A-Z')')`'dnl +define(`CONCATE',`$1$2')`'dnl +changecom(`##', `')`'dnl +dnl +#pragma once + +#ifdef HAVE_CONFIG_H +#include +#endif + +/* + * Report performance profiling + */ +#ifdef PNETCDF_PROFILING + +#define NC_CHK_NTIMER list_len(NC_CHK_TIMERS) + +foreach_idx(`t', `i', NC_CHK_TIMERS, `#define CONCATE(`NC_CHK_TIMER_', upcase(t)) i +')dnl + +#define NC_CHK_TIMER_START(A) ncchkp->profile.st[A] = MPI_Wtime(); +#define NC_CHK_TIMER_PAUSE(A) { \ + ncchkp->profile.tt[A] += MPI_Wtime() - ncchkp->profile.st[A]; \ +} +#define NC_CHK_TIMER_STOP(A) { \ + NC_CHK_TIMER_PAUSE(A) \ + ncchkp->profile.cnt[A] ++; \ +} +#define NC_CHK_TIMER_SWAP(A, B) { \ + double tmp = MPI_Wtime(); \ + ncchkp->profile.tt[A] += tmp - ncchkp->profile.st[A]; \ + ncchkp->profile.cnt[A] ++; \ + ncchkp->profile.st[B] = tmp; \ +} +#define NC_CHK_TIMER_STOPEX(A, B) { \ + double tmp = MPI_Wtime(); \ + ncchkp->profile.tt[A] += tmp - ncchkp->profile.st[A]; \ + ncchkp->profile.cnt[A] ++; \ + ncchkp->profile.tt[B] -= tmp - ncchkp->profile.st[A]; \ +} + +dnl +typedef struct NC_chk_timers { + /* Profiling information */ + double st[NC_CHK_NTIMER]; + double tt[NC_CHK_NTIMER]; + double cnt[NC_CHK_NTIMER]; +} NC_chk_timers; + +#else + +#define NC_CHK_TIMER_START(A) +#define NC_CHK_TIMER_STOP(A) +#define NC_CHK_TIMER_PAUSE(A) +#define NC_CHK_TIMER_SWAP(A, B) +#define NC_CHK_TIMER_STOPEX(A, B) + +#endif + diff --git a/src/drivers/ncchunkio/ncchkioi_profile_timers.m4 b/src/drivers/ncchunkio/ncchkioi_profile_timers.m4 new file mode 100644 index 000000000..27652837b --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_profile_timers.m4 @@ -0,0 +1,73 @@ +define(`NC_CHK_TIMERS', `( `total', dnl + `var_init', dnl + `var_init_meta', dnl + `var_init_csize', dnl + `var_init_cown', dnl + `var_resize', dnl + `put', dnl + `put_cb', dnl + `put_cb_init', dnl + `put_cb_sync', dnl + `put_cb_pack_req', dnl + `put_cb_pack_rep', dnl + `put_cb_unpack_req', dnl + `put_cb_unpack_rep', dnl + `put_cb_send_req', dnl + `put_cb_send_rep', dnl + `put_cb_recv_req', dnl + `put_cb_recv_rep', dnl + `put_cb_self', dnl + `put_cb_barr', dnl + `put_bg', dnl + `put_bg_init', dnl + `put_bg_cache', dnl + `put_bg_rd', dnl + `put_bg_decom', dnl + `put_io', dnl + `put_io_init', dnl + `put_io_com', dnl + `put_io_sync', dnl + `put_io_wr', dnl + `put_io_barr', dnl + `get', dnl + `get_resize', dnl + `get_cb', dnl + `get_cb_init', dnl + `get_cb_sync', dnl + `get_cb_pack_req', dnl + `get_cb_pack_rep', dnl + `get_cb_unpack_req', dnl + `get_cb_unpack_rep', dnl + `get_cb_send_req', dnl + `get_cb_send_rep', dnl + `get_cb_recv_req', dnl + `get_cb_recv_rep', dnl + `get_cb_self', dnl + `get_cb_barr', dnl + `get_io', dnl + `get_io_init', dnl + `get_io_cache', dnl + `get_io_rd', dnl + `get_io_decom', dnl + `get_convert', dnl + `finalize', dnl + `finalize_meta', dnl + `iput', dnl + `iget', dnl + `wait', dnl + `wait_put', dnl + `wait_put_barr', dnl + `wait_get', dnl + `put_size', dnl + `get_size', dnl + `send_size', dnl + `recv_size', dnl + `nsend', dnl + `nrecv', dnl + `nremote', dnl + `nreq', dnl + `nlocal', dnl + `nchunk', dnl + `var_size', dnl + `var_zsize', dnl +)')`'dnl \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkioi_put_var.c b/src/drivers/ncchunkio/ncchkioi_put_var.c new file mode 100644 index 000000000..45623e320 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_put_var.c @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ncchkio_internal.h" + +int ncchkioi_put_var_cb_chunk (NC_chk *ncchkp, + NC_chk_var *varp, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + void *buf) { + int err = NC_NOERR; + int i, j, k; + int cid; // Chunk iterator + + MPI_Offset *ostart, *osize; + int *tsize, *tssize, *tstart, *tsizep, *tstartp; // Size for sub-array type + MPI_Offset *citr; + + int *wcnt_local, *wcnt_all; // Number of processes that writes to each chunk + + int nread; // Chunks to read for background + int *rids; + + int overlapsize; // Size of overlaping region of request and chunk + int max_tbuf = 0; // Size of intermediate buffer + char *tbuf = NULL; // Intermediate buffer + + int packoff; // Pack offset + MPI_Datatype ptype; // Pack datatype + + int nsend, nrecv; // Number of send and receive + MPI_Request *sreqs, *rreqs; // Send and recv req + MPI_Status *sstats, *rstats; // Send and recv status + char **sbufs, **rbufs; // Send and recv buffer + int *rsizes; // recv size of each message + MPI_Message rmsg; // Receive message + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_INIT) + + // Allocate buffering for write count + wcnt_local = (int *)NCI_Malloc (sizeof (int) * varp->nchunk * 2); + wcnt_all = wcnt_local + varp->nchunk; + + // Allocate buffering for overlaping index + tstart = (int *)NCI_Malloc (sizeof (int) * varp->ndim * 3); + tsize = tstart + varp->ndim; + tssize = tsize + varp->ndim; + ostart = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim * 3); + osize = ostart + varp->ndim; + + // Chunk iterator + citr = osize + varp->ndim; + + // We need to calculate the size of message of each chunk + // This is just for allocating send buffer + // We do so by iterating through all request and all chunks they cover + // If we are not the owner of a chunk, we need to send message + memset (wcnt_local, 0, sizeof (int) * varp->nchunk); + nsend = 0; + + // Iterate through chunks + ncchkioi_chunk_itr_init (varp, start, count, citr, &cid); // Initialize chunk iterator + do { + if (varp->chunk_owner[cid] != ncchkp->rank) { + // Count number of mnessage we need to send + nsend++; + wcnt_local[cid] = 1; + } else { + // We mark covered chunk of our own to prevent unnecessary calculation of overlap + // -1 is purely a mark, we need to add 1 back to global message count + wcnt_local[cid] = -1; + max_tbuf = varp->chunksize; + } + } while (ncchkioi_chunk_itr_next (varp, start, count, citr, &cid)); + + // Allocate buffer for sending + sbufs = (char **)NCI_Malloc (sizeof (char *) * nsend); + sreqs = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * nsend); + sstats = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * nsend); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SYNC) + + // Sync number of messages of each chunk + CHK_ERR_ALLREDUCE (wcnt_local, wcnt_all, varp->nchunk, MPI_INT, MPI_SUM, ncchkp->comm); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SYNC) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_PACK_REQ) + + // Calculate number of recv request + // This is for all the chunks + nrecv = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + // We don't need message for our own data + nrecv += wcnt_all[cid] - wcnt_local[cid]; + } + rreqs = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * nrecv); + rstats = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * nrecv); + rbufs = (char **)NCI_Malloc (sizeof (char *) * nrecv); + rsizes = (int *)NCI_Malloc (sizeof (int) * nrecv); + + // Post send + nsend = 0; + // Iterate through chunks + ncchkioi_chunk_itr_init_ex (varp, start, count, citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // We got something to send if we are not owner + if (varp->chunk_owner[cid] != ncchkp->rank) { + // Calculate chunk overlap + overlapsize = varp->esize; + for (j = 0; j < varp->ndim; j++) { overlapsize *= osize[j]; } + + // Allocate buffer + sbufs[nsend] = (char *)NCI_Malloc (overlapsize + sizeof (int) * varp->ndim * 2); + + // Metadata + packoff = 0; + tstartp = (int *)sbufs[nsend]; + packoff += varp->ndim * sizeof (int); + tsizep = (int *)(sbufs[nsend] + packoff); + packoff += varp->ndim * sizeof (int); + for (j = 0; j < varp->ndim; j++) { + tstartp[j] = (int)(ostart[j] - citr[j]); + tsizep[j] = (int)osize[j]; + } + + // Pack type + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - start[j]); + tsize[j] = (int)count[j]; + tssize[j] = (int)osize[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data + CHK_ERR_PACK (buf, 1, ptype, sbufs[nsend], packoff + overlapsize, &packoff, + ncchkp->comm); + + MPI_Type_free (&ptype); + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SEND_REQ) + + // Send the request + CHK_ERR_ISEND (sbufs[nsend], packoff, MPI_BYTE, varp->chunk_owner[cid], cid, + ncchkp->comm, sreqs + nsend); + + NC_CHK_TIMER_STOPEX (NC_CHK_TIMER_PUT_CB_SEND_REQ, NC_CHK_TIMER_PUT_CB_PACK_REQ) + nsend++; + } + } while (ncchkioi_chunk_itr_next_ex (varp, start, count, citr, &cid, ostart, osize)); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_PACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_RECV_REQ) + + // Post recv + nrecv = 0; + for (j = 0; j < varp->nmychunk; j++) { + cid = varp->mychunks[j]; + // We are the owner of the chunk + // Receive data from other process + for (i = 0; i < wcnt_all[cid] - wcnt_local[cid]; i++) { + // Get message size, including metadata + CHK_ERR_MPROBE (MPI_ANY_SOURCE, cid, ncchkp->comm, &rmsg, rstats); + CHK_ERR_GET_COUNT (rstats, MPI_BYTE, rsizes + nrecv); + + // Allocate buffer + rbufs[nrecv] = (char *)NCI_Malloc (rsizes[nrecv]); + + // Post irecv + CHK_ERR_IMRECV (rbufs[nrecv], rsizes[nrecv], MPI_BYTE, &rmsg, rreqs + nrecv); + + nrecv++; + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_RECV_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SEND_REQ) + + // Wait for all send + CHK_ERR_WAITALL (nsend, sreqs, sstats); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SEND_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_INIT) + + // Preparing chunk cache + nread = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + if (wcnt_all[cid] && varp->chunk_cache[cid] == NULL) { + if (varp->chunk_index[cid].len > 0) { nread++; } + } + } + rids = (int *)NCI_Malloc (sizeof (int) * nread); + nread = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + if (wcnt_all[cid] || wcnt_local[cid]) { + if (varp->chunk_cache[cid] == NULL) { + err = ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (NC_chk_cache*)NCI_Malloc(varp->chunksize); + if (varp->chunk_index[cid].len > 0) { rids[nread++] = cid; } + } else { + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + } + } + // Increase batch number to indicate allocated chunk buffer can be freed for future allocation + (ncchkp->cache_serial)++; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_INIT) + + // Read background + ncchkioi_load_var_bg (ncchkp, varp, nread, rids); + + // Allocate intermediate buffer + if (max_tbuf > 0) { tbuf = (char *)NCI_Malloc (max_tbuf); } + + // For each chunk we own, we need to receive incoming data + nrecv = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SELF) + + // Handle our own data first if we have any + if (wcnt_local[cid] < 0) { + // Convert chunk id to iterator + get_chunk_itr (varp, cid, citr); + + // Calculate overlapping region + overlapsize = get_chunk_overlap (varp, citr, start, count, ostart, osize); + + if (overlapsize > 0) { + // Pack type from user buffer to (contiguous) intermediate buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - start[j]); + tsize[j] = (int)count[j]; + tssize[j] = (int)osize[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data into intermediate buffer + packoff = 0; + CHK_ERR_PACK (buf, 1, ptype, tbuf, varp->chunksize, &packoff, ncchkp->comm); + overlapsize = packoff; + + MPI_Type_free (&ptype); + + // Pack type from (contiguous) intermediate buffer to chunk buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - citr[j]); + tsize[j] = varp->chunkdim[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Unpack data into chunk buffer + packoff = 0; + CHK_ERR_UNPACK (tbuf, overlapsize, &packoff, varp->chunk_cache[cid]->buf, 1, ptype, + ncchkp->comm); + + MPI_Type_free (&ptype); + + // Mark chunk as dirty + varp->dirty[cid] = 1; + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SELF) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_RECV_REQ) + + // Now, it is time to process data from other processes + + // Wait for all send requests related to this chunk + // We remove the impact of -1 mark in wcnt_local[cid] + CHK_ERR_WAITALL (wcnt_all[cid] - wcnt_local[cid], rreqs + nrecv, rstats + nrecv); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_RECV_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_UNPACK_REQ) + + // Process data received + for (j = nrecv; j < nrecv + wcnt_all[cid] - wcnt_local[cid]; j++) { + // Metadata + packoff = 0; + tstartp = (int *)rbufs[j]; + packoff += varp->ndim * sizeof (int); + tsizep = (int *)(rbufs[j] + packoff); + packoff += varp->ndim * sizeof (int); + + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, varp->chunkdim, tsizep, tstartp, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Data + CHK_ERR_UNPACK (rbufs[j], rsizes[j], &packoff, varp->chunk_cache[cid]->buf, 1, ptype, + ncchkp->comm); + MPI_Type_free (&ptype); + + // Mark chunk as dirty + varp->dirty[cid] = 1; + } + nrecv += wcnt_all[cid] - wcnt_local[cid]; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_UNPACK_REQ) + } + + // Free buffers + NCI_Free (wcnt_local); + + NCI_Free (tstart); + + NCI_Free (ostart); + + NCI_Free (sreqs); + NCI_Free (sstats); + for (i = 0; i < nsend; i++) { NCI_Free (sbufs[i]); } + NCI_Free (sbufs); + + NCI_Free (rreqs); + NCI_Free (rstats); + for (i = 0; i < nrecv; i++) { NCI_Free (rbufs[i]); } + NCI_Free (rbufs); + NCI_Free (rsizes); + + if (tbuf != NULL) { NCI_Free (tbuf); } + + if (rids != NULL) { NCI_Free (rids); } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB) + +err_out:; + return err; +} + +int ncchkioi_put_var_cb_proc (NC_chk *ncchkp, + NC_chk_var *varp, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + void *buf) { + int err = NC_NOERR; + int i, j, k; + int cid, cown; // Chunk iterator + + MPI_Offset *ostart = NULL, *osize; + int *tsize, *tssize, *tstart = NULL, *tssizep, *tstartp; // Size for sub-array type + MPI_Offset *citr; // Bounding box for chunks overlapping my own write region + + int *wcnt_local = NULL, *wcnt_all; // Number of processes that writes to each chunk + int wrange_local[2], wrange_all[2]; // Number of processes that writes to each chunk + + int nread; // Chunks to read for background + int *rids; + + int overlapsize; // Size of overlaping region of request and chunk + int max_tbuf = 0; // Size of intermediate buffer + char *tbuf = NULL; // Intermediate buffer + + int packoff; // Pack offset + MPI_Datatype ptype; // Pack datatype + + int nsend, nrecv; // Number of send and receive + MPI_Request *sreq = NULL, *rreq = NULL; // Send and recv req + MPI_Status *sstat = NULL, rstat; // Send and recv status + char **sbuf = NULL, **sbufp, **rbuf = NULL, **rbufp; // Send and recv buffer + int *rsize = NULL, *ssize = NULL; // recv size of each message + int *sdst; // recv size of each message + int *smap; + size_t bsize; + MPI_Message rmsg; // Receive message + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_INIT) + + // Allocate buffering for write count + wcnt_local = (int *)NCI_Malloc (sizeof (int) * ncchkp->np * 3); + CHK_PTR (wcnt_local) + wcnt_all = wcnt_local + ncchkp->np; + smap = wcnt_all + ncchkp->np; + + // Allocate buffering for overlaping index + tstart = (int *)NCI_Malloc (sizeof (int) * varp->ndim * 3); + CHK_PTR (tstart) + tssize = tstart + varp->ndim; + tsize = tssize + varp->ndim; + ostart = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim * 3); + CHK_PTR (ostart) + osize = ostart + varp->ndim; + + // Chunk iterator + citr = osize + varp->ndim; + + // We need to calculate the size of message of each chunk + // This is just for allocating send buffer + // We do so by iterating through all request and all chunks they cover + // If we are not the owner of a chunk, we need to send message + memset (wcnt_local, 0, sizeof (int) * ncchkp->np); + nsend = 0; + + // Count total number of messages and build a map of accessed chunk to list of comm + // datastructure + wrange_local[0] = varp->nchunk; + wrange_local[1] = 0; + ncchkioi_chunk_itr_init (varp, start, count, citr, &cid); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + + // Mapping to skip list of send requests + if (wcnt_local[cown] == 0 && cown != ncchkp->rank) { smap[cown] = nsend++; } + wcnt_local[cown] = 1; // Need to send message if not owner + + // Record lowest and highest chunk accessed + if (wrange_local[0] > cid) { wrange_local[0] = cid; } + if (wrange_local[1] < cid) { wrange_local[1] = cid; } + } while (ncchkioi_chunk_itr_next (varp, start, count, citr, &cid)); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SYNC) + + // Sync number of messages of each chunk and access range + CHK_ERR_ALLREDUCE (wcnt_local, wcnt_all, ncchkp->np, MPI_INT, MPI_SUM, ncchkp->comm); + wrange_local[1] *= -1; + CHK_ERR_ALLREDUCE (wrange_local, wrange_all, 2, MPI_INT, MPI_MIN, ncchkp->comm); + nrecv = wcnt_all[ncchkp->rank] - + wcnt_local[ncchkp->rank]; // We don't need to receive request from self + wrange_all[1] *= -1; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SYNC) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_PACK_REQ) + + // Allocate data structure for messaging + sbuf = (char **)NCI_Malloc (sizeof (char *) * nsend * 2); + CHK_PTR (sbuf) + sbufp = sbuf + nsend; + ssize = (int *)NCI_Malloc (sizeof (int) * nsend * 2); + CHK_PTR (ssize) + sdst = ssize + nsend; + sreq = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * nsend); + CHK_PTR (sreq) + sstat = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * nsend); + CHK_PTR (sstat) + + rbuf = (char **)NCI_Malloc (sizeof (char *) * nrecv * 2); + CHK_PTR (rbuf) + rbufp = rbuf + nrecv; + rsize = (int *)NCI_Malloc (sizeof (int) * nrecv); + CHK_PTR (rsize) + rreq = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * nrecv); + CHK_PTR (rreq) + + // Count size of each request + memset (ssize, 0, sizeof (int) * nsend); + ncchkioi_chunk_itr_init_ex (varp, start, count, citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + if (cown != ncchkp->rank) { + j = smap[cown]; + sdst[j] = cown; // Record a reverse map by the way + + // Count overlap + overlapsize = varp->esize; + for (i = 0; i < varp->ndim; i++) { overlapsize *= osize[i]; } + ssize[j] += overlapsize + sizeof (int) * (varp->ndim * 2 + 1); + } + } while (ncchkioi_chunk_itr_next_ex (varp, start, count, citr, &cid, ostart, osize)); + + // Allocate buffer for send + bsize = 0; + for (i = 0; i < nsend; i++) { bsize += ssize[i]; } + if (nsend > 0) { + sbuf[0] = sbufp[0] = (char *)NCI_Malloc (bsize); + CHK_PTR (sbuf[0]) + for (i = 1; i < nsend; i++) { sbuf[i] = sbufp[i] = sbuf[0] + ssize[i]; } + } + + // Pack requests + ncchkioi_chunk_itr_init_ex (varp, start, count, citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + if (cown != ncchkp->rank) { + j = smap[cown]; + + // Metadata + *((int *)sbufp[j]) = cid; + sbufp[j] += sizeof (int); + tstartp = (int *)sbufp[j]; + sbufp[j] += varp->ndim * sizeof (int); + tssizep = (int *)sbufp[j]; + sbufp[j] += varp->ndim * sizeof (int); + for (i = 0; i < varp->ndim; i++) { + tstartp[i] = (int)(ostart[i] - citr[i]); + tssizep[i] = (int)osize[i]; + } + + // Pack type + for (i = 0; i < varp->ndim; i++) { + tstart[i] = (int)(ostart[i] - start[i]); + tsize[i] = (int)count[i]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssizep, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Data + packoff = 0; + CHK_ERR_PACK (buf, 1, ptype, sbufp[j], ssize[j], &packoff, ncchkp->comm); + sbufp[j] += packoff; + MPI_Type_free (&ptype); + } + } while (ncchkioi_chunk_itr_next_ex (varp, start, count, citr, &cid, ostart, osize)); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_PACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SEND_REQ) + + // Post send + for (i = 0; i < nsend; i++) { + CHK_ERR_ISEND (sbuf[i], ssize[i], MPI_BYTE, sdst[i], 0, ncchkp->comm, sreq + i); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SEND_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_RECV_REQ) + + // Post recv + for (i = 0; i < nrecv; i++) { + // Get message size, including metadata + CHK_ERR_MPROBE (MPI_ANY_SOURCE, 0, ncchkp->comm, &rmsg, &rstat); + CHK_ERR_GET_COUNT (&rstat, MPI_BYTE, rsize + i); + + // Allocate buffer + rbuf[i] = rbufp[i] = (char *)NCI_Malloc (rsize[i]); + CHK_PTR (rbuf[i]) + + // Post irecv + CHK_ERR_IMRECV (rbuf[i], rsize[i], MPI_BYTE, &rmsg, rreq + i); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_RECV_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_INIT) + + // Preparing chunk cache + for (j = 0; j < varp->nmychunk && varp->mychunks[j] < wrange_all[0]; j++) + ; + for (k = j; k < varp->nmychunk && varp->mychunks[k] <= wrange_all[1]; k++) + ; + rids = (int *)NCI_Malloc (sizeof (int) * (k - j)); + nread = 0; + for (i = j; i < k; i++) { + cid = varp->mychunks[i]; + if (varp->chunk_cache[cid] == NULL) { + err = ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + if (varp->chunk_index[cid].len > 0) { rids[nread++] = cid; } + } else { + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + } + // Increase batch number to indicate allocated chunk buffer can be freed for future allocation + (ncchkp->cache_serial)++; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_INIT) + + // Read background + err = ncchkioi_load_var_bg (ncchkp, varp, nread, rids); + CHK_ERR + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SELF) + + tbuf = (char *)NCI_Malloc (varp->chunksize); + CHK_PTR (tbuf) + + // Handle our own data + ncchkioi_chunk_itr_init_ex (varp, start, count, citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + if (varp->chunk_owner[cid] == ncchkp->rank) { + // Pack type from user buffer to (contiguous) intermediate buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - start[j]); + tsize[j] = (int)count[j]; + tssize[j] = (int)osize[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data into intermediate buffer + packoff = 0; + CHK_ERR_PACK (buf, 1, ptype, tbuf, varp->chunksize, &packoff, ncchkp->comm); + MPI_Type_free (&ptype); + overlapsize = packoff; + + // Pack type from (contiguous) intermediate buffer to chunk buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - citr[j]); + tsize[j] = varp->chunkdim[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Unpack data into chunk buffer + packoff = 0; + CHK_ERR_UNPACK (tbuf, overlapsize, &packoff, varp->chunk_cache[cid]->buf, 1, ptype, + ncchkp->comm); + MPI_Type_free (&ptype); + + // Mark chunk as dirty + varp->dirty[cid] = 1; + } + } while (ncchkioi_chunk_itr_next_ex (varp, start, count, citr, &cid, ostart, osize)); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SELF) + + // Handle incoming requests + for (i = 0; i < varp->ndim; i++) { tsize[i] = varp->chunkdim[i]; } + for (i = 0; i < nrecv; i++) { + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_RECV_REQ) + + // Will wait any provide any benefit? + MPI_Waitany (nrecv, rreq, &j, &rstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_RECV_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_UNPACK_REQ) + + while (rbufp[j] < rbuf[j] + rsize[j]) { + // Metadata + cid = *(int *)(rbufp[j]); + rbufp[j] += sizeof (int); + tstartp = (int *)rbufp[j]; + rbufp[j] += varp->ndim * sizeof (int); + tssizep = (int *)rbufp[j]; + rbufp[j] += varp->ndim * sizeof (int); + + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssizep, tstartp, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Data + packoff = 0; + CHK_ERR_UNPACK (rbufp[j], rsize[j], &packoff, varp->chunk_cache[cid]->buf, 1, ptype, + ncchkp->comm); + rbufp[j] += packoff; + MPI_Type_free (&ptype); + + // Mark chunk as dirty + varp->dirty[cid] = 1; + } + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_UNPACK_REQ) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SEND_REQ) + + CHK_ERR_WAITALL (nsend, sreq, sstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SEND_REQ) + +err_out:; + + // Free buffers + NCI_Free (wcnt_local); + + NCI_Free (tstart); + + NCI_Free (ostart); + + NCI_Free (sreq); + NCI_Free (sstat); + NCI_Free (ssize); + if (nsend > 0) { NCI_Free (sbuf[0]); } + NCI_Free (sbuf); + + NCI_Free (rreq); + for (i = 0; i < nrecv; i++) { NCI_Free (rbuf[i]); } + NCI_Free (rbuf); + NCI_Free (rsize); + + NCI_Free (tbuf); + + NCI_Free (rids); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB) + + return err; +} + +int ncchkioi_put_var (NC_chk *ncchkp, + NC_chk_var *varp, + const MPI_Offset *start, + const MPI_Offset *count, + const MPI_Offset *stride, + void *buf) { + int err = NC_NOERR; + + if (varp->isrec) { + if (ncchkp->recsize < start[0] + count[0]) { ncchkp->recsize = start[0] + count[0]; } + CHK_ERR_ALLREDUCE (MPI_IN_PLACE, &(ncchkp->recsize), 1, MPI_LONG_LONG, MPI_MAX, + ncchkp->comm); // Sync number of recs + if (varp->dimsize[0] < ncchkp->recsize) { + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_PUT) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_RESIZE) + + err = ncchkioi_var_resize (ncchkp, varp); + CHK_ERR + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_RESIZE) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT) + } + } + + // Collective buffer + switch (ncchkp->comm_unit) { + case NC_CHK_COMM_CHUNK: + err = ncchkioi_put_var_cb_chunk (ncchkp, varp, start, count, stride, buf); + break; + case NC_CHK_COMM_PROC: + err = ncchkioi_put_var_cb_proc (ncchkp, varp, start, count, stride, buf); + break; + } + CHK_ERR + + // Write the compressed variable + err = ncchkioi_save_var (ncchkp, varp); + CHK_ERR + +err_out:; + return err; +} \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkioi_put_varn.c b/src/drivers/ncchunkio/ncchkioi_put_varn.c new file mode 100644 index 000000000..94ab94d62 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_put_varn.c @@ -0,0 +1,818 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ncchkio_internal.h" + +int printbuf (int rank, char *buf, int len) { + int i; + printf ("Rank %d: ", rank); + for (i = 0; i < len; i++) { printf ("%02x ", buf[i]); } + printf ("\n"); +} + +int ncchkioi_put_varn_cb_chunk (NC_chk *ncchkp, + NC_chk_var *varp, + int nreq, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + MPI_Offset *const *strides, + void **bufs) { + int err = NC_NOERR; + int i, j, k; + int cid, req; // Chunk and request iterator + + int *tsize, *tssize, *tstart, *tsizep, *tstartp; // Size for sub-array type + MPI_Offset *ostart, *osize; + MPI_Offset *citr; + + int *wcnt_local, *wcnt_all; // Number of processes that writes to each chunk + + int nread; // Chunks to read for background + int *rids; + + int overlapsize; // Size of overlaping region of request and chunk + int max_tbuf; // Size of intermediate buffer + char *tbuf = NULL; // Intermediate buffer + + int packoff; // Pack offset + MPI_Datatype ptype; // Pack datatype + + int nsend, nrecv; // Number of send and receive + MPI_Request *sreqs, *rreqs; // Send and recv req + MPI_Status *sstats, *rstats; // Send and recv status + char **sbufs, **rbufs; // Send and recv buffer + int *rsizes; // recv size of each message + MPI_Message rmsg; // Receive message + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_INIT) + + // Allocate buffering for write count + wcnt_local = (int *)NCI_Malloc (sizeof (int) * varp->nchunk * 2); + wcnt_all = wcnt_local + varp->nchunk; + + // Allocate buffering for overlaping index + tstart = (int *)NCI_Malloc (sizeof (int) * varp->ndim * 3); + tsize = tstart + varp->ndim; + tssize = tsize + varp->ndim; + ostart = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim * 3); + osize = ostart + varp->ndim; + + // Chunk iterator + citr = osize + varp->ndim; + + // We need to calculate the size of message of each chunk + // This is just for allocating send buffer + // We do so by iterating through all request and all chunks they cover + // If we are not the owner of a chunk, we need to send message + memset (wcnt_local, 0, sizeof (int) * varp->nchunk); + nsend = 0; + max_tbuf = 0; + for (req = 0; req < nreq; req++) { + // Initialize chunk iterator + ncchkioi_chunk_itr_init_ex (varp, starts[req], counts[req], citr, &cid, ostart, + osize); // Initialize chunk iterator + + // Iterate through chunks + do { + // Calculate overlapping + overlapsize = varp->esize; + for (j = 0; j < varp->ndim; j++) { overlapsize *= osize[j]; } + + if (varp->chunk_owner[cid] != ncchkp->rank) { + // Count number of mnessage we need to send + if (wcnt_local[cid] == 0) { nsend++; } + wcnt_local[cid] += overlapsize + sizeof (int) * 2 * varp->ndim; + } else { + // We mark covered chunk of our own to prevent unnecessary calculation of overlap + // -1 is purely a mark, we need to add 1 back to global message count + wcnt_local[cid] = -1; + + // Record max overlapsize so we know how large the intermediate buffer is needed + // later + if (max_tbuf < overlapsize) { max_tbuf = overlapsize; } + } + + } while ( + ncchkioi_chunk_itr_next_ex (varp, starts[req], counts[req], citr, &cid, ostart, osize)); + } + + // Allocate buffer for sending + sbufs = (char **)NCI_Malloc (sizeof (char *) * nsend); + sreqs = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * nsend); + sstats = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * nsend); + j = 0; + // Allocate buffer for data + for (cid = 0; cid < varp->nchunk; cid++) { + // Count number of mnessage we need to send + if (wcnt_local[cid] > 0) { + // Add space for number of reqs + sbufs[j++] = (char *)NCI_Malloc (wcnt_local[cid]); + // We don't need message size anymore, wcnt_local is used to track number of message + // from now on + wcnt_local[cid] = 1; + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SYNC) + + // Sync number of messages of each chunk + CHK_ERR_ALLREDUCE (wcnt_local, wcnt_all, varp->nchunk, MPI_INT, MPI_SUM, ncchkp->comm); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SYNC) + + // Calculate number of recv request + // This is for all the chunks + nrecv = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + // We don't need message for our own data + nrecv += wcnt_all[cid] - wcnt_local[cid]; + } + rreqs = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * nrecv); + rstats = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * nrecv); + rbufs = (char **)NCI_Malloc (sizeof (char *) * nrecv); + rsizes = (int *)NCI_Malloc (sizeof (int) * nrecv); + + // Post send and recv + nrecv = 0; + nsend = 0; + for (cid = 0; cid < varp->nchunk; cid++) { + if (varp->chunk_owner[cid] == ncchkp->rank) { + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_RECV_REQ) + + // We are the owner of the chunk + // Receive data from other process + for (i = 0; i < wcnt_all[cid] - wcnt_local[cid]; i++) { + // Get message size, including metadata + CHK_ERR_MPROBE (MPI_ANY_SOURCE, cid, ncchkp->comm, &rmsg, rstats); + CHK_ERR_GET_COUNT (rstats, MPI_BYTE, rsizes + nrecv); + + // Allocate buffer + rbufs[nrecv] = (char *)NCI_Malloc (rsizes[nrecv]); + + // Post irecv + CHK_ERR_IMRECV (rbufs[nrecv], rsizes[nrecv], MPI_BYTE, &rmsg, rreqs + nrecv); + nrecv++; + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_RECV_REQ) + } else { + // If we any of our request overlap with this chunk, we need to send data + // We send only 1 message for 1 chunk + if (wcnt_local[cid] > 0) { + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_PACK_REQ) + + packoff = 0; + // Get chunk iterator + get_chunk_itr (varp, cid, citr); + for (req = 0; req < nreq; req++) { + // Calculate chunk overlap + overlapsize = + get_chunk_overlap (varp, citr, starts[req], counts[req], ostart, osize); + + // If current request have any overlap with the chunk, we pack the data and + // metadata + if (overlapsize > 0) { + // Metadata + tstartp = (int *)(sbufs[nsend] + packoff); + packoff += varp->ndim * sizeof (int); + tsizep = (int *)(sbufs[nsend] + packoff); + packoff += varp->ndim * sizeof (int); + for (j = 0; j < varp->ndim; j++) { + tstartp[j] = (int)(ostart[j] - citr[j]); + tsizep[j] = (int)osize[j]; + } + + // Pack type + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - starts[req][j]); + tsize[j] = (int)counts[req][j]; + tssize[j] = (int)osize[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, + MPI_ORDER_C, varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Data + CHK_ERR_PACK (bufs[req], 1, ptype, sbufs[nsend], packoff + overlapsize, + &packoff, ncchkp->comm); + MPI_Type_free (&ptype); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_PACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SEND_REQ) + + // Send the request + CHK_ERR_ISEND (sbufs[nsend], packoff, MPI_BYTE, varp->chunk_owner[cid], cid, + ncchkp->comm, sreqs + nsend); + nsend++; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SEND_REQ) + } + } + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SEND_REQ) + + // Wait for all send + CHK_ERR_WAITALL (nsend, sreqs, sstats); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SEND_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_INIT) + + // Preparing chunk cache + nread = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + if (wcnt_all[cid] && varp->chunk_cache[cid] == NULL) { + if (varp->chunk_index[cid].len > 0) { nread++; } + } + } + rids = (int *)NCI_Malloc (sizeof (int) * nread); + nread = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + if (wcnt_all[cid] || wcnt_local[cid]) { + if (varp->chunk_cache[cid] == NULL) { + err = ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (NC_chk_cache*)NCI_Malloc(varp->chunksize); + if (varp->chunk_index[cid].len > 0) { rids[nread++] = cid; } + } else { + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + } + } + // Increase batch number to indicate allocated chunk buffer can be freed for future allocation + (ncchkp->cache_serial)++; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_INIT) + + // Read background + ncchkioi_load_var_bg (ncchkp, varp, nread, rids); + + // Allocate intermediate buffer + if (max_tbuf > 0) { tbuf = (char *)NCI_Malloc (max_tbuf); } + + // For each chunk we own, we need to receive incoming data + nrecv = 0; + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SELF) + + // Handle our own data first if we have any + if (wcnt_local[cid] < 0) { + for (req = 0; req < nreq; req++) { + // Convert chunk id to iterator + get_chunk_itr (varp, cid, citr); + + // Calculate overlapping region + overlapsize = + get_chunk_overlap (varp, citr, starts[req], counts[req], ostart, osize); + + // If anything overlaps + if (overlapsize > 0) { + // Pack type from user buffer to (contiguous) intermediate buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - starts[req][j]); + tsize[j] = (int)counts[req][j]; + tssize[j] = (int)osize[j]; + } + + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data into intermediate buffer + packoff = 0; + CHK_ERR_PACK (bufs[req], 1, ptype, tbuf, overlapsize, &packoff, ncchkp->comm); + + MPI_Type_free (&ptype); + + // Pack type from (contiguous) intermediate buffer to chunk buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - citr[j]); + tsize[j] = varp->chunkdim[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Unpack data into chunk buffer + packoff = 0; + CHK_ERR_UNPACK (tbuf, overlapsize, &packoff, varp->chunk_cache[cid]->buf, 1, + ptype, ncchkp->comm); + + MPI_Type_free (&ptype); + + // Mark chunk as dirty + varp->dirty[cid] = 1; + } + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SELF) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_RECV_REQ) + + // Now, it is time to process data from other processes + + // Wait for all send requests related to this chunk + // We remove the impact of -1 mark in wcnt_local[cid] + CHK_ERR_WAITALL (wcnt_all[cid] - wcnt_local[cid], rreqs + nrecv, rstats + nrecv); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_RECV_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_UNPACK_REQ) + + // Process data received + for (j = nrecv; j < nrecv + wcnt_all[cid] - wcnt_local[cid]; j++) { + packoff = 0; + while (packoff < rsizes[j]) { + // Metadata + tstartp = (int *)(rbufs[j] + packoff); + packoff += varp->ndim * sizeof (int); + tsizep = (int *)(rbufs[j] + packoff); + packoff += varp->ndim * sizeof (int); + + // Packtype + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, varp->chunkdim, tsizep, tstartp, + MPI_ORDER_C, varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Data + CHK_ERR_UNPACK (rbufs[j], rsizes[j], &packoff, varp->chunk_cache[cid]->buf, 1, + ptype, ncchkp->comm); + MPI_Type_free (&ptype); + + // Mark chunk as dirty + varp->dirty[cid] = 1; + } + } + nrecv += wcnt_all[cid] - wcnt_local[cid]; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_UNPACK_REQ) + } + + // Free buffers + NCI_Free (wcnt_local); + + NCI_Free (tstart); + + NCI_Free (ostart); + + NCI_Free (sreqs); + NCI_Free (sstats); + for (i = 0; i < nsend; i++) { NCI_Free (sbufs[i]); } + NCI_Free (sbufs); + + NCI_Free (rreqs); + NCI_Free (rstats); + for (i = 0; i < nrecv; i++) { NCI_Free (rbufs[i]); } + NCI_Free (rbufs); + NCI_Free (rsizes); + + if (tbuf != NULL) { NCI_Free (tbuf); } + + if (rids != NULL) { NCI_Free (rids); } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB) + +err_out:; + return err; +} + +int ncchkioi_put_varn_cb_proc (NC_chk *ncchkp, + NC_chk_var *varp, + int nreq, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + void **bufs) { + int err; + int i, j, k; + int cid, cown; // Chunk iterator and owner + int req; + + MPI_Offset *ostart, *osize; + int *tsize, *tssize, *tstart, *tssizep, *tstartp; // Size for sub-array type + MPI_Offset *citr; // Bounding box for chunks overlapping my own write region + + int *wcnt_local, *wcnt_all; // Number of processes that writes to each chunk + int wrange_local[2], wrange_all[2]; // Number of processes that writes to each chunk + + int nread; // Chunks to read for background + int *rids; + + int overlapsize; // Size of overlaping region of request and chunk + int max_tbuf = 0; // Size of intermediate buffer + char *tbuf = NULL; // Intermediate buffer + + int packoff; // Pack offset + MPI_Datatype ptype; // Pack datatype + + int nsend, nrecv; // Number of send and receive + MPI_Request *sreq, *rreq; // Send and recv req + MPI_Status *sstat, rstat; // Send and recv status + char **sbuf, **sbufp, **rbuf, **rbufp; // Send and recv buffer + int *rsize, *ssize; // recv size of each message + int *sdst; // recv size of each message + int *smap; + MPI_Message rmsg; // Receive message + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_INIT) + + // Allocate buffering for write count + wcnt_local = (int *)NCI_Malloc (sizeof (int) * ncchkp->np * 3); + wcnt_all = wcnt_local + ncchkp->np; + smap = wcnt_all + ncchkp->np; + + // Allocate buffering for overlaping index + tstart = (int *)NCI_Malloc (sizeof (int) * varp->ndim * 3); + tssize = tstart + varp->ndim; + tsize = tssize + varp->ndim; + ostart = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * varp->ndim * 3); + osize = ostart + varp->ndim; + + // Chunk iterator + citr = osize + varp->ndim; + + // We need to calculate the size of message of each processes + // This is just for allocating send buffer + // We do so by iterating through all request and all chunks they cover + // If we are not the owner of a chunk, we need to send message + memset (wcnt_local, 0, sizeof (int) * ncchkp->np); + nsend = 0; + + // Count total number of messages and build a map of accessed chunk to list of comm + // datastructure + wrange_local[0] = varp->nchunk; + wrange_local[1] = 0; + for (req = 0; req < nreq; req++) { + ncchkioi_chunk_itr_init (varp, starts[req], counts[req], citr, + &cid); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + + // Mapping to skip list of send requests + if (wcnt_local[cown] == 0 && cown != ncchkp->rank) { smap[cown] = nsend++; } + wcnt_local[cown] = 1; // Need to send message if not owner + + // Record lowest and highest chunk accessed + if (wrange_local[0] > cid) { wrange_local[0] = cid; } + if (wrange_local[1] < cid) { wrange_local[1] = cid; } + } while (ncchkioi_chunk_itr_next (varp, starts[req], counts[req], citr, &cid)); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SYNC) + + // Sync number of messages of each chunk + CHK_ERR_ALLREDUCE (wcnt_local, wcnt_all, ncchkp->np, MPI_INT, MPI_SUM, ncchkp->comm); + wrange_local[1] *= -1; + CHK_ERR_ALLREDUCE (wrange_local, wrange_all, 2, MPI_INT, MPI_MIN, ncchkp->comm); + nrecv = wcnt_all[ncchkp->rank] - + wcnt_local[ncchkp->rank]; // We don't need to receive request form self + wrange_all[1] *= -1; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SYNC) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_PACK_REQ) + + // Allocate data structure for messaging + sbuf = (char **)NCI_Malloc (sizeof (char *) * nsend * 2); + sbufp = sbuf + nsend; + ssize = (int *)NCI_Malloc (sizeof (int) * nsend * 2); + sdst = ssize + nsend; + sreq = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * nsend); + sstat = (MPI_Status *)NCI_Malloc (sizeof (MPI_Status) * nsend); + + rbuf = (char **)NCI_Malloc (sizeof (char *) * nrecv * 2); + rbufp = rbuf + nrecv; + rsize = (int *)NCI_Malloc (sizeof (int) * nrecv); + rreq = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * nrecv); + + // Count size of each request + memset (ssize, 0, sizeof (int) * nsend); + for (req = 0; req < nreq; req++) { + ncchkioi_chunk_itr_init_ex (varp, starts[req], counts[req], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + if (cown != ncchkp->rank) { + j = smap[cown]; + sdst[j] = cown; // Record a reverse map by the way + + // Count overlap + overlapsize = varp->esize; + for (i = 0; i < varp->ndim; i++) { overlapsize *= osize[i]; } + ssize[j] += overlapsize + sizeof (int) * (varp->ndim * 2 + 1); + } + } while ( + ncchkioi_chunk_itr_next_ex (varp, starts[req], counts[req], citr, &cid, ostart, osize)); + } + // Allocate buffer for send + for (i = 0; i < nsend; i++) { sbuf[i] = sbufp[i] = (char *)NCI_Malloc (ssize[i]); } + + // Pack requests + for (req = 0; req < nreq; req++) { + ncchkioi_chunk_itr_init_ex (varp, starts[req], counts[req], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + // Chunk owner + cown = varp->chunk_owner[cid]; + if (cown != ncchkp->rank) { + j = smap[cown]; + + // Metadata + *((int *)sbufp[j]) = cid; + sbufp[j] += sizeof (int); + tstartp = (int *)sbufp[j]; + sbufp[j] += varp->ndim * sizeof (int); + tssizep = (int *)sbufp[j]; + sbufp[j] += varp->ndim * sizeof (int); + for (i = 0; i < varp->ndim; i++) { + tstartp[i] = (int)(ostart[i] - citr[i]); + tssizep[i] = (int)osize[i]; + } + + // Pack type + for (i = 0; i < varp->ndim; i++) { + tstart[i] = (int)(ostart[i] - starts[req][i]); + tsize[i] = (int)counts[req][i]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssizep, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Data + packoff = 0; + CHK_ERR_PACK (bufs[req], 1, ptype, sbufp[j], ssize[j], &packoff, ncchkp->comm); + sbufp[j] += packoff; + MPI_Type_free (&ptype); + } + } while ( + ncchkioi_chunk_itr_next_ex (varp, starts[req], counts[req], citr, &cid, ostart, osize)); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_PACK_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SEND_REQ) + + // Post send + for (i = 0; i < nsend; i++) { + CHK_ERR_ISEND (sbuf[i], ssize[i], MPI_BYTE, sdst[i], 0, ncchkp->comm, sreq + i); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SEND_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_RECV_REQ) + + // Post recv + for (i = 0; i < nrecv; i++) { + // Get message size, including metadata + CHK_ERR_MPROBE (MPI_ANY_SOURCE, 0, ncchkp->comm, &rmsg, &rstat); + CHK_ERR_GET_COUNT (&rstat, MPI_BYTE, rsize + i); + + // Allocate buffer + rbuf[i] = rbufp[i] = (char *)NCI_Malloc (rsize[i]); + + // Post irecv + CHK_ERR_IMRECV (rbuf[i], rsize[i], MPI_BYTE, &rmsg, rreq + i); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_RECV_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_INIT) + + // Preparing chunk cache + for (j = 0; j < varp->nmychunk && varp->mychunks[j] < wrange_all[0]; j++) + ; + for (k = j; k < varp->nmychunk && varp->mychunks[k] <= wrange_all[1]; k++) + ; + rids = (int *)NCI_Malloc (sizeof (int) * (k - j)); + nread = 0; + for (i = j; i < k; i++) { + cid = varp->mychunks[i]; + if (varp->chunk_cache[cid] == NULL) { + err = ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + if (varp->chunk_index[cid].len > 0) { rids[nread++] = cid; } + } else { + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + } + // Increase batch number to indicate allocated chunk buffer can be freed for future allocation + (ncchkp->cache_serial)++; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_INIT) + + // Read background + ncchkioi_load_var_bg (ncchkp, varp, nread, rids); + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SELF) + + tbuf = (char *)NCI_Malloc (varp->chunksize); + + // Handle our own data + for (req = 0; req < nreq; req++) { + ncchkioi_chunk_itr_init_ex (varp, starts[req], counts[req], citr, &cid, ostart, + osize); // Initialize chunk iterator + do { + if (varp->chunk_owner[cid] == ncchkp->rank) { + // Pack type from user buffer to (contiguous) intermediate buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - starts[req][j]); + tsize[j] = (int)counts[req][j]; + tssize[j] = (int)osize[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Pack data into intermediate buffer + packoff = 0; + CHK_ERR_PACK (bufs[req], 1, ptype, tbuf, varp->chunksize, &packoff, ncchkp->comm); + MPI_Type_free (&ptype); + overlapsize = packoff; + + // Pack type from (contiguous) intermediate buffer to chunk buffer + for (j = 0; j < varp->ndim; j++) { + tstart[j] = (int)(ostart[j] - citr[j]); + tsize[j] = varp->chunkdim[j]; + } + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssize, tstart, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Unpack data into chunk buffer + packoff = 0; + CHK_ERR_UNPACK (tbuf, overlapsize, &packoff, varp->chunk_cache[cid]->buf, 1, ptype, + ncchkp->comm); + MPI_Type_free (&ptype); + + // Mark chunk as dirty + varp->dirty[cid] = 1; + } + } while ( + ncchkioi_chunk_itr_next_ex (varp, starts[req], counts[req], citr, &cid, ostart, osize)); + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SELF) + + // Handle incoming requests + for (i = 0; i < varp->ndim; i++) { tsize[i] = varp->chunkdim[i]; } + for (i = 0; i < nrecv; i++) { + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_RECV_REQ) + + // Will wait any provide any benefit? + MPI_Waitany (nrecv, rreq, &j, &rstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_RECV_REQ) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_UNPACK_REQ) + + while (rbufp[j] < rbuf[j] + rsize[j]) { + // Metadata + cid = *(int *)(rbufp[j]); + rbufp[j] += sizeof (int); + tstartp = (int *)rbufp[j]; + rbufp[j] += varp->ndim * sizeof (int); + tssizep = (int *)rbufp[j]; + rbufp[j] += varp->ndim * sizeof (int); + + // Pack type + CHK_ERR_TYPE_CREATE_SUBARRAY (varp->ndim, tsize, tssizep, tstartp, MPI_ORDER_C, + varp->etype, &ptype); + CHK_ERR_TYPE_COMMIT (&ptype); + + // Data + packoff = 0; + CHK_ERR_UNPACK (rbufp[j], rsize[j], &packoff, varp->chunk_cache[cid]->buf, 1, ptype, + ncchkp->comm); + rbufp[j] += packoff; + MPI_Type_free (&ptype); + + // Mark chunk as dirty + varp->dirty[cid] = 1; + } + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_UNPACK_REQ) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_CB_SEND_REQ) + + CHK_ERR_WAITALL (nsend, sreq, sstat); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB_SEND_REQ) + + // Free buffers + NCI_Free (wcnt_local); + + NCI_Free (tstart); + + NCI_Free (ostart); + + NCI_Free (sreq); + NCI_Free (sstat); + NCI_Free (ssize); + for (i = 0; i < nsend; i++) { NCI_Free (sbuf[i]); } + NCI_Free (sbuf); + + NCI_Free (rreq); + for (i = 0; i < nrecv; i++) { NCI_Free (rbuf[i]); } + NCI_Free (rbuf); + NCI_Free (rsize); + + NCI_Free (tbuf); + + NCI_Free (rids); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_CB) + +err_out:; + return err; +} + +int ncchkioi_put_varn (NC_chk *ncchkp, + NC_chk_var *varp, + int nreq, + MPI_Offset *const *starts, + MPI_Offset *const *counts, + const void *buf) { + int err = NC_NOERR; + int i, j; + MPI_Offset rsize; + char *bptr = (char *)buf; + char **bufs; + + if (varp->isrec) { + for (i = 0; i < nreq; i++) { + if (ncchkp->recsize < starts[i][0] + counts[i][0]) { + ncchkp->recsize = starts[i][0] + counts[i][0]; + } + } + CHK_ERR_ALLREDUCE (MPI_IN_PLACE, &(ncchkp->recsize), 1, MPI_LONG_LONG, MPI_MAX, + ncchkp->comm); // Sync number of recs + if (varp->dimsize[0] < ncchkp->recsize) { + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_PUT) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_RESIZE) + + ncchkioi_var_resize (ncchkp, varp); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_RESIZE) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT) + } + } + + // Calculate buffer offset of each request + bufs = (char **)NCI_Malloc (sizeof (char *) * nreq); + for (i = 0; i < nreq; i++) { + bufs[i] = bptr; + rsize = varp->esize; + for (j = 0; j < varp->ndim; j++) { rsize *= counts[i][j]; } + bptr += rsize; + } + + // Collective buffer + switch (ncchkp->comm_unit) { + case NC_CHK_COMM_CHUNK: + ncchkioi_put_varn_cb_chunk (ncchkp, varp, nreq, starts, counts, NULL, (void **)bufs); + break; + case NC_CHK_COMM_PROC: + ncchkioi_put_varn_cb_proc (ncchkp, varp, nreq, starts, counts, (void **)bufs); + break; + } + + // Write the compressed variable + ncchkioi_save_var (ncchkp, varp); + +err_out:; + NCI_Free (bufs); + + return err; +} \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkioi_util.c b/src/drivers/ncchunkio/ncchkioi_util.c new file mode 100644 index 000000000..34ec21ff5 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_util.c @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2017, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "ncchkio_internal.h" + +/* return internal size for values of specified netCDF type */ +MPI_Offset NC_Type_size (nc_type type) { /* netCDF type code */ + switch (type) { + case NC_BYTE: + return sizeof (char); + case NC_CHAR: + return sizeof (char); + case NC_SHORT: + return sizeof (short); + case NC_INT: + return sizeof (int); + case NC_FLOAT: + return sizeof (float); + case NC_DOUBLE: + return sizeof (double); + case NC_UBYTE: + return sizeof (unsigned char); + case NC_USHORT: + return sizeof (unsigned short); + case NC_UINT: + return sizeof (unsigned int); + case NC_INT64: + return sizeof (long long); + case NC_UINT64: + return sizeof (unsigned long long); + default: + + return 0; + } +} + +/* + * Convert NC type to MPI type + */ +MPI_Datatype ncchkioi_nc_to_mpi_type (nc_type atype) { + switch (atype) { + case NC_BYTE: + return MPI_BYTE; + case NC_CHAR: + return MPI_CHAR; + case NC_SHORT: + return MPI_SHORT; + case NC_INT: + return MPI_INT; + case NC_FLOAT: + return MPI_FLOAT; + case NC_DOUBLE: + return MPI_DOUBLE; + } + + return NC_NAT; +} + +/* + * Extract mpi hints and set up the flags + */ +int ncchkioi_extract_hint (NC_chk *ncchkp, MPI_Info info) { + int flag; + char value[MPI_MAX_INFO_VAL]; + + // Block assignment + MPI_Info_get (info, "nc_chk_block_mapping", MPI_MAX_INFO_VAL - 1, value, &flag); + if (flag) { + if (strcmp (value, "static") == 0) { + ncchkp->blockmapping = NC_CHK_MAPPING_STATIC; + } else { + printf ("Warning: Unknown mapping %s, using static\n", value); + ncchkp->blockmapping = NC_CHK_MAPPING_STATIC; + } + } else { + ncchkp->blockmapping = NC_CHK_MAPPING_STATIC; + } + + // Messaging unit + MPI_Info_get (info, "nc_chk_comm_unit", MPI_MAX_INFO_VAL - 1, value, &flag); + if (flag) { + if (strcmp (value, "chunk") == 0) { + ncchkp->comm_unit = NC_CHK_COMM_CHUNK; + } else if (strcmp (value, "proc") == 0) { + ncchkp->comm_unit = NC_CHK_COMM_PROC; + } else { + printf ("Warning: Unknown messaging unit %s, using proc\n", value); + ncchkp->comm_unit = NC_CHK_COMM_PROC; + } + } else { + ncchkp->comm_unit = NC_CHK_COMM_PROC; + } + + // Delay init + ncchkp->delay_init = 0; + MPI_Info_get (info, "nc_chk_delay_init", MPI_MAX_INFO_VAL - 1, value, &flag); + if (flag) { + if (strcmp (value, "1") == 0) { ncchkp->delay_init = 1; } + } + + // Exact chunk owner assignment + ncchkp->exact_cown = 0; + MPI_Info_get (info, "nc_chk_exact_cown", MPI_MAX_INFO_VAL - 1, value, &flag); + if (flag) { + if (strcmp (value, "1") == 0) { ncchkp->exact_cown = 1; } + } + + // Additional reserved space in file header + ncchkp->hdr_reserve = 1048576; // 1 MiB default + MPI_Info_get (info, "nc_chk_hdr_reserve", MPI_MAX_INFO_VAL - 1, value, &flag); + if (flag) { ncchkp->hdr_reserve = atoi (value); } + + // Reserve space for records + ncchkp->default_recnalloc = NC_CHK_DEFAULT_REC_ALLOC; + MPI_Info_get (info, "nc_chk_nrec", MPI_MAX_INFO_VAL - 1, value, &flag); + if (flag) { ncchkp->default_recnalloc = atoi (value); } + + ncchkp->default_recnalloc = NC_CHK_DEFAULT_REC_ALLOC; + MPI_Info_get (info, "nc_chk_nrec", MPI_MAX_INFO_VAL - 1, value, &flag); + if (flag) { ncchkp->default_recnalloc = atoi (value); } + + // Default filter + ncchkp->default_filter = NC_CHK_FILTER_NONE; + MPI_Info_get (info, "nc_chk_driver", MPI_MAX_INFO_VAL - 1, value, &flag); + if (flag) { + if (strcmp (value, "none") == 0) { + ncchkp->default_filter = NC_CHK_FILTER_NONE; + } else if (strcmp (value, "dummy") == 0) { + ncchkp->default_filter = NC_CHK_FILTER_DUMMY; + } else if (strcmp (value, "zlib") == 0) { + ncchkp->default_filter = NC_CHK_FILTER_ZLIB; + } else if (strcmp (value, "sz") == 0) { + ncchkp->default_filter = NC_CHK_FILTER_SZ; + } else { + if (ncchkp->rank == 0) { printf ("Warning: Unknown filter %s, use none\n", value); } + } + } + + // Buffer size + ncchkp->cache_limit = 0; // Unlimited + ncchkp->cache_limit_hint = 0; + MPI_Info_get (info, "nc_chk_buffer_size", MPI_MAX_INFO_VAL - 1, value, &flag); + if (flag) { + sscanf (value, "%lld", &(ncchkp->cache_limit_hint)); + + if (ncchkp->cache_limit_hint > 0) { ncchkp->cache_limit = ncchkp->cache_limit_hint; } + } + + // Chunk owning size penalty + ncchkp->cown_ratio = 0.1; + MPI_Info_get (info, "nc_chk_cown_ratio", MPI_MAX_INFO_VAL - 1, value, &flag); + if (flag) { ncchkp->cown_ratio = atof (value); } + + return NC_NOERR; +} + +/* + * Export hint based on flag + * NOTE: We only set up the hint if it is not the default setting + * user hint maching the default behavior will be ignored + */ +int ncchkioi_export_hint (NC_chk *ncchkp, MPI_Info info) { + char value[MPI_MAX_INFO_VAL]; + + MPI_Info_set (info, "nc_compression", "enable"); + + switch (ncchkp->blockmapping) { + case NC_CHK_MAPPING_STATIC: + MPI_Info_set (info, "nc_chk_block_mapping", "static"); + break; + } + + switch (ncchkp->comm_unit) { + case NC_CHK_COMM_CHUNK: + MPI_Info_set (info, "nc_chk_comm_unit", "chunk"); + break; + case NC_CHK_COMM_PROC: + MPI_Info_set (info, "nc_chk_comm_unit", "proc"); + break; + } + + // Delay inint + if (ncchkp->delay_init) { + MPI_Info_set (info, "nc_chk_delay_init", "1"); + } else { + MPI_Info_set (info, "nc_chk_delay_init", "0"); + } + + // Exact cown + if (ncchkp->exact_cown) { + MPI_Info_set (info, "nc_chk_exact_cown", "1"); + } else { + MPI_Info_set (info, "nc_chk_exact_cown", "0"); + } + + // Additional reserved space in file header + sprintf (value, "%lld", ncchkp->hdr_reserve); + MPI_Info_set (info, "nc_chk_hdr_reserve", value); + + // Reserve space for records + sprintf (value, "%lld", ncchkp->default_recnalloc); + MPI_Info_set (info, "nc_chk_nrec", value); + + // Zip driver + switch (ncchkp->default_filter) { + case NC_CHK_FILTER_NONE: + MPI_Info_set (info, "nc_chk_driver", "none"); + break; + case NC_CHK_FILTER_DUMMY: + MPI_Info_set (info, "nc_chk_driver", "dummy"); + break; + case NC_CHK_FILTER_ZLIB: + MPI_Info_set (info, "nc_chk_driver", "zlib"); + break; + case NC_CHK_FILTER_SZ: + MPI_Info_set (info, "nc_chk_driver", "sz"); + break; + } + + // Buffer size + sprintf (value, "%lld", ncchkp->cache_limit); + MPI_Info_set (info, "nc_chk_buffer_size", value); + + return NC_NOERR; +} + +int ncchkioi_print_buffer_int (char *prefix, int *buf, int len) { + int i; + int rank, np; + int plen, rlen; + char *out, *outp; + char rankstr[16]; + + MPI_Comm_size (MPI_COMM_WORLD, &np); + MPI_Comm_rank (MPI_COMM_WORLD, &rank); + + rlen = sprintf (rankstr, "Rank %d: ", rank); + + plen = strlen (prefix); + out = outp = (char *)NCI_Malloc (len * 12 + 2 + plen + rlen); + + rlen = sprintf (outp, "%s ", rankstr); + outp += rlen; + plen = sprintf (outp, "%s ", prefix); + outp += plen; + for (i = 0; i < len; i++) { + plen = sprintf (outp, "%d ", buf[i]); + outp += plen; + } + + printf ("%s\n", out); + fflush (stdout); + + NCI_Free (out); + + return NC_NOERR; +} + +int ncchkioi_print_buffer_int64 (char *prefix, long long *buf, int len) { + int i; + int rank, np; + int plen, rlen; + char *out, *outp; + char rankstr[16]; + + MPI_Comm_size (MPI_COMM_WORLD, &np); + MPI_Comm_rank (MPI_COMM_WORLD, &rank); + + rlen = sprintf (rankstr, "Rank %d: ", rank); + + plen = strlen (prefix); + out = outp = (char *)NCI_Malloc (len * 18 + 2 + plen + rlen); + + rlen = sprintf (outp, "%s ", rankstr); + outp += rlen; + plen = sprintf (outp, "%s ", prefix); + outp += plen; + for (i = 0; i < len; i++) { + plen = sprintf (outp, "%lld ", buf[i]); + outp += plen; + } + + printf ("%s\n", out); + fflush (stdout); + + NCI_Free (out); + + return NC_NOERR; +} +#define NCCHKIOISWAP(V0, V1) \ + fdisps[V0] ^= fdisps[V1]; \ + fdisps[V1] ^= fdisps[V0]; \ + fdisps[V0] ^= fdisps[V1]; \ + mdisps[V0] ^= mdisps[V1]; \ + mdisps[V1] ^= mdisps[V0]; \ + mdisps[V0] ^= mdisps[V1]; \ + lens[V0] ^= lens[V1]; \ + lens[V1] ^= lens[V0]; \ + lens[V0] ^= lens[V1]; + +void ncchkioi_sort_file_offset (int len, MPI_Aint *fdisps, MPI_Aint *mdisps, int *lens) { + int i, j, p; + MPI_Aint at; + + if (len < 16) { + j = 1; + while (j) { + j = 0; + for (i = 0; i < len - 1; i++) { + if (fdisps[i] > fdisps[i + 1]) { + NCCHKIOISWAP (i, i + 1); + j = 1; + } + } + } + } else { + j = len / 2; + p = len - 1; + NCCHKIOISWAP (j, p); + + for (i = j = 0; i < len; i++) { + if (fdisps[i] < fdisps[p]) { + if (i != j) { NCCHKIOISWAP (i, j); } + j++; + } + } + + NCCHKIOISWAP (p, j); + + ncchkioi_sort_file_offset (j, fdisps, mdisps, lens); + ncchkioi_sort_file_offset (len - j - 1, fdisps + j + 1, mdisps + j + 1, lens + j + 1); + } +} + +int ncchkioi_subarray_off_len ( + int ndim, int *tsize, int *tssize, int *tstart, MPI_Offset *off, int *len) { + int err; + int i; + + // Try single row + err = 0; + for (i = 0; i < ndim - 1; i++) { + if (tssize[i] != 1) { + err = -1; + break; + } + } + if (err) { + // Try contiguous block + err = 0; + for (i = 1; i < ndim; i++) { + if (tssize[i] < tsize[i]) { + err = -1; + break; + } + } + if (!err) { + *len = 1; + for (i = 0; i < ndim; i++) { (*len) *= tssize[i]; } + } + } else { + *len = tssize[ndim - 1]; + } + + if (!err) { + *off = 0; + for (i = 0; i < ndim; i++) { (*off) = (*off) * tsize[i] + tstart[i]; } + } + + return err; +} + +#ifdef PNETCDF_PROFILING +int ncchkioi_update_statistics (NC_chk *ncchkp) { + int i, j; + int cid; + NC_chk_var *varp; + + ncchkp->var_size_sum = ncchkp->var_zsize_sum = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + varp = ncchkp->vars.data + i; + if (varp->varkind == NC_CHK_VAR_COMPRESSED) { + for (j = 0; j < varp->nmychunk; j++) { + cid = varp->mychunks[j]; + ncchkp->var_zsize_sum += varp->chunk_index[cid].len; + } + ncchkp->var_size_sum += varp->nmychunk * varp->chunksize; + } + } + + return NC_NOERR; +} +#endif + +int ncchkioi_get_default_chunk_dim (NC_chk *ncchkp) { + int err = NC_NOERR, ret; + int i; + int ndim, dimid; + int len; + char *cur, *pre; + char name[1024]; + char *env = getenv ("PNETCDF_DEFAULT_CHUNK_DIM"); + + if (env != NULL) { + err = ncchkp->driver->inq (ncchkp->ncp, &ndim, NULL, NULL, NULL); + if (err != NC_NOERR) return err; + + if (ndim > ncchkp->ndim) { + ncchkp->chunkdim = NCI_Realloc (ncchkp->chunkdim, ndim * sizeof (int)); + for (i = ncchkp->ndim; i < ndim; i++) { ncchkp->chunkdim[i] = 0; } + ncchkp->ndim = ndim; + } + + cur = pre = env; + for (cur = pre = env; (*cur) != '\0'; cur++) { + if ((*cur) == ';') { + if (sscanf (pre, "%s : %d ;", name, &len) == 2) { + if (len > 0) { + ret = ncchkp->driver->inq_dimid (ncchkp->ncp, name, &dimid); + if (ret == NC_NOERR) { ncchkp->chunkdim[dimid] = len; } + } + } + pre = cur + 1; + } + } + } + + return NC_NOERR; +} + +/* in-place byte swap */ +void ncchkioi_idx_in_swapn (NC_chk_chunk_index_entry *idx, MPI_Offset nelems) { + NC_chk_chunk_index_entry *bufp; + + for (bufp = idx; bufp < idx + nelems; bufp++) { + bufp->off = ((bufp->off & 0x00000000000000FFULL) << 56) | + ((bufp->off & 0x000000000000FF00ULL) << 40) | + ((bufp->off & 0x0000000000FF0000ULL) << 24) | + ((bufp->off & 0x00000000FF000000ULL) << 8) | + ((bufp->off & 0x000000FF00000000ULL) >> 8) | + ((bufp->off & 0x0000FF0000000000ULL) >> 24) | + ((bufp->off & 0x00FF000000000000ULL) >> 40) | + ((bufp->off & 0xFF00000000000000ULL) >> 56); + bufp->len = ((bufp->len) << 24) | (((bufp->len) & 0x0000ff00) << 8) | + (((bufp->len) & 0x00ff0000) >> 8) | (((bufp->len) >> 24)); + } +} \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkioi_var_init.c b/src/drivers/ncchunkio/ncchkioi_var_init.c new file mode 100644 index 000000000..5347dd160 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_var_init.c @@ -0,0 +1,579 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ncmpio/ncmpio_NC.h" +#include "ncchkio_internal.h" + +int ncchkioi_var_init_core ( + NC_chk *ncchkp, NC_chk_var *varp, int nreq, MPI_Offset **starts, MPI_Offset **counts) { + int err = NC_NOERR; + int ret; + int i, j; + int valid; + MPI_Offset len; + NC_chk_var *var; + + if (varp->varkind == NC_CHK_VAR_COMPRESSED) { + if (varp->chunkdim == NULL) { // This is a new uninitialized variable + // Init value + varp->mychunks = NULL; // To be added later + + // Update dimsize on rec dim + if (ncchkp->recdim >= 0) { + if (varp->dimsize[0] < ncchkp->recsize) { varp->dimsize[0] = ncchkp->recsize; } + } + + // Determine its block size + varp->chunkdim = (int *)NCI_Malloc (sizeof (int) * varp->ndim); + varp->nchunks = (int *)NCI_Malloc (sizeof (int) * varp->ndim); + + // First check attribute + valid = 1; + ret = ncchkp->driver->inq_att (ncchkp->ncp, varp->varid, "_chunkdim", NULL, &len); + if (ret == NC_NOERR && len == varp->ndim) { + ret = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_chunkdim", + varp->chunkdim, MPI_INT); + if (ret != NC_NOERR) { valid = 0; } + // chunkdim must be at leasst 1 + for (j = 0; j < varp->ndim; j++) { + if (varp->chunkdim[j] <= 0) { + valid = 0; + printf ("Warning: chunk size invalid, use default"); + break; + } + } + } else { + valid = 0; + } + + // Now, try global default + if ((!valid) && ncchkp->chunkdim) { + valid = 1; + for (i = 0; i < varp->ndim; i++) { + if (ncchkp->chunkdim[varp->dimids[i]] > 0) { + varp->chunkdim[i] = ncchkp->chunkdim[varp->dimids[i]]; + } else { + valid = 0; + break; + } + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_META) + + // Still no clue, try to infer form I/O pattern (expensive) + // If there is no I/O records, the default is just set to entire variable (only 1 chunk) + if (!valid) { + // Infering not supported + err = ncchkioi_calc_chunk_size (ncchkp, varp, nreq, starts, counts); + CHK_ERR + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_META) + + // Calculate total # chunks, # chunks along each dim, chunksize + varp->nchunkrec = 1; + varp->chunksize = NC_Type_size (varp->xtype); + for (i = 0; i < varp->ndim; i++) { // chunkdim must be at leasst 1 + if (varp->dimsize[i] % varp->chunkdim[i] == 0) { + varp->nchunks[i] = (int)(varp->dimsize[i] / (MPI_Offset)varp->chunkdim[i]); + } else { + varp->nchunks[i] = (int)(varp->dimsize[i] / (MPI_Offset)varp->chunkdim[i] + 1); + } + if (i > 0) { varp->nchunkrec *= varp->nchunks[i]; } + varp->chunksize *= varp->chunkdim[i]; + } + if (varp->isrec) { + varp->nrec = varp->nchunks[0]; + varp->nrecalloc = ncchkp->default_recnalloc; + while (varp->nrecalloc < varp->nchunks[0]) { + varp->nrecalloc *= NC_CHK_REC_MULTIPLIER; + } + } else { + varp->nrec = 1; + varp->nrecalloc = 1; + varp->nchunkrec *= varp->nchunks[0]; + } + varp->nchunk = varp->nchunkrec * varp->nrec; + varp->nchunkalloc = varp->nrecalloc * varp->nchunkrec; + + // Calculate number of chunks below each dimension + varp->cidsteps = (int *)NCI_Malloc (sizeof (int) * varp->ndim); + varp->cidsteps[varp->ndim - 1] = 1; + for (i = varp->ndim - 2; i >= 0; i--) { + varp->cidsteps[i] = varp->cidsteps[i + 1] * varp->nchunks[i + 1]; + } + + // Determine block ownership + varp->dirty = (int *)NCI_Malloc (sizeof (int) * varp->nchunkalloc); + varp->chunk_cache = (NC_chk_cache **)NCI_Malloc (sizeof (char *) * varp->nchunkalloc); + memset (varp->chunk_cache, 0, sizeof (char *) * varp->nchunkalloc); + memset (varp->dirty, 0, sizeof (int) * varp->nchunkalloc); + + // Block ownership to be decisded later + varp->chunk_owner = (int *)NCI_Malloc (sizeof (int) * varp->nchunkalloc); + + // Determine block offset + varp->chunk_index = (NC_chk_chunk_index_entry *)NCI_Malloc ( + sizeof (NC_chk_chunk_index_entry) * (varp->nchunkalloc + 1)); + + // Try if there are offset recorded in attributes, it can happen after opening a file + if (varp->isnew) { + varp->metaoff = -1; + ; + memset (varp->chunk_index, 0, + sizeof (NC_chk_chunk_index_entry) * (varp->nchunk + 1)); + } + + /* Select compression driver based on attribute */ + ret = ncchkp->driver->inq_att (ncchkp->ncp, varp->varid, "_filter", NULL, &len); + if (ret == NC_NOERR && len == 1) { + ret = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_filter", + &(varp->filter), MPI_INT); + if (ret != NC_NOERR) { return err; } + } else { + varp->filter = ncchkp->default_filter; + } + switch (varp->filter) { + case NC_CHK_FILTER_NONE: + varp->filter_driver = NULL; + break; + case NC_CHK_FILTER_DUMMY: + varp->filter_driver = ncchk_dummy_inq_driver (); + break; +#ifdef ENABLE_ZLIB + case NC_CHK_FILTER_ZLIB: + varp->filter_driver = ncchk_zlib_inq_driver (); + break; +#endif +#ifdef ENABLE_SZ + case NC_CHK_FILTER_SZ: + varp->filter_driver = ncchk_sz_inq_driver (); + break; +#endif + default: + if (ncchkp->rank == 0) { + printf ("Warning: Unknown filter driver id %d, use NC_CHK_FILTER_DUMMY\n", + varp->filter); + } + varp->filter_driver = ncchk_dummy_inq_driver (); + break; + break; + } + + // Update max ndim and chunksize + if (ncchkp->max_ndim < varp->ndim) { ncchkp->max_ndim = varp->ndim; } + if (ncchkp->max_chunk_size < varp->chunksize) { + ncchkp->max_chunk_size = varp->chunksize; + } + + if (ncchkp->cache_limit_hint == -1) { + ncchkp->cache_limit += (size_t) (varp->nmychunkrec) * (size_t) (varp->chunksize); + } + } + } + +err_out:; + return err; +} + +int ncchkioi_var_init ( + NC_chk *ncchkp, NC_chk_var *varp, int nreq, MPI_Offset **starts, MPI_Offset **counts) { + int err; + + err = ncchkioi_var_init_core (ncchkp, varp, nreq, starts, counts); + CHK_ERR + + if (varp->varkind == NC_CHK_VAR_COMPRESSED) { + err = ncchkioi_calc_chunk_owner (ncchkp, varp, nreq, starts, counts); + CHK_ERR + } + +err_out:; + return err; +} + +void ncchkioi_var_free (NC_chk_var *varp) { + int i; + + if (varp->chunkdim != NULL) { + NCI_Free (varp->dimsize); + NCI_Free (varp->chunkdim); + NCI_Free (varp->dimids); + NCI_Free (varp->nchunks); + NCI_Free (varp->cidsteps); + NCI_Free (varp->chunk_index); + NCI_Free (varp->chunk_owner); + NCI_Free (varp->dirty); + // for(i = 0; i < varp->nmychunk; i++){ + // if (varp->chunk_cache[varp->mychunks[i]] != NULL){ + // NCI_Free(varp->chunk_cache[varp->mychunks[i]]); + // } + //} + NCI_Free (varp->chunk_cache); + NCI_Free (varp->mychunks); + } +} + +int ncchkioi_init_nvar_core_gather (NC_chk *ncchkp, + int nvar, + NC_chk_var **varps, + int *rcnt, + int *roff, + MPI_Offset **starts, + MPI_Offset **counts) { + int err = NC_NOERR; + int i, j; + NC_chk_var *varp; + ncchkioi_chunk_overlap_t *ocnt[2], *ocnt_all[2]; + size_t ocnt_size[2]; + MPI_Status stat; + MPI_Request req; + + // Iinit vars + ocnt_size[0] = ocnt_size[1] = 0; + ocnt[0] = ocnt[1] = NULL; + for (i = 0; i < nvar; i++) { + varp = varps[i]; + j = i & 1; + + err = ncchkioi_var_init_core (ncchkp, varp, rcnt[i], starts + roff[i], counts + roff[i]); + CHK_ERR + + if (varp->varkind == NC_CHK_VAR_COMPRESSED) { + if (varp->nchunkrec > ocnt_size[j]) { + ocnt_size[j] = varp->nchunkrec; + NCI_Free (ocnt[j]); + ocnt[j] = (ncchkioi_chunk_overlap_t *)NCI_Malloc ( + sizeof (ncchkioi_chunk_overlap_t) * varp->nchunkrec * 2); + ocnt_all[j] = ocnt[j] + varp->nchunkrec; + } + + err = ncchkioi_calc_chunk_overlap (ncchkp, varp, rcnt[i], starts, counts, ocnt[j]); + CHK_ERR + } + + if ((i > 0) && (req != MPI_REQUEST_NULL)) { // Wait comm for prev var + err = MPI_Wait (&req, &stat); + ncchkioi_assign_chunk_owner (ncchkp, varps[i - 1], ocnt_all[(i - 1) & 1]); + ncchkioi_write_chunk_ocnt (ncchkp, varps[i - 1], ocnt[(i - 1) & 1], + sizeof (ncchkioi_chunk_overlap_t)); + } + + if (varp->varkind == NC_CHK_VAR_COMPRESSED) { + err = ncchkioi_sync_ocnt_reduce (ncchkp, varp->nchunkrec, ocnt[j], ocnt_all[j], &req); + CHK_ERR + } else { + req = MPI_REQUEST_NULL; + } + } + // Last var + if (req != MPI_REQUEST_NULL) { + err = MPI_Wait (&req, &stat); + ncchkioi_assign_chunk_owner (ncchkp, varp, ocnt_all[(i - 1) & 1]); + ncchkioi_write_chunk_ocnt (ncchkp, varp, ocnt[(i - 1) & 1], + sizeof (ncchkioi_chunk_overlap_t)); + } + +err_out:; + NCI_Free (ocnt[0]); + NCI_Free (ocnt[1]); + return err; +} + +int ncchkioi_init_nvar_core_reduce (NC_chk *ncchkp, + int nvar, + NC_chk_var **varps, + int *rcnt, + int *roff, + MPI_Offset **starts, + MPI_Offset **counts) { + int err = NC_NOERR; + int i, j; + NC_chk_var *varp; + ncchkioi_chunk_overlap_t *ocnt[2], *ocnt_all[2]; + size_t ocnt_size[2]; + MPI_Status stat; + MPI_Request req; + + // Iinit vars + ocnt_size[0] = ocnt_size[1] = 0; + ocnt[0] = ocnt[1] = NULL; + for (i = 0; i < nvar; i++) { + varp = varps[i]; + j = i & 1; + + err = ncchkioi_var_init_core (ncchkp, varp, rcnt[i], starts + roff[i], counts + roff[i]); + CHK_ERR + + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_COWN) + + if (varp->varkind == NC_CHK_VAR_COMPRESSED) { + if (varp->nchunkrec > ocnt_size[j]) { + ocnt_size[j] = varp->nchunkrec; + NCI_Free (ocnt[j]); + ocnt[j] = (ncchkioi_chunk_overlap_t *)NCI_Malloc ( + sizeof (ncchkioi_chunk_overlap_t) * varp->nchunkrec * 2); + ocnt_all[j] = ocnt[j] + varp->nchunkrec; + } + + err = ncchkioi_calc_chunk_overlap (ncchkp, varp, rcnt[i], starts + roff[i], + counts + roff[i], ocnt[j]); + CHK_ERR + } + + if ((i > 0) && (req != MPI_REQUEST_NULL)) { // Wait comm for prev var + err = MPI_Wait (&req, &stat); + ncchkioi_assign_chunk_owner (ncchkp, varps[i - 1], ocnt_all[(i - 1) & 1]); + ncchkioi_write_chunk_ocnt (ncchkp, varps[i - 1], ocnt[(i - 1) & 1], + sizeof (ncchkioi_chunk_overlap_t)); + } + + if (varp->varkind == NC_CHK_VAR_COMPRESSED) { + ncchkioi_sync_ocnt_reduce (ncchkp, varp->nchunkrec, ocnt[j], ocnt_all[j], &req); + } else { + req = MPI_REQUEST_NULL; + } + + NC_CHK_TIMER_STOPEX (NC_CHK_TIMER_VAR_INIT_COWN, NC_CHK_TIMER_VAR_INIT_META) + } + // Last var + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_COWN) + if (req != MPI_REQUEST_NULL) { + err = MPI_Wait (&req, &stat); + ncchkioi_assign_chunk_owner (ncchkp, varp, ocnt_all[(i - 1) & 1]); + ncchkioi_write_chunk_ocnt (ncchkp, varp, ocnt[(i - 1) & 1], + sizeof (ncchkioi_chunk_overlap_t)); + } + NC_CHK_TIMER_STOPEX (NC_CHK_TIMER_VAR_INIT_COWN, NC_CHK_TIMER_VAR_INIT_META) + +err_out:; + NCI_Free (ocnt[0]); + NCI_Free (ocnt[1]); + return err; +} + +int ncchkioi_init_nvar (NC_chk *ncchkp, int nput, int *putreqs, int nget, int *getreqs) { + int err = NC_NOERR, ret; + int i, j; + int nflag; + unsigned int *flag, *flag_all; + int nvar; + int *vmap; + NC_chk_var *varp; + NC_chk_var **varps; + int *rcnt, *roff; + MPI_Offset **starts, **counts; + NC_chk_req *req; + int nread; + int *lens; + MPI_Aint *fdisps, *mdisps; + MPI_Datatype ftype, mtype; + MPI_Status status; + + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_META) + + CHK_ERR_ALLREDUCE (MPI_IN_PLACE, &(ncchkp->recsize), 1, MPI_LONG_LONG, MPI_MAX, + ncchkp->comm); // Sync number of recs + + // Flag of touched vars + nflag = ncchkp->vars.cnt / 32 + 1; + flag = (unsigned int *)NCI_Malloc (sizeof (int) * nflag * 2); + CHK_PTR (flag) + flag_all = flag + nflag; + memset (flag, 0, sizeof (int) * nflag); + for (i = 0; i < nput; i++) { + req = ncchkp->putlist.reqs + putreqs[i]; + flag[req->varid >> 5] |= 1u << (req->varid % 32); + } + for (i = 0; i < nget; i++) { + req = ncchkp->getlist.reqs + getreqs[i]; + flag[req->varid >> 5] |= 1u << (req->varid % 32); + } + + // Sync flag + CHK_ERR_ALLREDUCE (flag, flag_all, nflag, MPI_UNSIGNED, MPI_BOR, ncchkp->comm); + + // Build a skip list of touched vars + nvar = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + if (flag_all[i >> 5] & (1u << (i % 32))) { + if ((ncchkp->vars.data + i)->chunkdim == NULL) { // If not yet inited + nvar++; + } else { + flag_all[i >> 5] ^= (1u << (i % 32)); + if ((ncchkp->vars.data + i)->dimsize[0] < ncchkp->recsize) { + ncchkioi_var_resize (ncchkp, ncchkp->vars.data + i); + } + } + } + } + varps = (NC_chk_var **)NCI_Malloc (sizeof (NC_chk_var *) * nvar); + CHK_PTR (varps) + vmap = (int *)NCI_Malloc (sizeof (int) * ncchkp->vars.cnt); + CHK_PTR (vmap) + nvar = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + if (flag_all[i >> 5] & (1u << (i % 32))) { + varps[nvar] = ncchkp->vars.data + i; + vmap[i] = nvar++; + } + } + + // Count reqs for each var + roff = (int *)NCI_Malloc (sizeof (int) * (nvar + 1)); + CHK_PTR (roff) + rcnt = (int *)NCI_Malloc (sizeof (int) * nvar); + CHK_PTR (rcnt) + memset (rcnt, 0, sizeof (int) * nvar); + for (i = 0; i < nput; i++) { + req = ncchkp->putlist.reqs + putreqs[i]; + j = req->varid; + if (flag_all[j >> 5] & (1u << (j % 32))) { rcnt[vmap[j]] += req->nreq; } + } + for (i = 0; i < nget; i++) { + req = ncchkp->getlist.reqs + getreqs[i]; + j = req->varid; + if (flag_all[j >> 5] & (1u << (j % 32))) { rcnt[vmap[j]] += req->nreq; } + } + roff[0] = 0; + for (i = 0; i < nvar; i++) { roff[i + 1] = roff[i] + rcnt[i]; } + + // Gather starts and counts + starts = (MPI_Offset **)NCI_Malloc (sizeof (MPI_Offset *) * roff[nvar] * 2); + CHK_PTR (starts) + counts = starts + roff[nvar]; + memset (rcnt, 0, sizeof (int) * nvar); + for (i = 0; i < nput; i++) { + req = ncchkp->putlist.reqs + putreqs[i]; + j = req->varid; + if (flag_all[j >> 5] & (1u << (j % 32))) { + j = vmap[req->varid]; + if (req->nreq > 1) { + memcpy (starts + roff[j] + rcnt[j], req->starts, sizeof (MPI_Offset *) * req->nreq); + memcpy (counts + roff[j] + rcnt[j], req->counts, sizeof (MPI_Offset *) * req->nreq); + rcnt[j] += req->nreq; + } else { + starts[roff[j] + rcnt[j]] = req->start; + counts[roff[j] + (rcnt[j]++)] = req->count; + } + } + } + for (i = 0; i < nget; i++) { + req = ncchkp->getlist.reqs + getreqs[i]; + j = req->varid; + if (flag_all[j >> 5] & (1u << (j % 32))) { + j = vmap[req->varid]; + if (req->nreq > 1) { + memcpy (starts + roff[j] + rcnt[j], req->starts, sizeof (MPI_Offset *) * req->nreq); + memcpy (counts + roff[j] + rcnt[j], req->counts, sizeof (MPI_Offset *) * req->nreq); + rcnt[j] += req->nreq; + } else { + starts[roff[j] + rcnt[j]] = req->start; + counts[roff[j] + (rcnt[j]++)] = req->count; + } + } + } + + // Buffer for index table type + lens = NCI_Malloc (sizeof (int) * nvar); + CHK_PTR (lens) + fdisps = NCI_Malloc (sizeof (MPI_Aint) * nvar * 2); + CHK_PTR (fdisps) + mdisps = fdisps + nvar; + nread = 0; + + // Iinit vars + ncchkp->cown_size = 0; // Reset owner penalty + err = ncchkioi_init_nvar_core_reduce (ncchkp, nvar, varps, rcnt, roff, starts, counts); + CHK_ERR + + // Read the index table for existing variables + // MPI Type to load the index table for existing variables + for (i = 0; i < nvar; i++) { + varp = varps[i]; + if (!(varp->isnew)) { + ret = ncchkp->driver->get_att (ncchkp->ncp, varp->varid, "_metaoffset", + &(varp->metaoff), MPI_LONG_LONG); + if (ret == NC_NOERR) { + lens[nread] = sizeof (NC_chk_chunk_index_entry) * (varp->nchunk); + fdisps[nread] = varp->metaoff; + mdisps[nread++] = (MPI_Aint) (varp->chunk_index); + } else { + varp->metaoff = -1; + memset (varp->chunk_index, 0, + sizeof (NC_chk_chunk_index_entry) * (varp->nchunk + 1)); + } + } + } + if (nread) { + ncchkioi_sort_file_offset (nread, fdisps, mdisps, lens); + + MPI_Type_create_hindexed (nread, lens, fdisps, MPI_BYTE, &ftype); + CHK_ERR_TYPE_COMMIT (&ftype); + + MPI_Type_create_hindexed (nread, lens, mdisps, MPI_BYTE, &mtype); + CHK_ERR_TYPE_COMMIT (&mtype); + + // Set file view + CHK_ERR_SET_VIEW (((NC *)(ncchkp->ncp))->collective_fh, ((NC *)(ncchkp->ncp))->begin_var, + MPI_BYTE, ftype, "native", MPI_INFO_NULL); + + // Read data + CHK_ERR_READ_AT_ALL (((NC *)(ncchkp->ncp))->collective_fh, 0, MPI_BOTTOM, 1, mtype, + &status); + + // Restore file view + CHK_ERR_SET_VIEW (((NC *)(ncchkp->ncp))->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", + MPI_INFO_NULL); + +#ifdef WORDS_BIGENDIAN // Switch back to little endian + for (i = 0; i < nvar; i++) { + ncchkioi_idx_in_swapn (varps[i]->chunk_index, varps[i]->nchunk + 1); + } +#endif + + MPI_Type_free (&ftype); + MPI_Type_free (&mtype); + } + + NCI_Free (lens); + NCI_Free (fdisps); + + NCI_Free (flag); + NCI_Free (varps); + NCI_Free (vmap); + NCI_Free (roff); + NCI_Free (rcnt); + NCI_Free (starts); + +err_out:; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_META) + return err; +} diff --git a/src/drivers/ncchunkio/ncchkioi_var_rd.c b/src/drivers/ncchunkio/ncchkioi_var_rd.c new file mode 100644 index 000000000..49633ede0 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_var_rd.c @@ -0,0 +1,761 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ncmpio/ncmpio_NC.h" +#include "ncchkio_internal.h" + +int ncchkioi_load_var (NC_chk *ncchkp, NC_chk_var *varp, int nchunk, int *cids) { + int err = NC_NOERR; + int i; + int cid; + int get_size; + + int dsize; + MPI_Offset bsize; + + int *lens; + MPI_Aint *fdisps, *mdisps; + MPI_Status status; + MPI_Datatype ftype, mtype; // Memory and file datatype + + char **zbufs; + + NC *ncp = (NC *)(ncchkp->ncp); + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_IO) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_IO_INIT) + + // -1 means all chunks + if (nchunk < 0) { + nchunk = varp->nmychunk; + cids = varp->mychunks; + } + + // Allocate buffer for I/O + lens = (int *)NCI_Malloc (sizeof (int) * nchunk); + fdisps = (MPI_Aint *)NCI_Malloc (sizeof (MPI_Aint) * nchunk * 2); + mdisps = fdisps + nchunk; + zbufs = (char **)NCI_Malloc (sizeof (char *) * nchunk); + + /* Carry our coll I/O + * OpenMPI will fail when set view or do I/O on type created with MPI_Type_create_hindexed when + * count is 0 We use a dummy call inplace of type with 0 count + */ + if (nchunk > 0) { + // Create file type + bsize = 0; + for (i = 0; i < nchunk; i++) { + cid = cids[i]; + // offset and length of compressed chunks + lens[i] = varp->chunk_index[cid].len; + fdisps[i] = (MPI_Aint) (varp->chunk_index[cid].off) + ncp->begin_var; + mdisps[i] = bsize; + // At the same time, we record the size of buffer we need + bsize += (MPI_Offset)lens[i]; + } + + // Allocate buffer for compressed data + zbufs[0] = (char *)NCI_Malloc (bsize); + for (i = 1; i < nchunk; i++) { + zbufs[i] = zbufs[i - 1] + varp->chunk_index[cids[i - 1]].len; + } + + ncchkioi_sort_file_offset (nchunk, fdisps, mdisps, lens); + + MPI_Type_create_hindexed (nchunk, lens, fdisps, MPI_BYTE, &ftype); + CHK_ERR_TYPE_COMMIT (&ftype); + + MPI_Type_create_hindexed (nchunk, lens, mdisps, MPI_BYTE, &mtype); + CHK_ERR_TYPE_COMMIT (&mtype); + + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_GET_IO_INIT, NC_CHK_TIMER_GET_IO_RD) + + // Perform MPI-IO + // Set file view + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, ftype, "native", MPI_INFO_NULL); + // Write data + CHK_ERR_READ_AT_ALL (ncp->collective_fh, 0, zbufs[0], 1, mtype, &status); + // Restore file view + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_GET_IO_RD, NC_CHK_TIMER_GET_IO_INIT) + +#ifdef _USE_MPI_GET_COUNT + MPI_Get_count (&status, MPI_BYTE, &get_size); +#else + MPI_Type_size (ftype, &get_size); +#endif + ncchkp->getsize += get_size; + + // Free type + MPI_Type_free (&ftype); + MPI_Type_free (&mtype); + } else { + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_GET_IO_INIT, NC_CHK_TIMER_GET_IO_RD) + + // Follow coll I/O with dummy call + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + CHK_ERR_READ_AT_ALL (ncp->collective_fh, 0, &i, 0, MPI_BYTE, &status); + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_GET_IO_RD, NC_CHK_TIMER_GET_IO_INIT) + } + + // Decompress each chunk + // Allocate chunk cache if not allocated + if (varp->filter_driver != NULL) { + varp->filter_driver->init (MPI_INFO_NULL); + dsize = varp->chunksize; + for (i = 0; i < nchunk; i++) { + cid = cids[i]; + if (varp->chunk_cache[cid] == NULL) { + err = ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + } else { + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_IO_DECOM) + varp->filter_driver->decompress (zbufs[i], lens[i], varp->chunk_cache[cid]->buf, &dsize, + varp->ndim, varp->chunkdim, varp->etype); + NC_CHK_TIMER_STOPEX (NC_CHK_TIMER_GET_IO_DECOM, NC_CHK_TIMER_GET_IO_INIT) + + if (dsize != varp->chunksize) { printf ("Decompress Error\n"); } + } + varp->filter_driver->finalize (); + } else { + for (i = 0; i < nchunk; i++) { + cid = cids[i]; + if (varp->chunk_cache[cid] == NULL) { + err = ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_IO_DECOM) + memcpy (varp->chunk_cache[cid]->buf, zbufs[i], lens[i]); + NC_CHK_TIMER_STOPEX (NC_CHK_TIMER_GET_IO_DECOM, NC_CHK_TIMER_GET_IO_INIT) + } else { + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_IO_INIT) + + // Free buffers + if (nchunk > 0) { NCI_Free (zbufs[0]); } + NCI_Free (zbufs); + + NCI_Free (lens); + NCI_Free (fdisps); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_IO) + +err_out:; + return err; +} + +int ncchkioi_load_nvar (NC_chk *ncchkp, int nvar, int *varids, int *lo, int *hi) { + int err = NC_NOERR; + int i, j, k, l; + int cid, vid; + int get_size; + + int nchunk; + + int dsize; + MPI_Offset bsize; + + int *lens; + MPI_Aint *fdisps, *mdisps; + MPI_Status status; + MPI_Datatype ftype, mtype; // Memory and file datatype + + char **zbufs; + + NC *ncp = (NC *)(ncchkp->ncp); + NC_chk_var *varp; + NC_var *ncvarp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_IO) + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_IO_INIT) + + // -1 means all chunks + nchunk = 0; + for (i = 0; i < nvar; i++) { + varp = ncchkp->vars.data + varids[i]; + + for (j = lo[i]; j < hi[i]; j++) { + cid = varp->mychunks[j]; + if (varp->chunk_cache[cid] == NULL && varp->chunk_index[cid].len > 0) { nchunk++; } + } + } + + // Allocate buffer for I/O + lens = (int *)NCI_Malloc (sizeof (int) * nchunk); + fdisps = (MPI_Aint *)NCI_Malloc (sizeof (MPI_Aint) * nchunk * 2); + mdisps = fdisps + nchunk; + zbufs = (char **)NCI_Malloc (sizeof (char *) * nchunk); + + /* Carry our coll I/O + * OpenMPI will fail when set view or do I/O on type created with MPI_Type_create_hindexed when + * count is 0 We use a dummy call inplace of type with 0 count + */ + if (nchunk > 0) { + // Create file type + bsize = 0; + k = 0; + for (i = 0; i < nvar; i++) { + varp = ncchkp->vars.data + varids[i]; + + for (j = lo[i]; j < hi[i]; j++) { + cid = varp->mychunks[j]; + + // We only need to read when it is not in cache + if (varp->chunk_cache[cid] == NULL && varp->chunk_index[cid].len > 0) { + // offset and length of compressed chunks + lens[k] = varp->chunk_index[cid].len; + fdisps[k] = (MPI_Aint) (varp->chunk_index[cid].off + ncp->begin_var); + mdisps[k] = bsize; + // At the same time, we record the size of buffer we need + bsize += (MPI_Offset)lens[k++]; + } + } + } + + // Allocate buffer for compressed data + // We allocate it continuously so no mem type needed + zbufs[0] = (char *)NCI_Malloc (bsize); + for (j = 1; j < nchunk; j++) { zbufs[j] = zbufs[j - 1] + lens[j - 1]; } + + ncchkioi_sort_file_offset (k, fdisps, mdisps, lens); + + MPI_Type_create_hindexed (nchunk, lens, fdisps, MPI_BYTE, &ftype); + CHK_ERR_TYPE_COMMIT (&ftype); + + MPI_Type_create_hindexed (nchunk, lens, mdisps, MPI_BYTE, &mtype); + CHK_ERR_TYPE_COMMIT (&mtype); + + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_GET_IO_INIT, NC_CHK_TIMER_GET_IO_RD) + + // Perform MPI-IO + // Set file view + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, ftype, "native", MPI_INFO_NULL); + // Write data + CHK_ERR_READ_AT_ALL (ncp->collective_fh, 0, zbufs[0], 1, mtype, &status); + // Restore file view + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + +#ifdef _USE_MPI_GET_COUNT + MPI_Get_count (&status, MPI_BYTE, &get_size); +#else + MPI_Type_size (ftype, &get_size); +#endif + ncchkp->getsize += get_size; + + // Free type + MPI_Type_free (&ftype); + MPI_Type_free (&mtype); + + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_GET_IO_RD, NC_CHK_TIMER_GET_IO_CACHE) + + k = 0; + for (i = 0; i < nvar; i++) { + varp = ncchkp->vars.data + varids[i]; + dsize = varp->chunksize; + + // Decompress each chunk + if (varp->filter_driver != NULL) { + varp->filter_driver->init (MPI_INFO_NULL); + + for (j = lo[i]; j < hi[i]; j++) { + cid = varp->mychunks[j]; + + // Allocate chunk cache if not allocated + if (varp->chunk_cache[cid] == NULL) { + err = + ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + + // Perform decompression + if (varp->chunk_index[cid].len > 0) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_IO_DECOM) + varp->filter_driver->decompress (zbufs[k], lens[k], varp->chunk_cache[cid]->buf, + &dsize, varp->ndim, varp->chunkdim, varp->etype); + if (dsize != varp->chunksize) { printf ("Decompress Error\n"); } + k++; + NC_CHK_TIMER_STOPEX (NC_CHK_TIMER_GET_IO_DECOM, + NC_CHK_TIMER_GET_IO_CACHE) + } else { + memset (varp->chunk_cache[cid]->buf, 0, varp->chunksize); + } + } else { + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + } + varp->filter_driver->finalize (); + } else { + for (j = lo[i]; j < hi[i]; j++) { + cid = varp->mychunks[j]; + + // Allocate chunk cache if not allocated + if (varp->chunk_cache[cid] == NULL) { + err = + ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + + if (varp->chunk_index[cid].len > 0) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_IO_DECOM) + memcpy (varp->chunk_cache[cid]->buf, zbufs[k], lens[k]); + k++; + NC_CHK_TIMER_STOPEX (NC_CHK_TIMER_GET_IO_DECOM, + NC_CHK_TIMER_GET_IO_CACHE) + } else { + memset (varp->chunk_cache[cid]->buf, 0, varp->chunksize); + } + } else { + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + } + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_IO_CACHE) + } else { + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_GET_IO_INIT, NC_CHK_TIMER_GET_IO_CACHE) + + for (i = 0; i < nvar; i++) { + varp = ncchkp->vars.data + varids[i]; + + for (j = lo[i]; j < hi[i]; j++) { + cid = varp->mychunks[j]; + + // Allocate chunk cache if not allocated + if (varp->chunk_cache[cid] == NULL) { + err = ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + memset (varp->chunk_cache[cid]->buf, 0, varp->chunksize); + } else { + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + } + } + + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_GET_IO_CACHE, NC_CHK_TIMER_GET_IO_RD) + + // Follow coll I/O with dummy call + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + CHK_ERR_READ_AT_ALL (ncp->collective_fh, 0, &i, 0, MPI_BYTE, &status); + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_IO_RD) + } + + // Free buffers + if (nchunk > 0) { NCI_Free (zbufs[0]); } + NCI_Free (zbufs); + + NCI_Free (lens); + NCI_Free (fdisps); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_IO) + +err_out:; + return err; +} + +int ncchkioi_load_var_bg (NC_chk *ncchkp, NC_chk_var *varp, int nchunk, int *cids) { + int err; + int i; + int cid; + int get_size; + + int dsize; + MPI_Offset bsize; + + int *lens; + MPI_Aint *fdisps, *mdisps; + MPI_Status status; + MPI_Datatype ftype, mtype; // Memory and file datatype + + char **zbufs; + + NC *ncp = (NC *)(ncchkp->ncp); + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_BG) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_BG_INIT) + + // -1 means all chunks + if (nchunk < 0) { + nchunk = varp->nmychunk; + cids = varp->mychunks; + } + + // Allocate buffer for I/O + lens = (int *)NCI_Malloc (sizeof (int) * nchunk); + fdisps = (MPI_Aint *)NCI_Malloc (sizeof (MPI_Aint) * nchunk * 2); + mdisps = fdisps + nchunk; + zbufs = (char **)NCI_Malloc (sizeof (char *) * nchunk); + + /* Carry our coll I/O + * OpenMPI will fail when set view or do I/O on type created with MPI_Type_create_hindexed when + * count is 0 We use a dummy call inplace of type with 0 count + */ + if (nchunk > 0) { + // Create file type + bsize = 0; + for (i = 0; i < nchunk; i++) { + cid = cids[i]; + // offset and length of compressed chunks + lens[i] = varp->chunk_index[cid].len; + fdisps[i] = (MPI_Aint) (varp->chunk_index[cid].off) + ncp->begin_var; + mdisps[i] = bsize; + // At the same time, we record the size of buffer we need + bsize += (MPI_Offset)lens[i]; + } + + // Allocate buffer for compressed data + zbufs[0] = (char *)NCI_Malloc (bsize); + for (i = 1; i < nchunk; i++) { + zbufs[i] = zbufs[i - 1] + varp->chunk_index[cids[i - 1]].len; + } + + ncchkioi_sort_file_offset (nchunk, fdisps, mdisps, lens); + + MPI_Type_create_hindexed (nchunk, lens, fdisps, MPI_BYTE, &ftype); + CHK_ERR_TYPE_COMMIT (&ftype); + + MPI_Type_create_hindexed (nchunk, lens, mdisps, MPI_BYTE, &mtype); + CHK_ERR_TYPE_COMMIT (&mtype); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_BG_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_BG_RD) + + // Perform MPI-IO + // Set file view + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, ftype, "native", MPI_INFO_NULL); + // Write data + CHK_ERR_READ_AT_ALL (ncp->collective_fh, 0, zbufs[0], 1, mtype, &status); + // Restore file view + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_BG_RD) + +#ifdef _USE_MPI_PUT_COUNT + MPI_Get_count (&status, MPI_BYTE, &get_size); +#else + MPI_Type_size (ftype, &get_size); +#endif + ncchkp->getsize += get_size; + + // Free type + MPI_Type_free (&ftype); + MPI_Type_free (&mtype); + } else { + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_BG_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_BG_RD) + + // Follow coll I/O with dummy call + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + CHK_ERR_READ_AT_ALL (ncp->collective_fh, 0, &i, 0, MPI_BYTE, &status); + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_BG_RD) + } + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_BG_DECOM) + + // Decompress each chunk + // Allocate chunk cache if not allocated + if (varp->filter_driver != NULL) { + varp->filter_driver->init (MPI_INFO_NULL); + dsize = varp->chunksize; + for (i = 0; i < nchunk; i++) { + cid = cids[i]; + if (varp->chunk_cache[cid] == NULL) { + err = ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + } else { + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + + varp->filter_driver->decompress (zbufs[i], lens[i], varp->chunk_cache[cid]->buf, &dsize, + varp->ndim, varp->chunkdim, varp->etype); + + if (dsize != varp->chunksize) { printf ("Decompress Error\n"); } + } + varp->filter_driver->finalize (); + } else { + for (i = 0; i < nchunk; i++) { + cid = cids[i]; + if (varp->chunk_cache[cid] == NULL) { + err = ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + } else { + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + + memcpy (varp->chunk_cache[cid]->buf, zbufs[i], lens[i]); + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_BG_DECOM) + + // Free buffers + if (nchunk > 0) { NCI_Free (zbufs[0]); } + NCI_Free (zbufs); + + NCI_Free (lens); + NCI_Free (fdisps); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_BG) + +err_out:; + return err; +} + +int ncchkioi_load_nvar_bg (NC_chk *ncchkp, int nvar, int *varids, int *lo, int *hi) { + int err = NC_NOERR; + int i, j, k, l; + int cid, vid; + int get_size; + + int nchunk; + + int dsize; + MPI_Offset bsize; + + int *lens; + MPI_Aint *fdisps, *mdisps; + MPI_Status status; + MPI_Datatype ftype, mtype; // Memory and file datatype + + char **zbufs; + + NC *ncp = (NC *)(ncchkp->ncp); + NC_chk_var *varp; + NC_var *ncvarp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_BG) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_BG_INIT) + + // -1 means all chunks + nchunk = 0; + for (i = 0; i < nvar; i++) { + varp = ncchkp->vars.data + varids[i]; + + for (j = lo[i]; j < hi[i]; j++) { + cid = varp->mychunks[j]; + if (varp->chunk_cache[cid] == NULL && varp->chunk_index[cid].len > 0) { nchunk++; } + } + } + + // Allocate buffer for I/O + lens = (int *)NCI_Malloc (sizeof (int) * nchunk); + fdisps = (MPI_Aint *)NCI_Malloc (sizeof (MPI_Aint) * nchunk * 2); + mdisps = fdisps + nchunk; + zbufs = (char **)NCI_Malloc (sizeof (char *) * nchunk); + + /* Carry our coll I/O + * OpenMPI will fail when set view or do I/O on type created with MPI_Type_create_hindexed when + * count is 0 We use a dummy call inplace of type with 0 count + */ + if (nchunk > 0) { + // Create file type + bsize = 0; + k = 0; + for (i = 0; i < nvar; i++) { + varp = ncchkp->vars.data + varids[i]; + + for (j = lo[i]; j < hi[i]; j++) { + cid = varp->mychunks[j]; + + // We only need to read when it is not in cache + if (varp->chunk_cache[cid] == NULL && varp->chunk_index[cid].len > 0) { + // offset and length of compressed chunks + lens[k] = varp->chunk_index[cid].len; + fdisps[k] = (MPI_Aint) (varp->chunk_index[cid].off + ncp->begin_var); + mdisps[k] = bsize; + // At the same time, we record the size of buffer we need + bsize += (MPI_Offset)lens[k++]; + } + } + } + + // Allocate buffer for compressed data + // We allocate it continuously so no mem type needed + zbufs[0] = (char *)NCI_Malloc (bsize); + for (j = 1; j < nchunk; j++) { zbufs[j] = zbufs[j - 1] + lens[j - 1]; } + + ncchkioi_sort_file_offset (k, fdisps, mdisps, lens); + + MPI_Type_create_hindexed (nchunk, lens, fdisps, MPI_BYTE, &ftype); + CHK_ERR_TYPE_COMMIT (&ftype); + + MPI_Type_create_hindexed (nchunk, lens, mdisps, MPI_BYTE, &mtype); + CHK_ERR_TYPE_COMMIT (&mtype); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_BG_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_BG_RD) + + // Perform MPI-IO + // Set file view + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, ftype, "native", MPI_INFO_NULL); + // Write data + CHK_ERR_READ_AT_ALL (ncp->collective_fh, 0, zbufs[0], 1, mtype, &status); + // Restore file view + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + +#ifdef _USE_MPI_PUT_COUNT + MPI_Get_count (&status, MPI_BYTE, &get_size); +#else + MPI_Type_size (ftype, &get_size); +#endif + ncchkp->getsize += get_size; + + // Free type + MPI_Type_free (&ftype); + MPI_Type_free (&mtype); + + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_PUT_BG_RD, NC_CHK_TIMER_PUT_BG_CACHE) + + k = 0; + for (i = 0; i < nvar; i++) { + varp = ncchkp->vars.data + varids[i]; + dsize = varp->chunksize; + + // Decompress each chunk + if (varp->filter_driver != NULL) { + varp->filter_driver->init (MPI_INFO_NULL); + + for (j = lo[i]; j < hi[i]; j++) { + cid = varp->mychunks[j]; + + // Allocate chunk cache if not allocated + if (varp->chunk_cache[cid] == NULL) { + err = + ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + + // Perform decompression + if (varp->chunk_index[cid].len > 0) { + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_BG_DECOM) + varp->filter_driver->decompress (zbufs[k], lens[k], varp->chunk_cache[cid]->buf, + &dsize, varp->ndim, varp->chunkdim, varp->etype); + if (dsize != varp->chunksize) { printf ("Decompress Error\n"); } + k++; + NC_CHK_TIMER_STOPEX (NC_CHK_TIMER_PUT_BG_DECOM, + NC_CHK_TIMER_PUT_BG_CACHE) + } else { + memset (varp->chunk_cache[cid]->buf, 0, varp->chunksize); + } + } else { + // Cache is always up to date, no need to read and decompress + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + } + varp->filter_driver->finalize (); + } else { + for (j = lo[i]; j < hi[i]; j++) { + cid = varp->mychunks[j]; + + // Allocate chunk cache if not allocated + if (varp->chunk_cache[cid] == NULL) { + err = + ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + + if (varp->chunk_index[cid].len > 0) { + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_BG_DECOM) + memcpy (varp->chunk_cache[cid]->buf, zbufs[k], lens[k]); + k++; + NC_CHK_TIMER_STOPEX (NC_CHK_TIMER_PUT_BG_DECOM, + NC_CHK_TIMER_PUT_BG_CACHE) + } else { + memset (varp->chunk_cache[cid]->buf, 0, varp->chunksize); + } + } else { + // Cache is always up to date, no need to read and decompress + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + } + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_BG_CACHE) + } else { + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_PUT_BG_INIT, NC_CHK_TIMER_PUT_BG_CACHE) + + for (i = 0; i < nvar; i++) { + varp = ncchkp->vars.data + varids[i]; + + for (j = lo[i]; j < hi[i]; j++) { + cid = varp->mychunks[j]; + + // Allocate chunk cache if not allocated + if (varp->chunk_cache[cid] == NULL) { + err = ncchkioi_cache_alloc (ncchkp, varp->chunksize, varp->chunk_cache + cid); + CHK_ERR + // varp->chunk_cache[cid] = (char*)NCI_Malloc(varp->chunksize); + memset (varp->chunk_cache[cid]->buf, 0, varp->chunksize); + } else { + ncchkioi_cache_visit (ncchkp, varp->chunk_cache[cid]); + } + } + } + + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_PUT_BG_CACHE, NC_CHK_TIMER_PUT_BG_RD) + + // Follow coll I/O with dummy call + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + CHK_ERR_READ_AT_ALL (ncp->collective_fh, 0, &i, 0, MPI_BYTE, &status); + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_BG_RD) + } + + // Free buffers + if (nchunk > 0) { NCI_Free (zbufs[0]); } + NCI_Free (zbufs); + + NCI_Free (lens); + NCI_Free (fdisps); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_BG) + +err_out:; + return err; +} diff --git a/src/drivers/ncchunkio/ncchkioi_var_resize.c b/src/drivers/ncchunkio/ncchkioi_var_resize.c new file mode 100644 index 000000000..3a72c36df --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_var_resize.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ncmpio/ncmpio_NC.h" +#include "ncchkio_internal.h" + +int ncchkioi_var_resize (NC_chk *ncchkp, NC_chk_var *varp) { + int err=NC_NOERR; + int i, j; + int cid; + int valid; + MPI_Offset len; + NC_chk_var *var; + + if (varp->varkind == NC_CHK_VAR_COMPRESSED && varp->isrec) { + if (varp->dimsize[0] < ncchkp->recsize) { + int oldnchunk, oldnrec; + int chunkperrec; + int oldnmychunk; + + oldnrec = varp->nrec; + oldnchunk = varp->nchunk; + oldnmychunk = varp->nmychunk; + varp->nrec = varp->dimsize[0] = varp->nchunks[0] = ncchkp->recsize; + varp->nchunk = varp->nchunkrec * varp->nrec; + + // Extend metadata list if needed + if (varp->nrec > varp->nrecalloc) { + while (varp->nrecalloc < varp->nrec) { varp->nrecalloc *= NC_CHK_REC_MULTIPLIER; } + varp->nchunkalloc = varp->nrecalloc * varp->nchunkrec; + + varp->chunk_owner = + (int *)NCI_Realloc (varp->chunk_owner, sizeof (int) * varp->nchunkalloc); + varp->dirty = (int *)NCI_Realloc (varp->dirty, sizeof (int) * varp->nchunkalloc); + varp->chunk_cache = (NC_chk_cache **)NCI_Realloc ( + varp->chunk_cache, sizeof (char *) * varp->nchunkalloc); + for (i = 0; i < oldnmychunk; i++) { + cid = varp->mychunks[i]; + if (varp->chunk_cache[cid] != NULL) { + varp->chunk_cache[cid]->ref = varp->chunk_cache + cid; + } + } + + varp->chunk_index = (NC_chk_chunk_index_entry *)NCI_Realloc ( + varp->chunk_index, sizeof (NC_chk_chunk_index_entry) * (varp->nchunkalloc + 1)); + varp->mychunks = (int *)NCI_Realloc ( + varp->mychunks, sizeof (int) * varp->nrecalloc * varp->nmychunkrec); + + varp->expanded = 1; + } + memset (varp->chunk_index + oldnchunk, 0, + sizeof (NC_chk_chunk_index_entry) * (varp->nchunk - oldnchunk)); + memset (varp->dirty + oldnchunk, 0, sizeof (int) * (varp->nchunk - oldnchunk)); + memset (varp->chunk_cache + oldnchunk, 0, sizeof (char *) * (varp->nchunk - oldnchunk)); + + // Extend block ownership list + if (oldnchunk > 0) { + for (i = oldnchunk; i < varp->nchunk; i += varp->nchunkrec) { + // We reuse chunk mapping of other records + memcpy (varp->chunk_owner + i, varp->chunk_owner, + sizeof (int) * varp->nchunkrec); + } + varp->nmychunk = varp->nmychunkrec * varp->nrec; + for (i = oldnmychunk; i < varp->nmychunk; i += varp->nmychunkrec) { + // We reuse chunk mapping of other records + memcpy (varp->mychunks + i, varp->mychunks, sizeof (int) * varp->nmychunkrec); + } + } else { + err = ncchkioi_calc_chunk_owner (ncchkp, varp, 0, NULL, NULL); + CHK_ERR + + varp->nmychunkrec = 0; + for (i = 0; i < varp->nchunkrec; i++) { + if (varp->chunk_owner[i] == ncchkp->rank) { varp->nmychunkrec++; } + } + varp->mychunks = + (int *)NCI_Realloc (varp->mychunks, sizeof (int) * varp->nmychunkrec * varp->nrecalloc); + + if (ncchkp->cache_limit_hint == -1) { + ncchkp->cache_limit += + (size_t) (varp->nmychunkrec) * (size_t) (varp->chunksize); + } + } + + varp->nmychunk = oldnmychunk; + for (i = oldnchunk; i < varp->nchunk; i++) { + if (varp->chunk_owner[i] == ncchkp->rank) { + varp->mychunks[varp->nmychunk++] = i; + // varp->chunk_cache[i] = (void*)NCI_Malloc(varp->chunksize); // Allocate + // buffer for blocks we own memset(varp->chunk_cache[i], 0 , varp->chunksize); + } + } + + // Update global chunk count + ncchkp->nmychunks += (MPI_Offset) (varp->nmychunk - oldnmychunk); + } + } else { + // Notify ncmpio driver + } + +err_out:; + return err; +} + +int ncchkioi_resize_nvar (NC_chk *ncchkp, int nput, int *putreqs, int nget, int *getreqs) { + int err = NC_NOERR; + int i; + int nflag; + unsigned int *flag = NULL, *flag_all; + int nvar; + int *vids; + NC_chk_req *req; + NC_chk_var *varp; + + CHK_ERR_ALLREDUCE (MPI_IN_PLACE, &(ncchkp->recsize), 1, MPI_LONG_LONG, MPI_MAX, + ncchkp->comm); // Sync number of recs + + // Flag of touched vars + nflag = ncchkp->vars.cnt / 32 + 1; + flag = (unsigned int *)NCI_Malloc (sizeof (int) * nflag * 2); + CHK_PTR (flag) + flag_all = flag + nflag; + memset (flag, 0, sizeof (int) * nflag); + for (i = 0; i < nput; i++) { + req = ncchkp->putlist.reqs + putreqs[i]; + flag[req->varid >> 5] |= 1u << (req->varid % 32); + } + for (i = 0; i < nget; i++) { + req = ncchkp->getlist.reqs + getreqs[i]; + flag[req->varid >> 5] |= 1u << (req->varid % 32); + } + + // Sync flag + CHK_ERR_ALLREDUCE (flag, flag_all, nflag, MPI_UNSIGNED, MPI_BOR, ncchkp->comm); + + // Resize each var + nvar = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + if (flag_all[i >> 5] & (1u << (i % 32))) { + flag_all[i >> 5] ^= (1u << (i % 32)); + if ((ncchkp->vars.data + i)->dimsize[0] < ncchkp->recsize) { + err = ncchkioi_var_resize (ncchkp, ncchkp->vars.data + i); + CHK_ERR + } + } + } + + NCI_Free (flag); + +err_out:; + return err; +} \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkioi_var_wr.c b/src/drivers/ncchunkio/ncchkioi_var_wr.c new file mode 100644 index 000000000..4905c2dac --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_var_wr.c @@ -0,0 +1,638 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ncmpio/ncmpio_NC.h" +#include "ncchkio_internal.h" + +int ncchkioi_save_var (NC_chk *ncchkp, NC_chk_var *varp) { + int i, j, k, l, err = NC_NOERR; + int *zsizes = NULL, *zsizes_all = NULL; + MPI_Datatype mtype, ftype; // Memory and file datatype + int wcnt; + int *lens = NULL; + MPI_Aint *disps = NULL; + MPI_Status status; + MPI_Offset *zoffs = NULL; + MPI_Offset voff; + void **zbufs = NULL; + int zdimid, zvarid; + int put_size; + char name[128]; // Name of objects + NC *ncp = (NC *)(ncchkp->ncp); + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_IO) + + // Allocate buffer for compression + zsizes = (int *)NCI_Malloc (sizeof (int) * varp->nchunk); + CHK_PTR (zsizes) + zbufs = (void **)NCI_Malloc (sizeof (void *) * varp->nmychunk); + CHK_PTR (zbufs) + zsizes_all = (int *)NCI_Malloc (sizeof (int) * varp->nchunk); + CHK_PTR (zsizes_all) + zoffs = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * (varp->nchunk + 1)); + CHK_PTR (zoffs) + + // Allocate buffer for I/O + wcnt = 0; + for (l = 0; l < varp->nmychunk; l++) { + k = varp->mychunks[l]; + if (varp->dirty[k]) { wcnt++; } + } + if (ncchkp->rank == varp->chunk_owner[0]) { wcnt += 1; } + lens = (int *)NCI_Malloc (sizeof (int) * wcnt); + CHK_PTR (lens) + disps = (MPI_Aint *)NCI_Malloc (sizeof (MPI_Aint) * wcnt); + CHK_PTR (disps) + + memset (zsizes, 0, sizeof (int) * varp->nchunk); + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_IO_COM) + + // Compress each chunk we own + if (varp->filter_driver != NULL) { + varp->filter_driver->init (MPI_INFO_NULL); + for (l = 0; l < varp->nmychunk; l++) { + k = varp->mychunks[l]; + + if (varp->dirty[k]) { + // Apply compression + err = varp->filter_driver->compress_alloc (varp->chunk_cache[k]->buf, varp->chunksize, + zbufs + l, zsizes + k, varp->ndim, varp->chunkdim, + varp->etype); + CHK_ERR + } + } + varp->filter_driver->finalize (); + } else { + for (l = 0; l < varp->nmychunk; l++) { + k = varp->mychunks[l]; + if (varp->dirty[k]) { + zbufs[l] = varp->chunk_cache[k]->buf; + zsizes[k] = varp->chunksize; + } + } + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO_COM) + +#ifdef PNETCDF_PROFILING + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_IO_BARR) + MPI_Barrier (ncchkp->comm); + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO_BARR) +#endif + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_IO_SYNC) + + // Sync compressed data size with other processes + CHK_ERR_ALLREDUCE (zsizes, zsizes_all, varp->nchunk, MPI_INT, MPI_MAX, ncchkp->comm); + + if (varp->metaoff < 0 || varp->expanded) { + zoffs[0] = varp->nchunkalloc * sizeof (NC_chk_chunk_index_entry); + } else { + zoffs[0] = 0; + } + for (i = 0; i < varp->nchunk; i++) { zoffs[i + 1] = zoffs[i] + zsizes_all[i]; } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO_SYNC) + + if (zoffs[varp->nchunk] > 0) { // No need to do I/O if no dirty chunk to write + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_IO_INIT) + + /* Write comrpessed variable + * We start by defining data variable and writing metadata + * Then, we create buffer type and file type for data + * Finally MPI collective I/O is used for writing data + */ + + // Enter redefine mode + ncchkp->driver->redef (ncchkp->ncp); + + // Prepare data variable + + // Define dimension for data variable + sprintf (name, "_datablock_dim_%d", ncchkp->nwrite); + err = ncchkp->driver->def_dim (ncchkp->ncp, name, zoffs[varp->nchunk], &zdimid); + if (err != NC_NOERR) return err; + + // Define data variable + sprintf (name, "_datablock_%d", ncchkp->nwrite); + err = ncchkp->driver->def_var (ncchkp->ncp, name, NC_BYTE, 1, &zdimid, &(zvarid)); + if (err != NC_NOERR) return err; + + // Mark as data variable + i = NC_CHK_VAR_DATA; + err = ncchkp->driver->put_att (ncchkp->ncp, zvarid, "_varkind", NC_INT, 1, &i, MPI_INT); + if (err != NC_NOERR) return err; + + // Record serial + ncchkp->nwrite++; + err = ncchkp->driver->put_att (ncchkp->ncp, NC_GLOBAL, "_nwrite", NC_INT, 1, + &(ncchkp->nwrite), MPI_INT); + if (err != NC_NOERR) return err; + + // Metadata offset + // Real metadata offset is only known after enddef + // We reserve the space so we don't need to enter define mode again + if (varp->metaoff < 0) { + err = ncchkp->driver->put_att (ncchkp->ncp, varp->varid, "_metaoffset", NC_INT64, 1, + &(varp->metaoff), MPI_LONG_LONG); + if (err != NC_NOERR) return err; + } + + // Switch to data mode + err = ncchkp->driver->enddef (ncchkp->ncp); + if (err != NC_NOERR) return err; + + // Update metadata + voff = ncp->vars.value[zvarid]->begin; + for (i = 0; i < varp->nchunk; i++) { + if (zsizes_all[i] > 0) { + varp->chunk_index[i].len = zsizes_all[i]; + varp->chunk_index[i].off = zoffs[i] + voff - ncp->begin_var; + } + } + + if (varp->metaoff < 0 || varp->expanded) { + varp->metaoff = voff - ncp->begin_var; + err = ncchkp->driver->put_att (ncchkp->ncp, varp->varid, "_metaoffset", NC_INT64, 1, + &(varp->metaoff), MPI_LONG_LONG); + if (err != NC_NOERR) return err; + + // unset expand flag + varp->expanded = 0; + } + + /* Carry out coll I/O + * OpenMPI will fail when set view or do I/O on type created with MPI_Type_create_hindexed + * when count is 0 We use a dummy call inplace of type with 0 count + */ + if (wcnt > 0) { + // Create file type + l = 0; + if (ncchkp->rank == varp->chunk_owner[0]) { // First chunk owner writes metadata + lens[l] = (varp->nchunk) * sizeof (NC_chk_chunk_index_entry); + disps[l++] = (MPI_Aint)varp->metaoff + ncp->begin_var; + } + for (i = 0; i < varp->nmychunk; i++) { + k = varp->mychunks[i]; + + // Record compressed size + if (varp->dirty[k]) { + lens[l] = zsizes[k]; + disps[l++] = (MPI_Aint) (varp->chunk_index[k].off) + ncp->begin_var; + } + } + MPI_Type_create_hindexed (wcnt, lens, disps, MPI_BYTE, &ftype); + CHK_ERR_TYPE_COMMIT (&ftype); + + // Create memory buffer type + l = 0; + if (ncchkp->rank == varp->chunk_owner[0]) { // First chunk owner writes metadata + lens[l] = (varp->nchunk) * sizeof (NC_chk_chunk_index_entry); + disps[l++] = (MPI_Aint)varp->chunk_index; + } + for (i = 0; i < varp->nmychunk; i++) { + k = varp->mychunks[i]; + + // Record compressed size + if (varp->dirty[k]) { + lens[l] = zsizes[k]; + disps[l++] = (MPI_Aint)zbufs[i]; + } + } + err = MPI_Type_create_hindexed (wcnt, lens, disps, MPI_BYTE, &mtype); + CHK_ERR_TYPE_COMMIT (&mtype); + + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_PUT_IO_INIT, NC_CHK_TIMER_PUT_IO_WR) + +#ifdef WORDS_BIGENDIAN // NetCDF data is big endian + if (ncchkp->rank == varp->chunk_owner[0]) { + ncchkioi_idx_in_swapn (varp - chunk_index, varp->nchunk); + } +#endif + + // Perform MPI-IO + // Set file view + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, ftype, "native", MPI_INFO_NULL); + // Write data + CHK_ERR_WRITE_AT_ALL (ncp->collective_fh, 0, MPI_BOTTOM, 1, mtype, &status); + // Restore file view + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + +#ifdef WORDS_BIGENDIAN // Switch back to little endian + if (ncchkp->rank == varp->chunk_owner[0]) { + ncchkioi_idx_in_swapn (varp - chunk_index, varp->nchunk); + } +#endif + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO_WR) + +#ifdef _USE_MPI_GET_COUNT + MPI_Get_count (&status, MPI_BYTE, &put_size); +#else + MPI_Type_size (mtype, &put_size); +#endif + ncchkp->putsize += put_size; + + // Free type + MPI_Type_free (&ftype); + MPI_Type_free (&mtype); + } else { + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_PUT_IO_INIT, NC_CHK_TIMER_PUT_IO_WR) + + // Follow coll I/O with dummy call + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + CHK_ERR_WRITE_AT_ALL (ncp->collective_fh, 0, MPI_BOTTOM, 0, MPI_BYTE, &status); + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO_WR) + } + } + +err_out:; + // Free buffers + NCI_Free (zsizes); + NCI_Free (zsizes_all); + NCI_Free (zoffs); + for (l = 0; l < varp->nmychunk; l++) { + k = varp->mychunks[l]; + if (varp->dirty[k]) { + if (varp->filter_driver != NULL) { free (zbufs[l]); } + // Clear dirty flag + varp->dirty[k] = 0; + } + } + NCI_Free (zbufs); + + NCI_Free (lens); + NCI_Free (disps); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO) + + return err; +} + +int ncchkioi_save_nvar (NC_chk *ncchkp, int nvar, int *varids) { + int i, j, k, l, err = NC_NOERR; + int vid; // Iterator for variable id + int cid; // Iterator for chunk id + int total_nchunks = 0; + int *zsizes = NULL, *zsizes_all = NULL, *zsizesp = NULL, *zsizes_allp = NULL; + int nreq; + MPI_Offset *zoffs = NULL, *zoffsp; + MPI_Offset start, count, oldzoff, voff; + MPI_Datatype mtype, ftype; // Memory and file datatype + int wcnt, ccnt, wcur, ccur; + int *lens = NULL; + MPI_Aint *mdisps = NULL, *fdisps = NULL; + MPI_Status status; + MPI_Request *reqs = NULL; + int put_size; + void **zbufs = NULL; + int *zdels = NULL; + int zdimid, zvarid; + char name[128]; // Name of objects + NC_chk_var *varp; + NC *ncp = (NC *)(ncchkp->ncp); + NC_var *ncvarp; + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_IO) + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_IO_INIT) + + wcnt = 0; + ccnt = 0; + for (i = 0; i < nvar; i++) { + varp = ncchkp->vars.data + varids[i]; + if (ncchkp->rank == varp->chunk_owner[0]) { wcnt += 1; } + for (l = 0; l < varp->nmychunk; l++) { + k = varp->mychunks[l]; + if (varp->dirty[k]) { ccnt++; } + } + total_nchunks += varp->nchunk + 1; + } + wcnt += ccnt; + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO_INIT) + + // Allocate reqid for metadata + reqs = (MPI_Request *)NCI_Malloc (sizeof (MPI_Request) * nvar); + CHK_PTR (reqs) + + // Allocate buffer for compression + zsizes = (int *)NCI_Malloc (sizeof (int) * total_nchunks); + CHK_PTR (zsizes) + zsizes_all = (int *)NCI_Malloc (sizeof (int) * total_nchunks); + CHK_PTR (zsizes_all) + zbufs = (void **)NCI_Malloc (sizeof (void *) * ccnt); + CHK_PTR (zbufs) + zdels = (int *)NCI_Malloc (sizeof (int) * ccnt); + CHK_PTR (zdels) + zoffs = (MPI_Offset *)NCI_Malloc (sizeof (MPI_Offset) * (total_nchunks + 1)); + CHK_PTR (zoffs) + + // Allocate buffer file type + mdisps = (MPI_Aint *)NCI_Malloc (sizeof (MPI_Aint) * wcnt); + CHK_PTR (mdisps) + lens = (int *)NCI_Malloc (sizeof (int) * wcnt); + CHK_PTR (lens) + fdisps = (MPI_Aint *)NCI_Malloc (sizeof (MPI_Aint) * wcnt); + CHK_PTR (fdisps) + + ccur = 0; + zsizesp = zsizes + nvar; + zsizes_allp = zsizes_all + nvar; + for (vid = 0; vid < nvar; vid++) { + varp = ncchkp->vars.data + varids[vid]; + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_IO_COM) + + oldzoff = zoffs[varp->nchunk]; + + memset (zsizesp, 0, sizeof (int) * varp->nchunk); + + // Compress each chunk we own + if (varp->filter_driver != NULL) { + varp->filter_driver->init (MPI_INFO_NULL); + for (l = 0; l < varp->nmychunk; l++) { + cid = varp->mychunks[l]; + + // Apply compression + if (varp->dirty[cid]) { + zdels[ccur] = 1; + err = varp->filter_driver->compress_alloc (varp->chunk_cache[cid]->buf, varp->chunksize, + zbufs + (ccur++), zsizesp + cid, varp->ndim, + varp->chunkdim, varp->etype); + CHK_ERR + } + } + varp->filter_driver->finalize (); + } else { + for (l = 0; l < varp->nmychunk; l++) { + cid = varp->mychunks[l]; + if (varp->dirty[cid]) { + zsizesp[cid] = varp->chunksize; + zdels[ccur] = 0; + zbufs[ccur++] = varp->chunk_cache[cid]->buf; + } + } + } + + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_PUT_IO_COM, NC_CHK_TIMER_PUT_IO_SYNC) + + // Sync compressed data size with other processes + CHK_ERR_IALLREDUCE (zsizesp, zsizes_allp, varp->nchunk, MPI_INT, MPI_MAX, ncchkp->comm, + reqs + vid); + + if (varp->metaoff < 0 || varp->expanded) { + zsizes_all[vid] = varp->nchunkalloc * sizeof (NC_chk_chunk_index_entry); + } else { + zsizes_all[vid] = 0; + } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO_SYNC) + + zsizesp += varp->nchunk; + zsizes_allp += varp->nchunk; + } + +#ifdef PNETCDF_PROFILING + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_IO_BARR) + MPI_Barrier (ncchkp->comm); + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO_BARR) +#endif + + /* Write comrpessed variable + * We start by defining data variable and writing metadata + * Then, we create buffer type and file type for data + * Finally MPI collective I/O is used for writing data + */ + + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_IO_SYNC) + zsizes_allp = zsizes_all + nvar; + for (vid = 0; vid < nvar; vid++) { + varp = ncchkp->vars.data + varids[vid]; + CHK_ERR_WAIT (reqs + vid, &status); + zsizes_allp += varp->nchunk; + } + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO_SYNC) + + zoffs[0] = 0; + for (i = 0; i < total_nchunks; i++) { zoffs[i + 1] = zoffs[i] + zsizes_all[i]; } + + if (zoffs[total_nchunks] > 0) { // No need to do I/O if no dirty chunk to write + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT_IO_INIT) + + // Prepare data variable + + // Enter redefine mode + ncchkp->driver->redef (ncchkp->ncp); + + // Define dimension for data variable + sprintf (name, "_datablock_dim_%d", ncchkp->nwrite); + err = ncchkp->driver->def_dim (ncchkp->ncp, name, zoffs[total_nchunks], &zdimid); + if (err != NC_NOERR) return err; + + // Define data variable + sprintf (name, "_datablock_%d", ncchkp->nwrite); + err = ncchkp->driver->def_var (ncchkp->ncp, name, NC_BYTE, 1, &zdimid, &zvarid); + if (err != NC_NOERR) return err; + + // Mark as data variable + i = NC_CHK_VAR_DATA; + err = ncchkp->driver->put_att (ncchkp->ncp, zvarid, "_varkind", NC_INT, 1, &i, MPI_INT); + if (err != NC_NOERR) return err; + + // Record serial + ncchkp->nwrite++; + err = ncchkp->driver->put_att (ncchkp->ncp, NC_GLOBAL, "_nwrite", NC_INT, 1, + &(ncchkp->nwrite), MPI_INT); + if (err != NC_NOERR) return err; + + // Metadata offset + for (vid = 0; vid < nvar; vid++) { + varp = ncchkp->vars.data + varids[vid]; + // Reserve space for _metaoffset + if (varp->metaoff < 0) { + err = ncchkp->driver->put_att (ncchkp->ncp, varp->varid, "_metaoffset", NC_INT64, 1, + &(varp->metaoff), MPI_LONG_LONG); + if (err != NC_NOERR) return err; + } + } + + // Switch back to data mode + err = ncchkp->driver->enddef (ncchkp->ncp); + if (err != NC_NOERR) return err; + + voff = ncp->vars.value[zvarid]->begin; + + wcur = ccur = 0; + for (vid = 0; vid < nvar; vid++) { + varp = ncchkp->vars.data + varids[vid]; + + if (varp->metaoff < 0 || varp->expanded) { + varp->metaoff = zoffs[vid] + voff - ncp->begin_var; + err = ncchkp->driver->put_att (ncchkp->ncp, varp->varid, "_metaoffset", NC_INT64, 1, + &(varp->metaoff), MPI_LONG_LONG); + if (err != NC_NOERR) return err; + + // unset expand flag + varp->expanded = 0; + } + + if (ncchkp->rank == varp->chunk_owner[0]) { // First chunk owner writes metadata + lens[wcur] = varp->nchunk * sizeof (NC_chk_chunk_index_entry); + fdisps[wcur] = (MPI_Aint)varp->metaoff + ncp->begin_var; + mdisps[wcur++] = (MPI_Aint) (varp->chunk_index); + + // lens[wcur] = varp->nchunk * sizeof(int); + // fdisps[wcur] = (MPI_Aint)(varp->metaoff + ncp->begin_var + sizeof(long long) * + // varp->nchunkalloc); mdisps[wcur++] = (MPI_Aint)(varp->data_lens); + } + } + + ncchkioi_sort_file_offset (wcur, fdisps, mdisps, lens); + + zsizes_allp = zsizes_all + nvar; + zoffsp = zoffs + nvar; + for (vid = 0; vid < nvar; vid++) { + varp = ncchkp->vars.data + varids[vid]; + + for (cid = 0; cid < varp->nchunk; cid++) { + if (zsizes_allp[cid] > 0) { + varp->chunk_index[cid].len = zsizes_allp[cid]; + varp->chunk_index[cid].off = zoffsp[cid] + voff - ncp->begin_var; + } + } + + /* Paramemter for file and memory type + * We do not know variable file offset until the end of define mode + * We will add the displacement later + */ + for (i = 0; i < varp->nmychunk; i++) { + cid = varp->mychunks[i]; + + // Record parameter + if (varp->dirty[cid]) { + lens[wcur] = varp->chunk_index[cid].len; + fdisps[wcur] = (MPI_Aint) (varp->chunk_index[cid].off) + ncp->begin_var; + mdisps[wcur++] = (MPI_Aint)zbufs[ccur++]; + } + } + + // Clear dirty flag + memset (varp->dirty, 0, varp->nchunk * sizeof (int)); + + zsizes_allp += varp->nchunk; + zoffsp += varp->nchunk; + } + + NC_CHK_TIMER_SWAP (NC_CHK_TIMER_PUT_IO_INIT, NC_CHK_TIMER_PUT_IO_WR) + + /* Carry our coll I/O + * OpenMPI will fail when set view or do I/O on type created with MPI_Type_create_hindexed + * when count is 0 We use a dummy call inplace of type with 0 count + */ + if (wcnt > 0) { + // Create file type + MPI_Type_create_hindexed (wcnt, lens, fdisps, MPI_BYTE, &ftype); + CHK_ERR_TYPE_COMMIT (&ftype); + + // Create memmory type + MPI_Type_create_hindexed (wcnt, lens, mdisps, MPI_BYTE, &mtype); + CHK_ERR_TYPE_COMMIT (&mtype); + +#ifdef WORDS_BIGENDIAN // NetCDF data is big endian + for (vid = 0; vid < nvar; vid++) { + varp = ncchkp->vars.data + varids[vid]; + if (ncchkp->rank == varp->chunk_owner[0]) { + ncchkioi_idx_in_swapn (varp - chunk_index, varp->nchunk + 1); + } + } +#endif + + // Perform MPI-IO + // Set file view + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, ftype, "native", MPI_INFO_NULL); + // Write data + CHK_ERR_WRITE_AT_ALL (ncp->collective_fh, 0, MPI_BOTTOM, 1, mtype, &status); + // Restore file view + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + +#ifdef WORDS_BIGENDIAN // Switch back to little endian + for (vid = 0; vid < nvar; vid++) { + varp = ncchkp->vars.data + varids[vid]; + if (ncchkp->rank == varp->chunk_owner[0]) { + ncchkioi_idx_in_swapn (varp - chunk_index, varp->nchunk + 1); + } + } +#endif + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO_WR) + +#ifdef _USE_MPI_GET_COUNT + MPI_Get_count (&status, MPI_BYTE, &put_size); +#else + MPI_Type_size (mtype, &put_size); +#endif + ncchkp->putsize += put_size; + + // Free type + MPI_Type_free (&ftype); + MPI_Type_free (&mtype); + } else { + // Follow coll I/O with dummy call + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + CHK_ERR_WRITE_AT_ALL (ncp->collective_fh, 0, MPI_BOTTOM, 0, MPI_BYTE, &status); + CHK_ERR_SET_VIEW (ncp->collective_fh, 0, MPI_BYTE, MPI_BYTE, "native", MPI_INFO_NULL); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO_WR) + } + } + +err_out:; + // Free buffers + NCI_Free (zsizes); + NCI_Free (zsizes_all); + NCI_Free (zoffs); + ccur = 0; + for (i = 0; i < ccnt; i++) { + if (zdels[i]) { free (zbufs[i]); } + } + NCI_Free (zbufs); + NCI_Free (zdels); + + NCI_Free (lens); + NCI_Free (fdisps); + NCI_Free (mdisps); + + NCI_Free (reqs); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT_IO) + + return err; +} diff --git a/src/drivers/ncchunkio/ncchkioi_vector.c b/src/drivers/ncchunkio/ncchkioi_vector.c new file mode 100644 index 000000000..adf519eb0 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_vector.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include +#include +#include "ncchkio_internal.h" + +#define STARTSIZE 32 +#define SIZEMUTIPLIER 20 + +int ncchkioi_vector_init(NC_chk_vector *v, int esize){ + v->esize = esize; + v->nalloc = STARTSIZE; + v->size = 0; + v->data = (char*)NCI_Malloc(esize * v->nalloc); + if (v->data == NULL){ + DEBUG_RETURN_ERROR(NC_ENOMEM); + } +} + +int ncchkioi_vector_init_ex(NC_chk_vector *v, int esize, int size){ + v->esize = esize; + v->nalloc = size; + v->size = 0; + v->data = (char*)NCI_Malloc(esize * v->nalloc); + if (v->data == NULL){ + DEBUG_RETURN_ERROR(NC_ENOMEM); + } +} + +void ncchkioi_vector_free(NC_chk_vector *v){ + NCI_Free(v->data); +} + +int ncchkioi_vector_append(NC_chk_vector *v, void *item){ + if (v->size == v->nalloc){ + v->nalloc = v->nalloc * SIZEMUTIPLIER; + v->data = (char*)NCI_Realloc(v->data, v->esize * v->nalloc); + if (v->data == NULL){ + DEBUG_RETURN_ERROR(NC_ENOMEM); + } + } + memcpy(data + v->size * v->esize, item, v->esize); +} \ No newline at end of file diff --git a/src/drivers/ncchunkio/ncchkioi_wait.c b/src/drivers/ncchunkio/ncchkioi_wait.c new file mode 100644 index 000000000..e75eac509 --- /dev/null +++ b/src/drivers/ncchunkio/ncchkioi_wait.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2019, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + */ +/* $Id$ */ + +/* + * This file implements the following PnetCDF APIs. + * + * ncmpi_get_var_all() : dispatcher->get_var() + * ncmpi_put_var_all() : dispatcher->put_var() + * ncmpi_get_var__all() : dispatcher->get_var() + * ncmpi_put_var__all() : dispatcher->put_var() + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ncchkio_internal.h" + +/* Out drive currently can handle only one variable at a time + * We pack all request as a large varn request + */ +int ncchkioi_wait_put_reqs (NC_chk *ncchkp, int nreq, int *reqids, int *stats) { + int err = NC_NOERR; + int i; + unsigned int j; + int nvar, nflag; + unsigned int *flag, *flag_all; + int *vids; + NC_chk_req *req; + + NC_CHK_TIMER_START (NC_CHK_TIMER_WAIT_PUT) + + // Flag of touched vars + nflag = ncchkp->vars.cnt / 32 + 1; + flag = (unsigned int *)NCI_Malloc (sizeof (int) * nflag * 2); + flag_all = flag + nflag; + memset (flag, 0, sizeof (int) * nflag); + for (i = 0; i < nreq; i++) { + req = ncchkp->putlist.reqs + reqids[i]; + flag[req->varid >> 5] |= 1u << (req->varid % 32); + } + + // Sync flag + CHK_ERR_ALLREDUCE (flag, flag_all, nflag, MPI_UNSIGNED, MPI_BOR, ncchkp->comm); + + // Build a skip list of touched vars + nvar = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + if (flag_all[i >> 5] & (1u << (i % 32))) { nvar++; } + } + vids = (int *)NCI_Malloc (sizeof (int) * nvar); + nvar = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + if (flag_all[i >> 5] & (1u << (i % 32))) { vids[nvar++] = i; } + } + + // Perform collective buffer + if (ncchkp->comm_unit == NC_CHK_COMM_CHUNK) { + err = ncchkioi_iput_cb_chunk (ncchkp, nreq, reqids, stats); + } else { + err = ncchkioi_iput_cb_proc (ncchkp, nreq, reqids, stats); + } + CHK_ERR + +#ifdef PNETCDF_PROFILING + NC_CHK_TIMER_START (NC_CHK_TIMER_WAIT_PUT_BARR) + MPI_Barrier (ncchkp->comm); + NC_CHK_TIMER_STOP (NC_CHK_TIMER_WAIT_PUT_BARR) +#endif + + // Perform I/O for comrpessed variables + err = ncchkioi_save_nvar (ncchkp, nvar, vids); + CHK_ERR + +err_out:; + + // Free buffers + NCI_Free (vids); + NCI_Free (flag); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_WAIT_PUT) + + return err; +} + +/* Out drive currently can handle only one variable at a time + * We pack all request as a large varn request + */ +int ncchkioi_wait_get_reqs (NC_chk *ncchkp, int nreq, int *reqids, int *stats) { + int err = NC_NOERR; + int i; + unsigned int j; + int nvar, nflag; + unsigned int *flag, *flag_all; + int *vids; + NC_chk_req *req; + + NC_CHK_TIMER_START (NC_CHK_TIMER_WAIT_GET) + + // Flag of touched vars + nflag = ncchkp->vars.cnt / 32 + 1; + flag = (unsigned int *)NCI_Malloc (sizeof (int) * nflag * 2); + flag_all = flag + nflag; + memset (flag, 0, sizeof (int) * nflag); + for (i = 0; i < nreq; i++) { + req = ncchkp->getlist.reqs + reqids[i]; + flag[req->varid >> 5] |= 1u << (req->varid % 32); + } + + // Sync flag + CHK_ERR_ALLREDUCE (flag, flag_all, nflag, MPI_UNSIGNED, MPI_BOR, ncchkp->comm); + + // Build a skip list of touched vars + nvar = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + if (flag_all[i >> 5] & (1u << (i % 32))) { nvar++; } + } + vids = (int *)NCI_Malloc (sizeof (int) * nvar); + nvar = 0; + for (i = 0; i < ncchkp->vars.cnt; i++) { + if (flag_all[i >> 5] & (1u << (i % 32))) { vids[nvar++] = i; } + } + + // Perform I/O for comrpessed variables + // ncchkioi_load_nvar(ncchkp, nvar, vids); + + // Perform collective buffer + if (ncchkp->comm_unit == NC_CHK_COMM_CHUNK) { + err = ncchkioi_iget_cb_chunk (ncchkp, nreq, reqids, stats); + } else { + err = ncchkioi_iget_cb_proc (ncchkp, nreq, reqids, stats); + // ncchkioi_iget_cb_chunk(ncchkp, nreq, reqids, stats); + } + CHK_ERR + + NC_CHK_TIMER_START (NC_CHK_TIMER_GET_CONVERT) + for (i = 0; i < nreq; i++) { + req = ncchkp->getlist.reqs + reqids[i]; + if (req->buf != req->xbuf) { + void *cbuf = (void *)req->buf; + + err = ncchkioiconvert (req->xbuf, cbuf, ncchkp->vars.data[req->varid].etype, + req->buftype, req->bufcount); + CHK_ERR + + if (cbuf != req->buf) NCI_Free (cbuf); + } + } + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET_CONVERT) + +err_out:; + + // Free buffers + NCI_Free (vids); + NCI_Free (flag); + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_WAIT_GET) + + return err; +} + +int ncchkioi_wait (NC_chk *ncchkp, int nreqs, int *reqids, int *stats, int reqMode) { + int err = NC_NOERR; + int i; + int nput = 0, nget = 0; + int *putreqs = NULL, *getreqs = NULL; + int *putstats = NULL, *getstats = NULL; + + if (nreqs == NC_REQ_ALL || nreqs == NC_PUT_REQ_ALL) { + nput = ncchkp->putlist.nused; + putreqs = (int *)NCI_Malloc (sizeof (int) * nput); + CHK_PTR (putreqs) + memcpy (putreqs, ncchkp->putlist.ids, nput * sizeof (int)); + } + if (nreqs == NC_REQ_ALL || nreqs == NC_GET_REQ_ALL) { + nget = ncchkp->getlist.nused; + getreqs = (int *)NCI_Malloc (sizeof (int) * nget); + CHK_PTR (getreqs) + memcpy (getreqs, ncchkp->getlist.ids, nget * sizeof (int)); + } + + if (nreqs > 0) { + // Count number of get and put requests + for (i = 0; i < nreqs; i++) { + if (reqids[i] & 1) { nput++; } + } + + // Allocate buffer + nget = nreqs - nput; + putreqs = (int *)NCI_Malloc (sizeof (int) * nput); + CHK_PTR (putreqs) + getreqs = (int *)NCI_Malloc (sizeof (int) * nget); + CHK_PTR (getreqs) + + // Build put and get req list + nput = nget = 0; + for (i = 0; i < nreqs; i++) { + if (reqids[i] & 1) { + putreqs[nput++] = reqids[i] >> 1; + } else { + getreqs[nget++] = reqids[i] >> 1; + } + } + } + + if (ncchkp->delay_init) { + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_WAIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_INIT_META) + + err = ncchkioi_init_nvar (ncchkp, nput, putreqs, nget, getreqs); // nput + nget = real nreq + if (err != NC_NOERR) { return err; } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT) + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_INIT_META) + NC_CHK_TIMER_START (NC_CHK_TIMER_WAIT) + } else { + NC_CHK_TIMER_PAUSE (NC_CHK_TIMER_WAIT) + NC_CHK_TIMER_START (NC_CHK_TIMER_VAR_RESIZE) + + // Sync number of rec + err = + ncchkioi_resize_nvar (ncchkp, nput, putreqs, nget, getreqs); // nput + nget = real nreq + if (err != NC_NOERR) { return err; } + + NC_CHK_TIMER_STOP (NC_CHK_TIMER_VAR_RESIZE) + NC_CHK_TIMER_START (NC_CHK_TIMER_WAIT) + } + + if (stats != NULL) { + putstats = (int *)NCI_Malloc (sizeof (int) * nput); + CHK_PTR (putstats) + getstats = (int *)NCI_Malloc (sizeof (int) * nget); + CHK_PTR (getstats) + memset (putstats, 0, sizeof (int) * nput); + memset (getstats, 0, sizeof (int) * nget); + } else { + putstats = NULL; + getstats = NULL; + } + + if ((ncchkp->mode & NC_WRITE) && nreqs != NC_GET_REQ_ALL) { + NC_CHK_TIMER_START (NC_CHK_TIMER_PUT) + err = ncchkioi_wait_put_reqs (ncchkp, nput, putreqs, putstats); + CHK_ERR + NC_CHK_TIMER_STOP (NC_CHK_TIMER_PUT) + } + + if (nreqs != NC_PUT_REQ_ALL) { + NC_CHK_TIMER_START (NC_CHK_TIMER_GET) + err = ncchkioi_wait_get_reqs (ncchkp, nget, getreqs, getstats); + CHK_ERR + NC_CHK_TIMER_STOP (NC_CHK_TIMER_GET) + } + + // Assign stats + if (stats != NULL) { + nput = nget = 0; + for (i = 0; i < nreqs; i++) { + if (reqids[i] & 1) { + stats[i] = putstats[nput++]; + } else { + stats[i] = getstats[nget++]; + } + } + + NCI_Free (putstats); + NCI_Free (getstats); + } + + // Remove from req list + for (i = 0; i < nput; i++) { ncchkioi_req_list_remove (&(ncchkp->putlist), putreqs[i]); } + for (i = 0; i < nget; i++) { ncchkioi_req_list_remove (&(ncchkp->getlist), getreqs[i]); } + +err_out:; + NCI_Free (putreqs); + NCI_Free (getreqs); + + return err; +} From f8f4a62db3cd8f8efe73ab001e9f0b90bde4bb18 Mon Sep 17 00:00:00 2001 From: Kaiyuan Hou Date: Sun, 4 Dec 2022 14:40:33 -0600 Subject: [PATCH 03/29] add ncmpi_var_get/set_chunk and ncmpi_var_get/set_filter --- src/dispatchers/variable.c | 39 ++++++++++++++++++++++++++++++++++++++ src/include/pnetcdf.h.in | 14 ++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/dispatchers/variable.c b/src/dispatchers/variable.c index f72aaaf86..5318683db 100644 --- a/src/dispatchers/variable.c +++ b/src/dispatchers/variable.c @@ -235,6 +235,45 @@ ncmpi_def_var(int ncid, /* IN: file ID */ return NC_NOERR; } +#ifdef ENABLE_COMPRESSION +/*----< ncmpi_var_set_chunk() >----------------------------------------------------*/ +/* This is a collective subroutine. */ +int ncmpi_var_set_chunk (int ncid, /* IN: file ID */ + int varid, + int *chunk_dim) +{ + int err; + int ndim; + + err = ncmpi_inq_varndims(ncid,varid, &ndim); + if (err != NC_NOERR) return err; + + return ncmpi_put_att_int(ncid, varid, "_chunkdim", NC_INT, ndim, chunk_dim); +} +/*----< ncmpi_var_get_chunk() >----------------------------------------------------*/ +int ncmpi_var_get_chunk (int ncid, /* IN: file ID */ + int varid, + int *chunk_dim) +{ + return ncmpi_get_att_int(ncid, varid, "_chunkdim", chunk_dim); +} +/*----< ncmpi_var_set_filter() >----------------------------------------------------*/ +/* This is a collective subroutine. */ +int ncmpi_var_set_filter (int ncid, /* IN: file ID */ + int varid, + int filter) +{ + return ncmpi_put_att_int(ncid, varid, "_filter", NC_INT, 1, &filter); +} +/*----< ncmpi_var_get_filter() >----------------------------------------------------*/ +int ncmpi_var_get_filter (int ncid, /* IN: file ID */ + int varid, + int *filter) +{ + return ncmpi_get_att_int(ncid, varid, "_filter", filter); +} +#endif + /*----< ncmpi_def_var_fill() >-----------------------------------------------*/ /* this API is collective, and must be called in define mode */ int diff --git a/src/include/pnetcdf.h.in b/src/include/pnetcdf.h.in index 881f5a847..6281e1e46 100644 --- a/src/include/pnetcdf.h.in +++ b/src/include/pnetcdf.h.in @@ -791,6 +791,20 @@ extern int ncmpi_def_var(int ncid, const char *name, nc_type xtype, int ndims, const int *dimidsp, int *varidp); +#ifdef ENABLE_COMPRESSION +#define NC_FILTER_NONE 0 +#define NC_FILTER_DEFLATE 2 +#define NC_FILTER_SZ 3 +extern int +ncmpi_var_set_chunk (int ncid, int varid, int *chunk_dim); +extern int +ncmpi_var_get_chunk (int ncid, int varid, int *chunk_dim); +extern int +ncmpi_var_set_filter (int ncid, int varid, int filter); +extern int +ncmpi_var_get_filter (int ncid, int varid, int *filter); +#endif + extern int ncmpi_rename_dim(int ncid, int dimid, const char *name); From 63b5b614daaf6c3520aeded14a009441e86e975e Mon Sep 17 00:00:00 2001 From: Kaiyuan Hou Date: Sun, 4 Dec 2022 16:56:08 -0600 Subject: [PATCH 04/29] enable chunk driver when chunking hint is set --- src/dispatchers/file.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/include/dispatch.h | 2 ++ src/libs/Makefile.am | 3 +++ 3 files changed, 45 insertions(+) diff --git a/src/dispatchers/file.c b/src/dispatchers/file.c index 1b2b66bd8..1948e5a14 100644 --- a/src/dispatchers/file.c +++ b/src/dispatchers/file.c @@ -290,6 +290,9 @@ ncmpi_create(MPI_Comm comm, #ifdef ENABLE_BURST_BUFFER int enable_bb_driver=0; #endif +#ifdef ENABLE_CHUNKING + int enable_chk_driver=0; +#endif MPI_Comm_rank(comm, &rank); MPI_Comm_size(comm, &nprocs); @@ -382,6 +385,18 @@ ncmpi_create(MPI_Comm comm, enable_bb_driver = 1; } #endif +#ifdef ENABLE_CHUNKING + if (combined_info != MPI_INFO_NULL) { + char value[MPI_MAX_INFO_VAL]; + int flag; + + /* check if nc_chunking is enabled */ + MPI_Info_get(combined_info, "nc_chunking", MPI_MAX_INFO_VAL-1, + value, &flag); + if (flag && strcasecmp(value, "enable") == 0) + enable_chk_driver = 1; + } +#endif /* Use environment variable and cmode to tell the file format * which is later used to select the right driver. @@ -462,6 +477,11 @@ ncmpi_create(MPI_Comm comm, if (enable_bb_driver) driver = ncbbio_inq_driver(); else +#endif +#ifdef ENABLE_CHUNKING + if (enable_chk_driver) + driver = ncchkio_inq_driver(); + else #endif /* default is the driver built on top of MPI-IO */ driver = ncmpio_inq_driver(); @@ -558,6 +578,9 @@ ncmpi_open(MPI_Comm comm, #ifdef ENABLE_BURST_BUFFER int enable_bb_driver=0; #endif +#ifdef ENABLE_CHUNKING + int enable_chk_driver=0; +#endif MPI_Comm_rank(comm, &rank); MPI_Comm_size(comm, &nprocs); @@ -688,6 +711,18 @@ ncmpi_open(MPI_Comm comm, enable_bb_driver = 1; } #endif +#ifdef ENABLE_CHUNKING + if (combined_info != MPI_INFO_NULL) { + char value[MPI_MAX_INFO_VAL]; + int flag; + + /* check if nc_chunking is enabled */ + MPI_Info_get(combined_info, "nc_chunking", MPI_MAX_INFO_VAL-1, + value, &flag); + if (flag && strcasecmp(value, "enable") == 0) + enable_chk_driver = 1; + } +#endif #ifdef ENABLE_NETCDF4 if (format == NC_FORMAT_NETCDF4_CLASSIC || format == NC_FORMAT_NETCDF4) { @@ -716,6 +751,11 @@ ncmpi_open(MPI_Comm comm, if (enable_bb_driver) driver = ncbbio_inq_driver(); else +#endif +#ifdef ENABLE_CHUNKING + if (enable_chk_driver) + driver = ncchkio_inq_driver(); + else #endif { /* ncmpio driver */ diff --git a/src/include/dispatch.h b/src/include/dispatch.h index 357d35ad3..95cfcfcba 100644 --- a/src/include/dispatch.h +++ b/src/include/dispatch.h @@ -153,6 +153,8 @@ extern PNC_driver* ncfoo_inq_driver(void); extern PNC_driver* ncbbio_inq_driver(void); +extern PNC_driver* ncchkio_inq_driver(void); + extern int PNC_check_id(int ncid, PNC **pncp); #endif /* _PNC_DISPATCH_H */ diff --git a/src/libs/Makefile.am b/src/libs/Makefile.am index a932f20f5..be7808905 100644 --- a/src/libs/Makefile.am +++ b/src/libs/Makefile.am @@ -32,6 +32,9 @@ endif if ENABLE_BURST_BUFFER libpnetcdf_la_LIBADD += ../drivers/ncbbio/libncbbio.la endif +if ENABLE_CHUNKING + libpnetcdf_la_LIBADD += ../drivers/ncchunkio/libncchkio.la +endif if ENABLE_ADIOS libpnetcdf_la_LIBADD += ../drivers/ncadios/libncadios.la endif From 13d9d152b6e8fb48895f0dbaa2da759ea8d3a327 Mon Sep 17 00:00:00 2001 From: Kaiyuan Hou Date: Sun, 4 Dec 2022 23:25:07 -0600 Subject: [PATCH 05/29] rename default filter hint to nc_chunk_default_filter --- src/drivers/ncchunkio/ncchkioi_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/ncchunkio/ncchkioi_util.c b/src/drivers/ncchunkio/ncchkioi_util.c index 34ec21ff5..058047d37 100644 --- a/src/drivers/ncchunkio/ncchkioi_util.c +++ b/src/drivers/ncchunkio/ncchkioi_util.c @@ -135,7 +135,7 @@ int ncchkioi_extract_hint (NC_chk *ncchkp, MPI_Info info) { // Default filter ncchkp->default_filter = NC_CHK_FILTER_NONE; - MPI_Info_get (info, "nc_chk_driver", MPI_MAX_INFO_VAL - 1, value, &flag); + MPI_Info_get (info, "nc_chunk_default_filter", MPI_MAX_INFO_VAL - 1, value, &flag); if (flag) { if (strcmp (value, "none") == 0) { ncchkp->default_filter = NC_CHK_FILTER_NONE; From e2ec339c8c9b1bd43ed769a5b1189de3a49c772b Mon Sep 17 00:00:00 2001 From: Kaiyuan Hou Date: Mon, 5 Dec 2022 00:37:24 -0600 Subject: [PATCH 06/29] add documentation about chunked I/O driver --- doc/README.Chunk.md | 119 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 doc/README.Chunk.md diff --git a/doc/README.Chunk.md b/doc/README.Chunk.md new file mode 100644 index 000000000..fea6255cf --- /dev/null +++ b/doc/README.Chunk.md @@ -0,0 +1,119 @@ +# Support variable chunking and compression + +PnetCDF contains an experimental variable chunking and compression feature +for classic NetCDF files. + +For details about its design and implementation, please refer to: +Hou, Kaiyuan, et al. "Supporting Data Compression in PnetCDF." +2021 IEEE International Conference on Big Data (Big Data). IEEE, 2021. + +## Enable variable chunking support + +* To build PnetCDF with variable chunking support + + Add `--enable-chunking` option at the configure command line. For example, + ``` + ./configure --prefix=/PnetCDF/install/path --enable-chunking + ``` +* To build deflate filter support for chunked variable + + Add `--enable-zlib` option at the configure command line. Option + `--with-zlib` can also be used to specify the installation path of + zlib if it is not in the standard locations. For example, + ``` + ./configure --prefix=/PnetCDF/install/path --enable-chunking --enable-zlib \ + --with-zlib=/zlib/install/path + ``` +* To build sz filter support for chunked variable + + Add `--enable-sz` option at the configure command line. Option + `--with-sz` can also be used to specify the installation path of + sz if it is not in the standard locations. For example, + ``` + ./configure --prefix=/PnetCDF/install/path --enable-chunking --enable-sz \ + --with-sz=/sz/install/path + ``` + +## Enable variable chunking + +To enable chunked storage layout for variables, set the file info "nc_chunking" +to "enable". The chunking feature requires 64-bit NetCDF format (CDF5). +For example, +``` + MPI_Info_create(&info); + ncmpi_create(MPI_COMM_WORLD, fname, NC_64BIT_DATA, info, &ncid); +``` +Alternatively, the file info can be set through the environment variable +"PNETCDF_HINTS". +``` +export PNETCDF_HINTS="nc_chunking=enable" +``` +When chunking is enabled, all non-scalar variables will be stored in a chunked +storage layout. Scalar variables are not chunked. + +Users can also set the default filter for chunked variables. For example, +``` + MPI_Info_set(info, "nc_chunk_default_filter", "zlib"); +``` +or +``` +export PNETCDF_HINTS="nc_chunking=enable;nc_chunk_default_filter=zlib" +``` +The available filter options are none (default), zlib (deflate), sz. + +## Define chunk dimension of variables + +Applications can use the following APIs to set and get the chunk dimension of +a variable. +``` + int ncmpi_var_set_chunk (int ncid, int varid, int *chunk_dim); + int ncmpi_var_get_chunk (int ncid, int varid, int *chunk_dim); +``` +For example: +``` + int dim[2] = {100, 100}; + int chunk_dim[2] = {10, 10}; + ncmpi_def_var (ncid, name, type, 2, dim, &varid) + ncmpi_var_set_chunk (ncid, varid, chunk_dim); +``` +For record variables, the chunk dimension along the record dimension is always +1. +The default chunk dimension is the dimension of the variable except for the +record dimension. By default, PnetCDF will create one chunk per record or +variable. + +## Define filter for chunked variables + +Applications can use the following APIs to set and get the chunk dimension of +a variable. +``` +#define NC_FILTER_NONE 0 +#define NC_FILTER_DEFLATE 2 +#define NC_FILTER_SZ 3 +int ncmpi_var_set_filter (int ncid, int varid, int filter); +int ncmpi_var_get_filter (int ncid, int varid, int *filter); +``` +For example: +``` + ncmpi_var_set_filter (ncid, varid, NC_FILTER_DEFLATE); +``` +Valid filter values are NC_FILTER_NONE (none), NC_FILTER_DEFLATE (zlib), and +NC_FILTER_SZ (sz). + + +## Known problems + +There are some limitations of the experimental variable chunking feature. + +* Only one filter can be applied to a chunked variable. Unlike HDF5 which allows + the stacking of multiple filters on chunked datasets, the current + implementation in PnetCDF only allows a single filter to be applied to a + variable. +* No per-variable option for variable chunking. If chunking is enabled, all + non-scalar variables will be chunked even if the chunk dimension is not + defined. +* Independent variable I/O is not supported. Variable read/write (get/put) + must be collective in order to maintain data consistency of filtered chunks. + Non-blocking APIs can be used to mitigate the impact of this limitation. + +Copyright (C) 2022, Northwestern University and Argonne National Laboratory + +See the COPYRIGHT notice in the top-level directory. + From ad1379859a39f5404d44074b0e2456f3e166a178 Mon Sep 17 00:00:00 2001 From: Kaiyuan Hou Date: Mon, 5 Dec 2022 00:48:41 -0600 Subject: [PATCH 07/29] bugfix:chunk driver build condition is ENABLE_CHUNKING --- src/include/pnetcdf.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/pnetcdf.h.in b/src/include/pnetcdf.h.in index 6281e1e46..32cda7da2 100644 --- a/src/include/pnetcdf.h.in +++ b/src/include/pnetcdf.h.in @@ -791,7 +791,7 @@ extern int ncmpi_def_var(int ncid, const char *name, nc_type xtype, int ndims, const int *dimidsp, int *varidp); -#ifdef ENABLE_COMPRESSION +#ifdef ENABLE_CHUNKING #define NC_FILTER_NONE 0 #define NC_FILTER_DEFLATE 2 #define NC_FILTER_SZ 3 From 490526c7b04cb20afc745ce68755d7b6b404af9f Mon Sep 17 00:00:00 2001 From: Kaiyuan Hou Date: Mon, 5 Dec 2022 01:31:29 -0600 Subject: [PATCH 08/29] always build chunk related APIs --- src/dispatchers/variable.c | 31 +++++++++++++++++++++++++++++++ src/include/pnetcdf.h.in | 2 -- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/dispatchers/variable.c b/src/dispatchers/variable.c index 5318683db..4257d100a 100644 --- a/src/dispatchers/variable.c +++ b/src/dispatchers/variable.c @@ -272,6 +272,37 @@ int ncmpi_var_get_filter (int ncid, /* IN: file ID */ { return ncmpi_get_att_int(ncid, varid, "_filter", filter); } +#else +/*----< ncmpi_var_set_chunk() >----------------------------------------------------*/ +/* This is a collective subroutine. */ +int ncmpi_var_set_chunk (int ncid, /* IN: file ID */ + int varid, + int *chunk_dim) +{ + return NC_ENOTBUILT; +} +/*----< ncmpi_var_get_chunk() >----------------------------------------------------*/ +int ncmpi_var_get_chunk (int ncid, /* IN: file ID */ + int varid, + int *chunk_dim) +{ + return NC_ENOTBUILT; +} +/*----< ncmpi_var_set_filter() >----------------------------------------------------*/ +/* This is a collective subroutine. */ +int ncmpi_var_set_filter (int ncid, /* IN: file ID */ + int varid, + int filter) +{ + return NC_ENOTBUILT; +} +/*----< ncmpi_var_get_filter() >----------------------------------------------------*/ +int ncmpi_var_get_filter (int ncid, /* IN: file ID */ + int varid, + int *filter) +{ + return NC_ENOTBUILT; +} #endif /*----< ncmpi_def_var_fill() >-----------------------------------------------*/ diff --git a/src/include/pnetcdf.h.in b/src/include/pnetcdf.h.in index 32cda7da2..1e94d1d3d 100644 --- a/src/include/pnetcdf.h.in +++ b/src/include/pnetcdf.h.in @@ -791,7 +791,6 @@ extern int ncmpi_def_var(int ncid, const char *name, nc_type xtype, int ndims, const int *dimidsp, int *varidp); -#ifdef ENABLE_CHUNKING #define NC_FILTER_NONE 0 #define NC_FILTER_DEFLATE 2 #define NC_FILTER_SZ 3 @@ -803,7 +802,6 @@ extern int ncmpi_var_set_filter (int ncid, int varid, int filter); extern int ncmpi_var_get_filter (int ncid, int varid, int *filter); -#endif extern int ncmpi_rename_dim(int ncid, int dimid, const char *name); From 21831e5d5e2ab7b35b83e56eaeb556d8e0cdee13 Mon Sep 17 00:00:00 2001 From: Kaiyuan Hou Date: Mon, 5 Dec 2022 01:51:00 -0600 Subject: [PATCH 09/29] bug fix: add ncchunkio to DIST_DIR --- src/drivers/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/Makefile.am b/src/drivers/Makefile.am index 1d8a44314..3291984f4 100644 --- a/src/drivers/Makefile.am +++ b/src/drivers/Makefile.am @@ -28,7 +28,7 @@ if ENABLE_ADIOS SUBDIRS += ncadios endif -DIST_SUBDIRS = include common ncmpio ncfoo ncbbio nc4io ncadios +DIST_SUBDIRS = include common ncmpio ncfoo ncbbio ncchunkio nc4io ncadios # For VPATH build (parallel build), try delete all sub-directories distclean-local: From eb6d336b7c8c2db1ad234cecc3794ac6b5f67051 Mon Sep 17 00:00:00 2001 From: Kaiyuan Hou Date: Mon, 5 Dec 2022 02:30:10 -0600 Subject: [PATCH 10/29] bugfix: add new m4 scripts to extra dist --- Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile.am b/Makefile.am index 806260eee..37202e67f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,6 +21,8 @@ EXTRA_DIST = COPYRIGHT \ README \ RELEASE_NOTES \ m4/foreach.m4 \ + m4/foreach_idx.m4 \ + m4/list_len.m4 \ m4/utils.m4 # Below is a trick to build all test executables, without running them From 49c761e64a8a278605fd5555f1359f1ddac4efaa Mon Sep 17 00:00:00 2001 From: Kaiyuan Hou Date: Mon, 5 Dec 2022 03:03:16 -0600 Subject: [PATCH 11/29] bugfix: add ncchkioi_profile_timers.m4 to extra_dist --- src/drivers/ncchunkio/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/ncchunkio/Makefile.am b/src/drivers/ncchunkio/Makefile.am index 882e49ba9..f7abacb0a 100644 --- a/src/drivers/ncchunkio/Makefile.am +++ b/src/drivers/ncchunkio/Makefile.am @@ -91,7 +91,7 @@ BUILT_SOURCES = $(M4_SRCS:.m4=.c) $(M4H_SRCS:.m4h=.h) CLEANFILES = $(M4_SRCS:.m4=.c) $(M4H_SRCS:.m4h=.h) core core.* *.gcda *.gcno *.gcov gmon.out -EXTRA_DIST = $(M4_HFILES) $(M4_SRCS) $(M4H_SRCS) +EXTRA_DIST = $(M4_HFILES) $(M4_SRCS) $(M4H_SRCS) ncchkioi_profile_timers.m4 tests-local: all From d3b160d9a65a234df21776dc826eb1f0b922ad9f Mon Sep 17 00:00:00 2001 From: Kaiyuan Hou Date: Mon, 5 Dec 2022 04:09:47 -0600 Subject: [PATCH 12/29] bugfix: add nchunk io to m4 include --- src/drivers/ncchunkio/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/drivers/ncchunkio/Makefile.am b/src/drivers/ncchunkio/Makefile.am index f7abacb0a..c304a128b 100644 --- a/src/drivers/ncchunkio/Makefile.am +++ b/src/drivers/ncchunkio/Makefile.am @@ -24,6 +24,7 @@ endif noinst_LTLIBRARIES = libncchkio.la M4FLAGS += -I${top_srcdir}/m4 +M4FLAGS += -I${top_srcdir}/src/drivers/ncchunkio if ENABLE_ERANGE_FILL M4FLAGS += -DERANGE_FILL endif From 2eec8aa9f28e456e45eae959ecb50e0380164b5e Mon Sep 17 00:00:00 2001 From: wkliao Date: Thu, 8 May 2025 14:47:21 -0500 Subject: [PATCH 13/29] define ENABLE_COMPRESSION if --enable-zlib or --enable-sz is set --- configure.ac | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure.ac b/configure.ac index f722ebfa8..b58af092d 100644 --- a/configure.ac +++ b/configure.ac @@ -2307,6 +2307,9 @@ fi AC_SUBST(ENABLE_SZ) AM_CONDITIONAL(ENABLE_SZ, [test x$enable_sz = xyes]) +if test "x${have_zlib}" = xyes || test "x$enable_sz" = "xyes" ; then + AC_DEFINE(ENABLE_COMPRESSION, [1], [Defined if compression is enabled]) +fi if test "x$enable_sz" = "xyes" ; then SZ_INSTALL="" From 98443b79df1cbaf47d0a2292560bb40f7ae32e3a Mon Sep 17 00:00:00 2001 From: wkliao Date: Thu, 8 May 2025 14:55:29 -0500 Subject: [PATCH 14/29] add example of using chunking and compression --- examples/C/Makefile.am | 3 +- examples/C/chunk_compress.c | 232 ++++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 examples/C/chunk_compress.c diff --git a/examples/C/Makefile.am b/examples/C/Makefile.am index 42c1d213c..e3bd0eb3c 100644 --- a/examples/C/Makefile.am +++ b/examples/C/Makefile.am @@ -37,7 +37,8 @@ check_PROGRAMS = collective_write \ ghost_cell \ req_all \ vard_mvars \ - time_var + time_var \ + chunk_compress if INSTALL_EXAMPLES example_execbin_PROGRAMS = $(check_PROGRAMS) diff --git a/examples/C/chunk_compress.c b/examples/C/chunk_compress.c new file mode 100644 index 000000000..673ac3ace --- /dev/null +++ b/examples/C/chunk_compress.c @@ -0,0 +1,232 @@ +/********************************************************************* + * + * Copyright (C) 2013, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + * + *********************************************************************/ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * This example shows how to use the chunking and compression features of + * PnetCDF to write a 3D record variable of integer data type in parallel. It + * first defines a netCDF variable of size time * global_ny * global_nx where + * global_ny == NY and + * global_nx == (NX * number of MPI processes). + * The data partitioning pattern is a column-wise partitioning across all + * processes. Each process writes a subarray of size ny * nx per record. + * + * To compile: + * mpicc -O2 chunk_compress.c -o chunk_compress -lpnetcdf + * + * Example commands for MPI run and outputs from running ncmpidump on the + * output netCDF file produced by this example program: + * + * % mpiexec -n 4 ./chunk_compress /pvfs2/wkliao/testfile.nc + * + * % ncmpidump /pvfs2/wkliao/testfile.nc + * netcdf testfile { + * // file format: CDF-5 (big variables) + * dimensions: + * time = UNLIMITED ; // (0 currently) <-- Not used anymore + * Y = 10 ; + * X = 16 ; + * _datablock_dim_0 = 65593 ; + * _datablock_dim_1 = 57 ; + * variables: + * int var ; + * var:_ndim = 3 ; <-- true ndims + * var:_dimids = 0, 1, 2 ; <-- dim IDs + * var:_datatype = 4 ; <-- true data type + * var:_varkind = 1 ; <-- compressed or not + * var:_chunkdim = 1, 10, 4 ; <-- chunk sizes + * var:_filter = 2 ; <-- filter ID + * var:_metaoffset = 4LL ; <-- offset to metadata block + * byte _datablock_0(_datablock_dim_0) ; + * _datablock_0:_varkind = 2 ; + * byte _datablock_1(_datablock_dim_1) ; + * _datablock_1:_varkind = 2 ; + * + * // global attributes: + * :_comressed = 1 ; <-- file contains compressed variables or not + * :_nwrite = 2 ; + * :_recsize = 2LL ; <-- true number of records + * } + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include /* strcpy(), strncpy() */ +#include /* getopt() */ +#include /* time() localtime(), asctime() */ +#include +#include + +#define NY 10 +#define NX 4 + +static int verbose; + +#define ERR {if(err!=NC_NOERR){printf("Error at %s:%d : %s\n", __FILE__,__LINE__, ncmpi_strerror(err));nerrs++;}} + +static void +usage(char *argv0) +{ + char *help = + "Usage: %s [-h] | [-q] [-k format] [file_name]\n" + " [-h] Print help\n" + " [-q] Quiet mode (reports when fail)\n" + " [-k format] file format: 1 for CDF-1, 2 for CDF-2, 5 for CDF-5\n" + " [filename] output netCDF file name\n"; + fprintf(stderr, help, argv0); +} + +/*----< pnetcdf_check_mem_usage() >------------------------------------------*/ +/* check PnetCDF library internal memory usage */ +static int +pnetcdf_check_mem_usage(MPI_Comm comm) +{ + int err, nerrs=0, rank; + MPI_Offset malloc_size, sum_size; + + MPI_Comm_rank(comm, &rank); + + /* print info about PnetCDF internal malloc usage */ + err = ncmpi_inq_malloc_max_size(&malloc_size); + if (err == NC_NOERR) { + MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD); + if (rank == 0 && verbose) + printf("maximum heap memory allocated by PnetCDF internally is %lld bytes\n", + sum_size); + + /* check if there is any PnetCDF internal malloc residue */ + err = ncmpi_inq_malloc_size(&malloc_size); + MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD); + if (rank == 0 && sum_size > 0) + printf("heap memory allocated by PnetCDF internally has %lld bytes yet to be freed\n", + sum_size); + } + else if (err != NC_ENOTENABLED) { + printf("Error at %s:%d: %s\n", __FILE__,__LINE__,ncmpi_strerror(err)); + nerrs++; + } + return nerrs; +} + +/*----< pnetcdf_io() >-------------------------------------------------------*/ +static int +pnetcdf_io(MPI_Comm comm, char *filename, int cmode) +{ + int i, j, rank, nprocs, err, nerrs=0; + int ncid, varid, dimid[3], buf[NY][NX]; + MPI_Offset global_ny, global_nx; + MPI_Offset start[3], count[3]; + MPI_Info info; + + MPI_Comm_rank(comm, &rank); + MPI_Comm_size(comm, &nprocs); + + MPI_Info_create(&info); + MPI_Info_set(info, "nc_chunking", "enable"); + MPI_Info_set(info, "nc_chunk_default_filter", "zlib"); + + /* create a new file for writing ----------------------------------------*/ + cmode |= NC_CLOBBER; + err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR + MPI_Info_free(&info); + + /* the global array is NY * (NX * nprocs) */ + global_ny = NY; + global_nx = NX * nprocs; + + for (i=0; i 0); +} + From fe3537dedd8a5348705334ab0e504f5e082db679 Mon Sep 17 00:00:00 2001 From: wkliao Date: Thu, 8 May 2025 16:37:14 -0500 Subject: [PATCH 15/29] run chunk_compress.c only when compression is enabled --- configure.ac | 5 ++++- examples/C/Makefile.am | 7 +++++-- examples/C/chunk_compress.c | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index b58af092d..dbce0a30a 100644 --- a/configure.ac +++ b/configure.ac @@ -2307,9 +2307,12 @@ fi AC_SUBST(ENABLE_SZ) AM_CONDITIONAL(ENABLE_SZ, [test x$enable_sz = xyes]) +has_compression=0 if test "x${have_zlib}" = xyes || test "x$enable_sz" = "xyes" ; then - AC_DEFINE(ENABLE_COMPRESSION, [1], [Defined if compression is enabled]) + has_compression=1 fi +AC_DEFINE(ENABLE_COMPRESSION, [$has_compression], [Defined if compression is enabled]) +AM_CONDITIONAL(ENABLE_COMPRESSION, [test x$has_compression = x1]) if test "x$enable_sz" = "xyes" ; then SZ_INSTALL="" diff --git a/examples/C/Makefile.am b/examples/C/Makefile.am index e3bd0eb3c..157638083 100644 --- a/examples/C/Makefile.am +++ b/examples/C/Makefile.am @@ -37,8 +37,11 @@ check_PROGRAMS = collective_write \ ghost_cell \ req_all \ vard_mvars \ - time_var \ - chunk_compress + time_var + +if ENABLE_COMPRESSION + check_PROGRAMS += chunk_compress +endif if INSTALL_EXAMPLES example_execbin_PROGRAMS = $(check_PROGRAMS) diff --git a/examples/C/chunk_compress.c b/examples/C/chunk_compress.c index 673ac3ace..1190cab7c 100644 --- a/examples/C/chunk_compress.c +++ b/examples/C/chunk_compress.c @@ -177,7 +177,7 @@ pnetcdf_io(MPI_Comm comm, char *filename, int cmode) /* check the current record dimension size */ MPI_Offset dim_len; err = ncmpi_inq_dimlen(ncid, 0, &dim_len); ERR - if (rank == 0) + if (verbose && rank == 0) printf("Time dimension length = %lld\n", dim_len); err = ncmpi_close(ncid); ERR From 84c71378937663be14d17b3dbf4cea06260b378a Mon Sep 17 00:00:00 2001 From: wkliao Date: Sat, 24 May 2025 13:07:51 -0500 Subject: [PATCH 16/29] Remove unused variable, initialize err to NC_NOERR --- m4/libtool.m4 | 842 +++++----- scripts/ltmain.sh | 1572 +++++++++++------- src/drivers/ncchunkio/ncchk_filter_sz.c | 8 +- src/drivers/ncchunkio/ncchk_filter_zlib.c | 12 +- src/drivers/ncchunkio/ncchkio_attr.c | 16 +- src/drivers/ncchunkio/ncchkio_dim.c | 8 +- src/drivers/ncchunkio/ncchkio_file.c | 39 +- src/drivers/ncchunkio/ncchkio_internal.c | 6 +- src/drivers/ncchunkio/ncchkio_internal.h | 4 +- src/drivers/ncchunkio/ncchkio_var.c | 41 +- src/drivers/ncchunkio/ncchkioi_cache.c | 2 +- src/drivers/ncchunkio/ncchkioi_chunk.c | 4 +- src/drivers/ncchunkio/ncchkioi_chunk_owner.c | 42 +- src/drivers/ncchunkio/ncchkioi_chunk_size.c | 4 +- src/drivers/ncchunkio/ncchkioi_get_var.c | 5 +- src/drivers/ncchunkio/ncchkioi_get_varn.c | 9 +- src/drivers/ncchunkio/ncchkioi_iget.c | 12 +- src/drivers/ncchunkio/ncchkioi_iget_cb.c | 7 +- src/drivers/ncchunkio/ncchkioi_iput.c | 14 +- src/drivers/ncchunkio/ncchkioi_iput_cb.c | 6 +- src/drivers/ncchunkio/ncchkioi_lagacy.c | 6 +- src/drivers/ncchunkio/ncchkioi_lists.c | 2 +- src/drivers/ncchunkio/ncchkioi_nonblocking.c | 2 +- src/drivers/ncchunkio/ncchkioi_profile.m4 | 2 +- src/drivers/ncchunkio/ncchkioi_put_var.c | 11 +- src/drivers/ncchunkio/ncchkioi_put_varn.c | 18 +- src/drivers/ncchunkio/ncchkioi_util.c | 11 +- src/drivers/ncchunkio/ncchkioi_var_init.c | 10 +- src/drivers/ncchunkio/ncchkioi_var_rd.c | 18 +- src/drivers/ncchunkio/ncchkioi_var_resize.c | 18 +- src/drivers/ncchunkio/ncchkioi_var_wr.c | 10 +- src/drivers/ncchunkio/ncchkioi_wait.c | 8 +- test/nc_test/tst_atts3.c | 5 +- 33 files changed, 1545 insertions(+), 1229 deletions(-) diff --git a/m4/libtool.m4 b/m4/libtool.m4 index f3a3d65b0..8d323b3ee 100644 --- a/m4/libtool.m4 +++ b/m4/libtool.m4 @@ -1,6 +1,7 @@ # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # -# Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc. +# Copyright (C) 1996-2001, 2003-2019, 2021-2024 Free Software +# Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives @@ -8,13 +9,13 @@ # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl -# Copyright (C) 2014 Free Software Foundation, Inc. +# Copyright (C) 2024 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of of the License, or +# the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, if you @@ -31,7 +32,7 @@ m4_define([_LT_COPYING], [dnl # along with this program. If not, see . ]) -# serial 58 LT_INIT +# serial 63 LT_INIT # LT_PREREQ(VERSION) @@ -59,7 +60,7 @@ esac # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], -[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK +[AC_PREREQ([2.64])dnl We use AC_PATH_PROGS_FEATURE_CHECK AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl @@ -114,60 +115,10 @@ func_cc_basename () compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; - mpicc | mpicxx | mpif77 | mpif90 | mpifort | *[[\\/]]mpicc | *[[\\/]]mpicxx | *[[\\/]]mpif77 | *[[\\/]]mpif90 | *[[\\/]]mpifort ) - # MPICH compilers - # eval "$cc_temp -show" < /dev/null >& conftest.ver - # func_cc_basename_result=`head -n1 conftest.ver |cut -d' ' -f1` - # ${RM} -f conftest.ver - func_cc_basename_result=`$cc_temp -show | cut -d' ' -f1 | xargs basename` - # echo "cc_temp=$cc_temp func_cc_basename_result=$func_cc_basename_result" - return - ;; - mpifccpx | mpiFCCpx | mpifrtpx | *[[\\/]]mpifccpx | *[[\\/]]mpiFCCpx | *[[\\/]]mpifrtpx ) - # MPI compilers based on Fujitsu compilers: fccpx, FCCpx, frtpx - func_cc_basename_result=`$cc_temp -showme | cut -d' ' -f1 | xargs basename` - # echo "cc_temp=$cc_temp func_cc_basename_result=$func_cc_basename_result" - return - ;; - cc | CC | ftn | *[[\\/]]cc | *[[\\/]]CC | *[[\\/]]ftn ) - # For Cray PrgEnv-intel, cc is a wrapper of icc - # For Cray PrgEnv-gnu, cc is a wrapper of gcc - # func_cc_basename_result=`$cc_temp --version |& head -n 1 | cut -d' ' -f1 | xargs basename` - eval "$cc_temp --version" < /dev/null >& conftest.ver - func_cc_basename_result=`head -n1 conftest.ver |cut -d' ' -f1` - ${RM} -f conftest.ver - if test "x${func_cc_basename_result}" = xicc || - test "x${func_cc_basename_result}" = xicpc || - test "x${func_cc_basename_result}" = xifort || - test "x${func_cc_basename_result}" = xgcc || - test "x${func_cc_basename_result}" = xg++ || - test "x${func_cc_basename_result}" = xgfortran || - test "x${func_cc_basename_result}" = xGNU ; then - # echo "cc_temp=$cc_temp func_cc_basename_result=$func_cc_basename_result" - return - fi - # For Cray PrgEnv-cray, cc is a wrapper of Cray CC - # Cray cc -V sends the output to stderr. - # func_cc_basename_result=`$cc_temp -V |& head -n 1 | cut -d' ' -f1 | xargs basename` - eval "$cc_temp -V" < /dev/null >& conftest.ver - func_cc_basename_result=`head -n1 conftest.ver |cut -d' ' -f1` - ${RM} -f conftest.ver - if test "x${func_cc_basename_result}" = xCray ; then - # echo "cc_temp=$cc_temp func_cc_basename_result=$func_cc_basename_result" - return - fi - return - ;; - mpixlc | mpixlcxx | mpixlf77 | mpixlf90 | *[[\\/]]mpixlc | *[[\\/]]mpixlcxx | *[[\\/]]mpixlf77 | *[[\\/]]mpixlf90 ) - func_cc_basename_result=`$cc_temp -show | cut -d' ' -f1 | xargs basename` - # echo "cc_temp=$cc_temp func_cc_basename_result=$func_cc_basename_result" - return - ;; *) break;; esac done func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` - # echo "cc_temp=$cc_temp func_cc_basename_result=$func_cc_basename_result" } ])# _LT_PREPARE_CC_BASENAME @@ -231,6 +182,7 @@ m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_DECL_FILECMD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl @@ -269,8 +221,8 @@ esac ofile=libtool can_build_shared=yes -# All known linkers require a '.a' archive for static linking (except MSVC, -# which needs '.lib'). +# All known linkers require a '.a' archive for static linking (except MSVC and +# ICC, which need '.lib'). libext=a with_gnu_ld=$lt_cv_prog_gnu_ld @@ -664,7 +616,7 @@ m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before -# AC_OUTPUT is called), incase it is used in configure for compilation +# AC_OUTPUT is called), in case it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} @@ -699,9 +651,9 @@ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. -Copyright (C) 2011 Free Software Foundation, Inc. +Copyright (C) 2024 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation -gives unlimited permision to copy, distribute and modify it." +gives unlimited permission to copy, distribute and modify it." while test 0 != $[#] do @@ -772,13 +724,12 @@ _LT_CONFIG_SAVE_COMMANDS([ fi cfgfile=${ofile}T - trap "$RM -f \"$cfgfile\"; exit 1" 1 2 15 - $RM -f "$cfgfile" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # Generated automatically by $as_me ($PACKAGE) $VERSION -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # Provide generalized library-building support services. @@ -828,7 +779,7 @@ _LT_EOF # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? - sed '$q' "$ltmain" >> "$cfgfile" \ + $SED '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || @@ -1006,7 +957,7 @@ ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` -$RM -f conftest* +$RM conftest* ])# _LT_COMPILER_BOILERPLATE @@ -1023,6 +974,7 @@ _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE + # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ @@ -1073,6 +1025,21 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ rm -f conftest.* fi]) + # Feature test to disable chained fixups since it is not + # compatible with '-undefined dynamic_lookup' + AC_CACHE_CHECK([for -no_fixup_chains linker flag], + [lt_cv_support_no_fixup_chains], + [ save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-no_fixup_chains" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([],[])], + lt_cv_support_no_fixup_chains=yes, + lt_cv_support_no_fixup_chains=no + ) + LDFLAGS=$save_LDFLAGS + ] + ) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no @@ -1092,12 +1059,12 @@ int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD - echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD - $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$AR $AR_FLAGS libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR $AR_FLAGS libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF -int main() { return 0;} +int main(void) { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err @@ -1117,23 +1084,37 @@ _LT_EOF _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - darwin*) # darwin 5.x on - # if running on 10.5 or later, the deployment target defaults - # to the OS version, if on x86, and 10.4, the deployment - # target defaults to 10.4. Don't you love it? - case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in - 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) - _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; - 10.[[012]][[,.]]*) - _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; - 10.*) - _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + darwin*) + case $MACOSX_DEPLOYMENT_TARGET,$host in + 10.[[012]],*|,*powerpc*-darwin[[5-8]]*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + *) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' + if test yes = "$lt_cv_support_no_fixup_chains"; then + AS_VAR_APPEND([_lt_dar_allow_undefined], [' $wl-no_fixup_chains']) + fi + ;; esac ;; esac if test yes = "$lt_cv_apple_cc_single_mod"; then _lt_dar_single_mod='$single_module' fi + _lt_dar_needs_single_mod=no + case $host_os in + rhapsody* | darwin1.*) + _lt_dar_needs_single_mod=yes ;; + darwin*) + # When targeting Mac OS X 10.4 (darwin 8) or later, + # -single_module is the default and -multi_module is unsupported. + # The toolchain on macOS 10.14 (darwin 18) and later cannot + # target any OS version that needs -single_module. + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*-darwin[[567]].*|10.[[0-3]],*-darwin[[5-9]].*|10.[[0-3]],*-darwin1[[0-7]].*) + _lt_dar_needs_single_mod=yes ;; + esac + ;; + esac if test yes = "$lt_cv_ld_exported_symbols_list"; then _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' else @@ -1169,22 +1150,19 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES], _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined case $cc_basename in - ifort*|nagfor*) - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _lt_dar_can_shared=yes - ;; + ifort*|nagfor*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test yes = "$_lt_dar_can_shared"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" - _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" - _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + _LT_TAGVAR(archive_expsym_cmds, $1)="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + _LT_TAGVAR(module_expsym_cmds, $1)="$SED -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" m4_if([$1], [CXX], -[ if test yes != "$lt_cv_apple_cc_single_mod"; then - _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs $nostdlib_flag -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" - _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs $nostdlib_flag -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" +[ if test yes = "$_lt_dar_needs_single_mod" -a yes != "$lt_cv_apple_cc_single_mod"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" + _LT_TAGVAR(archive_expsym_cmds, $1)="$SED 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" fi ],[]) else @@ -1298,7 +1276,8 @@ _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], -[AC_MSG_CHECKING([for sysroot]) +[m4_require([_LT_DECL_SED])dnl +AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], [Search for dependent libraries within DIR (or the compiler's sysroot @@ -1311,11 +1290,13 @@ lt_sysroot= case $with_sysroot in #( yes) if test yes = "$GCC"; then - lt_sysroot=`$CC --print-sysroot 2>/dev/null` + # Trim trailing / since we'll always append absolute paths and we want + # to avoid //, if only for less confusing output for the user. + lt_sysroot=`$CC --print-sysroot 2>/dev/null | $SED 's:/\+$::'` fi ;; #( /*) - lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + lt_sysroot=`echo "$with_sysroot" | $SED -e "$sed_quote_subst"` ;; #( no|'') ;; #( @@ -1345,7 +1326,7 @@ ia64-*-hpux*) # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then - case `/usr/bin/file conftest.$ac_objext` in + case `$FILECMD conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE=32 ;; @@ -1362,7 +1343,7 @@ ia64-*-hpux*) echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test yes = "$lt_cv_prog_gnu_ld"; then - case `/usr/bin/file conftest.$ac_objext` in + case `$FILECMD conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; @@ -1374,7 +1355,7 @@ ia64-*-hpux*) ;; esac else - case `/usr/bin/file conftest.$ac_objext` in + case `$FILECMD conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; @@ -1396,7 +1377,7 @@ mips64*-*linux*) echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then emul=elf - case `/usr/bin/file conftest.$ac_objext` in + case `$FILECMD conftest.$ac_objext` in *32-bit*) emul="${emul}32" ;; @@ -1404,7 +1385,7 @@ mips64*-*linux*) emul="${emul}64" ;; esac - case `/usr/bin/file conftest.$ac_objext` in + case `$FILECMD conftest.$ac_objext` in *MSB*) emul="${emul}btsmip" ;; @@ -1412,7 +1393,7 @@ mips64*-*linux*) emul="${emul}ltsmip" ;; esac - case `/usr/bin/file conftest.$ac_objext` in + case `$FILECMD conftest.$ac_objext` in *N32*) emul="${emul}n32" ;; @@ -1423,7 +1404,7 @@ mips64*-*linux*) ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ -s390*-*linux*|s390*-*tpf*|sparc*-*linux*) +s390*-*linux*|s390*-*tpf*|sparc*-*linux*|x86_64-gnu*) # Find out what ABI is being produced by ac_compile, and set linker # options accordingly. Note that the listed cases only cover the # situations where additional linker options are needed (such as when @@ -1432,14 +1413,14 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # not appear in the list. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then - case `/usr/bin/file conftest.o` in + case `$FILECMD conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; - x86_64-*linux*) - case `/usr/bin/file conftest.o` in + x86_64-*linux*|x86_64-gnu*) + case `$FILECMD conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; @@ -1467,7 +1448,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; - x86_64-*linux*) + x86_64-*linux*|x86_64-gnu*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*linux*) @@ -1507,7 +1488,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # options accordingly. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then - case `/usr/bin/file conftest.o` in + case `$FILECMD conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) @@ -1546,9 +1527,22 @@ need_locks=$enable_libtool_lock m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} -: ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) -_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +# Use ARFLAGS variable as AR's operation code to sync the variable naming with +# Automake. If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have +# higher priority because that's what people were doing historically (setting +# ARFLAGS for automake and AR_FLAGS for libtool). FIXME: Make the AR_FLAGS +# variable obsoleted/removed. + +test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr} +lt_ar_flags=$AR_FLAGS +_LT_DECL([], [lt_ar_flags], [0], [Flags to create an archive (by configure)]) + +# Make AR_FLAGS overridable by 'make ARFLAGS='. Don't try to run-time override +# by AR_FLAGS because that was never working and AR_FLAGS is about to die. +_LT_DECL([], [AR_FLAGS], [\@S|@{ARFLAGS-"\@S|@lt_ar_flags"}], + [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no @@ -1587,7 +1581,7 @@ AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) -AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_REQUIRE([AC_PROG_RANLIB]) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) @@ -1598,15 +1592,8 @@ old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then - case $host_os in - bitrig* | openbsd*) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" - ;; - *) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" - ;; - esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in @@ -1738,14 +1725,14 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; - gnu*) - # Under GNU Hurd, this test is not required because there is - # no limit to the length of command line arguments. + gnu* | ironclad*) + # Under GNU Hurd and Ironclad, this test is not required because there + # is no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; - cygwin* | mingw* | cegcc*) + cygwin* | mingw* | windows* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, @@ -1767,7 +1754,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl lt_cv_sys_max_cmd_len=8192; ;; - bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) + darwin* | dragonfly* | freebsd* | midnightbsd* | netbsd* | openbsd*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` @@ -1810,7 +1797,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + lt_cv_sys_max_cmd_len=`echo $kargmax | $SED 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi @@ -1927,11 +1914,11 @@ else /* When -fvisibility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord () __attribute__((visibility("default"))); +int fnord (void) __attribute__((visibility("default"))); #endif -int fnord () { return 42; } -int main () +int fnord (void) { return 42; } +int main (void) { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; @@ -1988,7 +1975,7 @@ else lt_cv_dlopen_self=yes ;; - mingw* | pw32* | cegcc*) + mingw* | windows* | pw32* | cegcc*) lt_cv_dlopen=LoadLibrary lt_cv_dlopen_libs= ;; @@ -2150,7 +2137,7 @@ AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], $RM out/* && rmdir out cd .. $RM -r conftest - $RM -f conftest* + $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) @@ -2260,26 +2247,35 @@ m4_defun([_LT_CMD_STRIPLIB], striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) -if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then - test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" - test -z "$striplib" && striplib="$STRIP --strip-unneeded" - AC_MSG_RESULT([yes]) +if test -z "$STRIP"; then + AC_MSG_RESULT([no]) else -# FIXME - insert some real tests, host_os isn't really good enough - case $host_os in - darwin*) - if test -n "$STRIP"; then + if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + old_striplib="$STRIP --strip-debug" + striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) + else + case $host_os in + darwin*) + # FIXME - insert some real tests, host_os isn't really good enough striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) - else + ;; + freebsd*) + if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then + old_striplib="$STRIP --strip-debug" + striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) AC_MSG_RESULT([no]) - fi - ;; - *) - AC_MSG_RESULT([no]) - ;; - esac + ;; + esac + fi fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) @@ -2347,13 +2343,10 @@ if test yes = "$GCC"; then *) lt_awk_arg='/^libraries:/' ;; esac case $host_os in - mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; + mingw* | windows* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; *) lt_sed_strip_eq='s|=/|/|g' ;; esac - case $cc_basename in - fccpx* | FCCpx* ) lt_search_path_spec=`$CC --showme:libdirs` ;; - *) lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` ;; - esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator @@ -2408,7 +2401,7 @@ BEGIN {RS = " "; FS = "/|\n";} { # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in - mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + mingw* | windows* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` @@ -2483,7 +2476,7 @@ aix[[4-9]]*) # Unfortunately, runtime linking may impact performance, so we do # not want this to be the default eventually. Also, we use the # versioned .so libs for executables only if there is the -brtl - # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # linker flag in LDFLAGS as well, or --enable-aix-soname=svr4 only. # To allow for filename-based versioning support, we need to create # libNAME.so.V as an archive file, containing: # *) an Import File, referring to the versioned filename of the @@ -2577,7 +2570,7 @@ bsdi[[45]]*) # libtool to hard-code these into programs ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | mingw* | windows* | pw32* | cegcc*) version_type=windows shrext_cmds=.dll need_version=no @@ -2588,15 +2581,29 @@ cygwin* | mingw* | pw32* | cegcc*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \$file`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' + # If user builds GCC with multilib enabled, + # it should just install on $(libdir) + # not on $(libdir)/../bin or 32 bits dlls would override 64 bit ones. + if test xyes = x"$multilib"; then + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + $install_prog $dir/$dlname $destdir/$dlname~ + chmod a+x $destdir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib $destdir/$dlname'\'' || exit \$?; + fi' + else + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + fi postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' @@ -2605,30 +2612,30 @@ cygwin* | mingw* | pw32* | cegcc*) case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + soname_spec='`echo $libname | $SED -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; - mingw* | cegcc*) + mingw* | windows* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + library_names_spec='`echo $libname | $SED -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' ;; esac dynamic_linker='Win32 ld.exe' ;; - *,cl*) - # Native MSVC + *,cl* | *,icl*) + # Native MSVC or ICC libname_spec='$name' soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' library_names_spec='$libname.dll.lib' case $build_os in - mingw*) + mingw* | windows*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' @@ -2641,7 +2648,7 @@ m4_if([$1], [],[ done IFS=$lt_save_ifs # Convert to MSYS style. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form @@ -2678,7 +2685,7 @@ m4_if([$1], [],[ ;; *) - # Assume MSVC wrapper + # Assume MSVC and ICC wrapper library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' dynamic_linker='Win32 ld.exe' ;; @@ -2711,7 +2718,7 @@ dgux*) shlibpath_var=LD_LIBRARY_PATH ;; -freebsd* | dragonfly*) +freebsd* | dragonfly* | midnightbsd*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then @@ -2735,7 +2742,21 @@ freebsd* | dragonfly*) need_version=yes ;; esac - shlibpath_var=LD_LIBRARY_PATH + case $host_cpu in + powerpc64) + # On FreeBSD bi-arch platforms, a different variable is used for 32-bit + # binaries. See . + AC_COMPILE_IFELSE( + [AC_LANG_SOURCE( + [[int test_pointer_size[sizeof (void *) - 5]; + ]])], + [shlibpath_var=LD_LIBRARY_PATH], + [shlibpath_var=LD_32_LIBRARY_PATH]) + ;; + *) + shlibpath_var=LD_LIBRARY_PATH + ;; + esac case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes @@ -2765,8 +2786,9 @@ haiku*) soname_spec='$libname$release$shared_ext$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=no - sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' - hardcode_into_libs=yes + sys_lib_search_path_spec='/boot/system/non-packaged/develop/lib /boot/system/develop/lib' + sys_lib_dlsearch_path_spec='/boot/home/config/non-packaged/lib /boot/home/config/lib /boot/system/non-packaged/lib /boot/system/lib' + hardcode_into_libs=no ;; hpux9* | hpux10* | hpux11*) @@ -2876,7 +2898,7 @@ linux*android*) version_type=none # Android doesn't support versioned libraries. need_lib_prefix=no need_version=no - library_names_spec='$libname$release$shared_ext' + library_names_spec='$libname$release$shared_ext $libname$shared_ext' soname_spec='$libname$release$shared_ext' finish_cmds= shlibpath_var=LD_LIBRARY_PATH @@ -2888,8 +2910,9 @@ linux*android*) hardcode_into_libs=yes dynamic_linker='Android linker' - # Don't embed -rpath directories since the linker doesn't support them. - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + # -rpath works at least for libraries that are not overridden by + # libraries installed in system locations. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; # This must be glibc/ELF. @@ -2923,7 +2946,7 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) # before this can be enabled. hardcode_into_libs=yes - # Ideally, we could use ldconfig to report *all* directores which are + # Ideally, we could use ldconfig to report *all* directories which are # searched for libraries, however this is still not possible. Aside from not # being certain /sbin/ldconfig is available, command # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, @@ -2943,6 +2966,18 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) dynamic_linker='GNU/Linux ld.so' ;; +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + netbsd*) version_type=sunos need_lib_prefix=no @@ -2961,6 +2996,18 @@ netbsd*) hardcode_into_libs=yes ;; +*-mlibc) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='mlibc ld.so' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' @@ -2980,7 +3027,7 @@ newsos6) dynamic_linker='ldqnx.so' ;; -openbsd* | bitrig*) +openbsd*) version_type=sunos sys_lib_dlsearch_path_spec=/usr/lib need_lib_prefix=no @@ -3040,6 +3087,17 @@ rdos*) dynamic_linker=no ;; +serenity*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + dynamic_linker='SerenityOS LibELF' + ;; + solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no @@ -3137,6 +3195,21 @@ uts4*) shlibpath_var=LD_LIBRARY_PATH ;; +emscripten*) + version_type=none + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + dynamic_linker="Emscripten linker" + _LT_COMPILER_PIC($1)='-fPIC' + _LT_TAGVAR(archive_cmds, $1)='$CC -sSIDE_MODULE=2 -shared $libobjs $deplibs $compiler_flags -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -sSIDE_MODULE=2 -shared $libobjs $deplibs $compiler_flags -o $lib -s EXPORTED_FUNCTIONS=@$output_objdir/$soname.expsym' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(no_undefined_flag, $1)= + ;; + *) dynamic_linker=no ;; @@ -3307,24 +3380,12 @@ AC_ARG_WITH([gnu-ld], [test no = "$withval" || with_gnu_ld=yes], [with_gnu_ld=no])dnl -_LT_CC_BASENAME($CC) - ac_prog=ld - -# special care for Fujitsu C or C++ compilers -if test "$cc_basename" = fccpx || test "$cc_basename" = FCCpx ; then - if test yes = "$with_gnu_ld" || test "$host_os" = linux-gnu ; then - ac_prog=`($CC -Xg -print-prog-name=ld) 2>&5` - test -z "$LD" && LD=$ac_prog - with_gnu_ld=yes - fi -fi - -if test "$ac_prog" = ld && test yes = "$GCC" ; then +if test yes = "$GCC"; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in - *-*-mingw*) + *-*-mingw* | *-*-windows*) # gcc leaves a trailing carriage return, which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) @@ -3433,14 +3494,14 @@ case $reload_flag in esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) if test yes != "$GCC"; then reload_cmds=false fi ;; darwin*) if test yes = "$GCC"; then - reload_cmds='$LTCC $LTCFLAGS $nostdlib_flag -nostdlib $wl-r -o $output$reload_objs' + reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi @@ -3505,7 +3566,6 @@ lt_cv_deplibs_check_method='unknown' # 'none' -- dependencies not supported. # 'unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. -# 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # that responds to the $file_magic_cmd with a given extended regex. # If you have 'file' or equivalent on your system and you're not sure @@ -3522,7 +3582,7 @@ beos*) bsdi[[45]]*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' - lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_cmd='$FILECMD -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; @@ -3532,7 +3592,7 @@ cygwin*) lt_cv_file_magic_cmd='func_win32_libid' ;; -mingw* | pw32*) +mingw* | windows* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. @@ -3541,7 +3601,7 @@ mingw* | pw32*) lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. - lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64|pe-aarch64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; @@ -3556,14 +3616,14 @@ darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; -freebsd* | dragonfly*) +freebsd* | dragonfly* | midnightbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_cmd=$FILECMD lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac @@ -3577,7 +3637,7 @@ haiku*) ;; hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_cmd=$FILECMD case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' @@ -3614,7 +3674,11 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; -netbsd*) +*-mlibc) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else @@ -3624,7 +3688,7 @@ netbsd*) newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_cmd=$FILECMD lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; @@ -3632,7 +3696,7 @@ newos6*) lt_cv_deplibs_check_method=pass_all ;; -openbsd* | bitrig*) +openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else @@ -3648,6 +3712,10 @@ rdos*) lt_cv_deplibs_check_method=pass_all ;; +serenity*) + lt_cv_deplibs_check_method=pass_all + ;; + solaris*) lt_cv_deplibs_check_method=pass_all ;; @@ -3696,7 +3764,7 @@ file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in - mingw* | pw32*) + mingw* | windows* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else @@ -3748,16 +3816,16 @@ else # Tru64's nm complains that /dev/null is an invalid object file # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty case $build_os in - mingw*) lt_bad_file=conftest.nm/nofile ;; + mingw* | windows*) lt_bad_file=conftest.nm/nofile ;; *) lt_bad_file=/dev/null ;; esac - case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in + case `"$tmp_nm" -B $lt_bad_file 2>&1 | $SED '1q'` in *$lt_bad_file* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break 2 ;; *) - case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + case `"$tmp_nm" -p /dev/null 2>&1 | $SED '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break 2 @@ -3783,7 +3851,7 @@ else # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) - case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | $SED '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols -headers" ;; @@ -3839,7 +3907,7 @@ lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | mingw* | windows* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh; # decide which one to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in @@ -3871,16 +3939,16 @@ _LT_DECL([], [sharedlib_from_linklib_cmd], [1], m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt -AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], - [lt_cv_path_mainfest_tool=no +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_manifest_tool], + [lt_cv_path_manifest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then - lt_cv_path_mainfest_tool=yes + lt_cv_path_manifest_tool=yes fi rm -f conftest*]) -if test yes != "$lt_cv_path_mainfest_tool"; then +if test yes != "$lt_cv_path_manifest_tool"; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl @@ -3909,7 +3977,7 @@ AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in -*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-mingw* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) @@ -3984,7 +4052,7 @@ case $host_os in aix*) symcode='[[BCDT]]' ;; -cygwin* | mingw* | pw32* | cegcc*) +cygwin* | mingw* | windows* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) @@ -3999,7 +4067,7 @@ osf*) symcode='[[BCDEGQRST]]' ;; solaris*) - symcode='[[BDRT]]' + symcode='[[BCDRT]]' ;; sco3.2v5*) symcode='[[DT]]' @@ -4023,7 +4091,7 @@ esac if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Gets list of data symbols to import. - lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" + lt_cv_sys_global_symbol_to_import="$SED -n -e 's/^I .* \(.*\)$/\1/p'" # Adjust the below global symbol transforms to fixup imported variables. lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" @@ -4041,20 +4109,20 @@ fi # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="sed -n"\ +lt_cv_sys_global_symbol_to_cdecl="$SED -n"\ $lt_cdecl_hook\ " -e 's/^T .* \(.*\)$/extern int \1();/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ +lt_cv_sys_global_symbol_to_c_name_address="$SED -n"\ $lt_c_name_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" # Transform an extracted symbol line into symbol name with lib prefix and # symbol address. -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="$SED -n"\ $lt_c_name_lib_hook\ " -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ " -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ @@ -4063,7 +4131,7 @@ $lt_c_name_lib_hook\ # Handle CRLF in mingw tool chain opt_cr= case $build_os in -mingw*) +mingw* | windows*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac @@ -4078,7 +4146,7 @@ for ac_symprfx in "" "_"; do if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function, # D for any global variable and I for any imported variable. - # Also find C++ and __fastcall symbols from MSVC++, + # Also find C++ and __fastcall symbols from MSVC++ or ICC, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ @@ -4096,9 +4164,9 @@ for ac_symprfx in "" "_"; do " s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else - lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + lt_cv_sys_global_symbol_pipe="$SED -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi - lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | $SED '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no @@ -4114,13 +4182,14 @@ void nm_test_func(void){} #ifdef __cplusplus } #endif -int main(){nm_test_var='a';nm_test_func();return(0);} +int main(void){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm - if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then + $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD + if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" @@ -4290,7 +4359,7 @@ m4_if([$1], [CXX], [ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) + mingw* | windows* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style @@ -4344,12 +4413,7 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) - if test "$cc_basename" = FCCpx ; then # Fujitsu C++ - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xg -KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - else - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else @@ -4371,7 +4435,7 @@ m4_if([$1], [CXX], [ ;; esac ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) + mingw* | windows* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], @@ -4390,7 +4454,7 @@ m4_if([$1], [CXX], [ ;; esac ;; - freebsd* | dragonfly*) + freebsd* | dragonfly* | midnightbsd*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) @@ -4472,14 +4536,8 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; - FCCpx* ) - # Fujitsu C++ - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xg -KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; *) - case `$CC -V 2>&1 | sed 5q` in + case `$CC -V 2>&1 | $SED 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' @@ -4503,7 +4561,9 @@ m4_if([$1], [CXX], [ ;; esac ;; - netbsd*) + netbsd* | netbsdelf*-gnu) + ;; + *-mlibc) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise @@ -4533,6 +4593,8 @@ m4_if([$1], [CXX], [ ;; psos*) ;; + serenity*) + ;; solaris*) case $cc_basename in CC* | sunCC*) @@ -4625,7 +4687,7 @@ m4_if([$1], [CXX], [ # PIC is the default for these OSes. ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style @@ -4701,10 +4763,6 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; - fccpx*) # Fujitsu C Compiler - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xg -KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. @@ -4733,7 +4791,7 @@ m4_if([$1], [CXX], [ esac ;; - mingw* | cygwin* | pw32* | os2* | cegcc*) + mingw* | windows* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], @@ -4775,6 +4833,12 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; + *flang* | ftn | f18* | f95*) + # Flang compiler. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) @@ -4788,18 +4852,6 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; - frtpx* ) - # Fujitsu Fortran compiler - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Kstatic_fjlib' - ;; - fccpx* | FCCpx* ) - # Fujitsu C or C++ compiler - _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xg -KPIC' - _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' @@ -4831,7 +4883,7 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) - case `$CC -V 2>&1 | sed 5q` in + case `$CC -V 2>&1 | $SED 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' @@ -4869,6 +4921,12 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; + *-mlibc) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. @@ -4885,6 +4943,9 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; + serenity*) + ;; + solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' @@ -5014,15 +5075,15 @@ m4_if([$1], [CXX], [ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else - _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds ;; - cygwin* | mingw* | cegcc*) + cygwin* | mingw* | windows* | cegcc*) case $cc_basename in - cl*) + cl* | icl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) @@ -5078,21 +5139,18 @@ dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in - cygwin* | mingw* | pw32* | cegcc*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time + cygwin* | mingw* | windows* | pw32* | cegcc*) + # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. + # Microsoft Visual C++ or Intel C++ Compiler. if test yes != "$GCC"; then with_gnu_ld=no fi ;; interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++) + # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC) with_gnu_ld=yes ;; - openbsd* | bitrig*) - with_gnu_ld=no - ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes @@ -5139,7 +5197,7 @@ dnl Note also adjust exclude_expsyms for C++ above. _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no - case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in + case `$LD -v | $SED -e 's/([[^)]]\+)\s\+//' 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... @@ -5193,7 +5251,7 @@ _LT_EOF fi ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' @@ -5203,6 +5261,7 @@ _LT_EOF _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + _LT_TAGVAR(file_list_spec, $1)='@' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' @@ -5222,7 +5281,7 @@ _LT_EOF haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=no ;; os2*) @@ -5249,8 +5308,9 @@ _LT_EOF cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' - _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' ;; interix[[3-9]]*) @@ -5265,7 +5325,7 @@ _LT_EOF # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) @@ -5299,8 +5359,6 @@ _LT_EOF _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; nagfor*) # NAGFOR 5.3 - _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' - _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-Wl,-shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' @@ -5310,7 +5368,7 @@ _LT_EOF _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac - case `$CC -V 2>&1 | sed 5q` in + case `$CC -V 2>&1 | $SED 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes @@ -5322,13 +5380,14 @@ _LT_EOF if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi case $cc_basename in tcc*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' ;; xlf* | bgf* | bgxlf* | mpixlf*) @@ -5338,7 +5397,7 @@ _LT_EOF _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi @@ -5349,7 +5408,12 @@ _LT_EOF fi ;; - netbsd*) + *-mlibc) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + + netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= @@ -5470,7 +5534,7 @@ _LT_EOF if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' else - _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no @@ -5651,14 +5715,14 @@ _LT_EOF _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. + # Microsoft Visual C++ or Intel C++ Compiler. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in - cl*) - # Native MSVC + cl* | icl*) + # Native MSVC or ICC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes @@ -5668,14 +5732,14 @@ _LT_EOF # Tell ltmain to make .dll files, not .so files. shrext_cmds=.dll # FIXME: Setting linknames here is a bad hack. - _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_cmds, $1)='$CC -Fe$output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then cp "$export_symbols" "$output_objdir/$soname.def"; echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; else $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; fi~ - $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + $CC -Fe$tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' @@ -5699,7 +5763,7 @@ _LT_EOF fi' ;; *) - # Assume MSVC wrapper + # Assume MSVC and ICC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. @@ -5747,7 +5811,7 @@ _LT_EOF ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly*) + freebsd* | dragonfly* | midnightbsd*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes @@ -5887,11 +5951,15 @@ _LT_EOF # Fabrice Bellard et al's Tiny C Compiler _LT_TAGVAR(ld_shlibs, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' ;; esac ;; - netbsd*) + *-mlibc) + ;; + + netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else @@ -5913,7 +5981,7 @@ _LT_EOF *nto* | *qnx*) ;; - openbsd* | bitrig*) + openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no @@ -5956,8 +6024,9 @@ _LT_EOF cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' - _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' ;; osf3*) @@ -5991,6 +6060,9 @@ _LT_EOF _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; + serenity*) + ;; + solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test yes = "$GCC"; then @@ -6175,7 +6247,7 @@ x|xyes) # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), - [$RM -f conftest* + [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then @@ -6202,7 +6274,7 @@ x|xyes) else cat conftest.err 1>&5 fi - $RM -f conftest* + $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; @@ -6249,7 +6321,7 @@ _LT_TAGDECL([], [hardcode_direct], [0], _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes DIR into the resulting binary and the resulting library dependency is - "absolute", i.e impossible to change by setting $shlibpath_var if the + "absolute", i.e. impossible to change by setting $shlibpath_var if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR @@ -6307,7 +6379,7 @@ _LT_TAGVAR(objext, $1)=$objext lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests -lt_simple_link_test_code='int main(){return(0);}' +lt_simple_link_test_code='int main(void){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other @@ -6484,8 +6556,8 @@ if test yes != "$_lt_caught_CXX_error"; then # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test yes = "$with_gnu_ld"; then - _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared $nostdlib_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared $nostdlib_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' @@ -6496,13 +6568,7 @@ if test yes != "$_lt_caught_CXX_error"; then wlarc='$wl' # ancient GNU ld didn't support --whole-archive et. al. - if test "$cc_basename" == FCCpx ; then - ac_prog=`($CC -Xg -print-prog-name=ld) 2>&5` - else - ac_prog=`($CC -print-prog-name=ld) 2>&5` - fi - if eval "$ac_prog --help 2>&1" | - $GREP 'no-whole-archive' > /dev/null; then + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= @@ -6516,13 +6582,13 @@ if test yes != "$_lt_caught_CXX_error"; then # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $nostdlib_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " [[-]]L"' else GXX=no @@ -6731,10 +6797,10 @@ if test yes != "$_lt_caught_CXX_error"; then esac ;; - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) case $GXX,$cc_basename in - ,cl* | no,cl*) - # Native MSVC + ,cl* | no,cl* | ,icl* | no,icl*) + # Native MSVC or ICC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' @@ -6784,9 +6850,10 @@ if test yes != "$_lt_caught_CXX_error"; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $nostdlib_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file, use it as # is; otherwise, prepend EXPORTS... _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then @@ -6795,7 +6862,7 @@ if test yes != "$_lt_caught_CXX_error"; then echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ - $CC -shared $nostdlib_flag -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi @@ -6830,8 +6897,9 @@ if test yes != "$_lt_caught_CXX_error"; then cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ emximp -o $lib $output_objdir/$libname.def' - _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' ;; dgux*) @@ -6862,7 +6930,7 @@ if test yes != "$_lt_caught_CXX_error"; then _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; - freebsd* | dragonfly*) + freebsd* | dragonfly* | midnightbsd*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes @@ -6870,7 +6938,7 @@ if test yes != "$_lt_caught_CXX_error"; then haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' - _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=no ;; hpux9*) @@ -6897,11 +6965,11 @@ if test yes != "$_lt_caught_CXX_error"; then # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "[[-]]L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then - _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $nostdlib_flag -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no @@ -6962,20 +7030,20 @@ if test yes != "$_lt_caught_CXX_error"; then # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " [[-]]L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then case $host_cpu in hppa*64*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $nostdlib_flag -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $nostdlib_flag -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $nostdlib_flag -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi @@ -6999,7 +7067,7 @@ if test yes != "$_lt_caught_CXX_error"; then # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$SED "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in @@ -7016,9 +7084,9 @@ if test yes != "$_lt_caught_CXX_error"; then *) if test yes = "$GXX"; then if test no = "$with_gnu_ld"; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $nostdlib_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' else - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $nostdlib_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes @@ -7139,13 +7207,13 @@ if test yes != "$_lt_caught_CXX_error"; then _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' if test yes = "$supports_anon_versioning"; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' fi ;; *) - case `$CC -V 2>&1 | sed 5q` in + case `$CC -V 2>&1 | $SED 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' @@ -7194,6 +7262,10 @@ if test yes != "$_lt_caught_CXX_error"; then esac ;; + *-mlibc) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' @@ -7210,7 +7282,7 @@ if test yes != "$_lt_caught_CXX_error"; then _LT_TAGVAR(ld_shlibs, $1)=yes ;; - openbsd* | bitrig*) + openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no @@ -7288,10 +7360,10 @@ if test yes != "$_lt_caught_CXX_error"; then _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' case $host in osf3*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $nostdlib_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; *) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $nostdlib_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' ;; esac @@ -7301,7 +7373,7 @@ if test yes != "$_lt_caught_CXX_error"; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " [[-]]L"' else # FIXME: insert proper C++ library support @@ -7316,6 +7388,9 @@ if test yes != "$_lt_caught_CXX_error"; then _LT_TAGVAR(ld_shlibs, $1)=no ;; + serenity*) + ;; + sunos4*) case $cc_basename in CC*) @@ -7378,25 +7453,25 @@ if test yes != "$_lt_caught_CXX_error"; then if test yes,no = "$GXX,$with_gnu_ld"; then _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $nostdlib_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag $nostdlib_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " [[-]]L"' else # g++ 2.7 appears to require '-G' NOT '-shared' on this # platform. - _LT_TAGVAR(archive_cmds, $1)='$CC -G $nostdlib_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G $nostdlib_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " [[-]]L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' @@ -7634,7 +7709,7 @@ if AC_TRY_EVAL(ac_compile); then case $prev$p in -L* | -R* | -l*) - # Some compilers place space between "-{L,R,l}" and the path (value). + # Some compilers place space between "-{L,R,l}" and the path. # Remove the space. if test x-L = x"$p" || test x-R = x"$p" || @@ -7669,7 +7744,7 @@ if AC_TRY_EVAL(ac_compile); then # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac - elif test "x$p" != x ; then # skip if $p is empty + else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)=$prev$p else @@ -7748,14 +7823,6 @@ _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) - -ac_nostdlib_flag= -# Fujitsu compilers -if test "$cc_basename" == FCCpx || test "$cc_basename" == fccpx || test "$cc_basename" == frtpx ; then - ac_nostdlib_flag=-Xg -fi -_LT_TAGVAR(nostdlib_flag, $1)=$ac_nostdlib_flag -_LT_TAGDECL([], [nostdlib_flag], [1]) ])# _LT_SYS_HIDDEN_LIBDEPS @@ -8300,6 +8367,14 @@ _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) +# _LT_DECL_FILECMD +# ---------------- +# Check for a file(cmd) program that can be used to detect file type and magic +m4_defun([_LT_DECL_FILECMD], +[AC_CHECK_PROG([FILECMD], [file], [file], [:]) +_LT_DECL([], [FILECMD], [1], [A file(cmd) program that detects file types]) +])# _LD_DECL_FILECMD + # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates @@ -8312,73 +8387,6 @@ _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED - -m4_ifndef([AC_PROG_SED], [ -############################################################ -# NOTE: This macro has been submitted for inclusion into # -# GNU Autoconf as AC_PROG_SED. When it is available in # -# a released version of Autoconf we should remove this # -# macro and use it instead. # -############################################################ - -m4_defun([AC_PROG_SED], -[AC_MSG_CHECKING([for a sed that does not truncate output]) -AC_CACHE_VAL(lt_cv_path_SED, -[# Loop through the user's path and test for sed and gsed. -# Then use that list of sed's as ones to test for truncation. -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for lt_ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then - lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" - fi - done - done -done -IFS=$as_save_IFS -lt_ac_max=0 -lt_ac_count=0 -# Add /usr/xpg4/bin/sed as it is typically found on Solaris -# along with /bin/sed that truncates output. -for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do - test ! -f "$lt_ac_sed" && continue - cat /dev/null > conftest.in - lt_ac_count=0 - echo $ECHO_N "0123456789$ECHO_C" >conftest.in - # Check for GNU sed and select it if it is found. - if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then - lt_cv_path_SED=$lt_ac_sed - break - fi - while true; do - cat conftest.in conftest.in >conftest.tmp - mv conftest.tmp conftest.in - cp conftest.in conftest.nl - echo >>conftest.nl - $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break - cmp -s conftest.out conftest.nl || break - # 10000 chars as input seems more than enough - test 10 -lt "$lt_ac_count" && break - lt_ac_count=`expr $lt_ac_count + 1` - if test "$lt_ac_count" -gt "$lt_ac_max"; then - lt_ac_max=$lt_ac_count - lt_cv_path_SED=$lt_ac_sed - fi - done -done -]) -SED=$lt_cv_path_SED -AC_SUBST([SED]) -AC_MSG_RESULT([$SED]) -])#AC_PROG_SED -])#m4_ifndef - -# Old name: -AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) @@ -8425,7 +8433,7 @@ AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in - *-*-mingw* ) # actually msys + *-*-mingw* | *-*-windows* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) @@ -8438,7 +8446,7 @@ AC_CACHE_VAL(lt_cv_to_host_file_cmd, ;; *-*-cygwin* ) case $build in - *-*-mingw* ) # actually msys + *-*-mingw* | *-*-windows* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) @@ -8464,9 +8472,9 @@ AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in - *-*-mingw* ) + *-*-mingw* | *-*-windows* ) case $build in - *-*-mingw* ) # actually msys + *-*-mingw* | *-*-windows* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac diff --git a/scripts/ltmain.sh b/scripts/ltmain.sh index 262f144b7..3e6a3db3a 100644 --- a/scripts/ltmain.sh +++ b/scripts/ltmain.sh @@ -1,12 +1,12 @@ -#! /bin/sh +#! /usr/bin/env sh ## DO NOT EDIT - This file generated from ./build-aux/ltmain.in -## by inline-source v2014-01-03.01 +## by inline-source v2019-02-19.15 -# libtool (GNU libtool) 2.4.6 +# libtool (GNU libtool) 2.5.4 # Provide generalized library-building support services. # Written by Gordon Matzigkeit , 1996 -# Copyright (C) 1996-2015 Free Software Foundation, Inc. +# Copyright (C) 1996-2019, 2021-2024 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. @@ -31,8 +31,8 @@ PROGRAM=libtool PACKAGE=libtool -VERSION=2.4.6 -package_revision=2.4.6 +VERSION=2.5.4 +package_revision=2.5.4 ## ------ ## @@ -64,34 +64,25 @@ package_revision=2.4.6 # libraries, which are installed to $pkgauxdir. # Set a version string for this script. -scriptversion=2015-01-20.17; # UTC +scriptversion=2019-02-19.15; # UTC # General shell script boiler plate, and helper functions. # Written by Gary V. Vaughan, 2004 -# Copyright (C) 2004-2015 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. - -# As a special exception to the GNU General Public License, if you distribute -# this file as part of a program or library that is built using GNU Libtool, -# you may include this file under the same distribution terms that you use -# for the rest of that program. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# This is free software. There is NO warranty; not even for +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Copyright (C) 2004-2019, 2021, 2023-2024 Bootstrap Authors +# +# This file is dual licensed under the terms of the MIT license +# , and GPL version 2 or later +# . You must apply one of +# these licenses when using or redistributing this software or any of +# the files within it. See the URLs above, or the file `LICENSE` +# included in the Bootstrap distribution for the full license texts. -# Please report bugs or propose patches to gary@gnu.org. +# Please report bugs or propose patches to: +# ## ------ ## @@ -139,9 +130,12 @@ do _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\" fi" done - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH +# These NLS vars are set unconditionally (bootstrap issue #24). Unset those +# in case the environment reset is needed later and the $save_* variant is not +# defined (see the code above). +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL # Make sure IFS has a sensible default sp=' ' @@ -149,7 +143,7 @@ nl=' ' IFS="$sp $nl" -# There are apparently some retarded systems that use ';' as a PATH separator! +# There are apparently some systems that use ';' as a PATH separator! if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { @@ -159,6 +153,26 @@ if test "${PATH_SEPARATOR+set}" != set; then fi +# func_unset VAR +# -------------- +# Portably unset VAR. +# In some shells, an 'unset VAR' statement leaves a non-zero return +# status if VAR is already unset, which might be problematic if the +# statement is used at the end of a function (thus poisoning its return +# value) or when 'set -e' is active (causing even a spurious abort of +# the script in this case). +func_unset () +{ + { eval $1=; (eval unset $1) >/dev/null 2>&1 && eval unset $1 || : ; } +} + + +# Make sure CDPATH doesn't cause `cd` commands to output the target dir. +func_unset CDPATH + +# Make sure ${,E,F}GREP behave sanely. +func_unset GREP_OPTIONS + ## ------------------------- ## ## Locate command utilities. ## @@ -259,7 +273,7 @@ test -z "$SED" && { rm -f conftest.in conftest.tmp conftest.nl conftest.out } - func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin + func_path_progs "sed gsed" func_check_prog_sed "$PATH:/usr/xpg4/bin" rm -f conftest.sed SED=$func_path_progs_result } @@ -295,7 +309,7 @@ test -z "$GREP" && { rm -f conftest.in conftest.tmp conftest.nl conftest.out } - func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin + func_path_progs "grep ggrep" func_check_prog_grep "$PATH:/usr/xpg4/bin" GREP=$func_path_progs_result } @@ -360,6 +374,35 @@ sed_double_backslash="\ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g s/\n//g" +# require_check_ifs_backslash +# --------------------------- +# Check if we can use backslash as IFS='\' separator, and set +# $check_ifs_backshlash_broken to ':' or 'false'. +require_check_ifs_backslash=func_require_check_ifs_backslash +func_require_check_ifs_backslash () +{ + _G_save_IFS=$IFS + IFS='\' + _G_check_ifs_backshlash='a\\b' + for _G_i in $_G_check_ifs_backshlash + do + case $_G_i in + a) + check_ifs_backshlash_broken=false + ;; + '') + break + ;; + *) + check_ifs_backshlash_broken=: + break + ;; + esac + done + IFS=$_G_save_IFS + require_check_ifs_backslash=: +} + ## ----------------- ## ## Global variables. ## @@ -546,7 +589,7 @@ func_require_term_colors () # _G_HAVE_PLUSEQ_OP # Can be empty, in which case the shell is probed, "yes" if += is - # useable or anything else if it does not work. + # usable or anything else if it does not work. test -z "$_G_HAVE_PLUSEQ_OP" \ && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \ && _G_HAVE_PLUSEQ_OP=yes @@ -580,16 +623,16 @@ if test yes = "$_G_HAVE_PLUSEQ_OP"; then { $debug_cmd - func_quote_for_eval "$2" - eval "$1+=\\ \$func_quote_for_eval_result" + func_quote_arg pretty "$2" + eval "$1+=\\ \$func_quote_arg_result" }' else func_append_quoted () { $debug_cmd - func_quote_for_eval "$2" - eval "$1=\$$1\\ \$func_quote_for_eval_result" + func_quote_arg pretty "$2" + eval "$1=\$$1\\ \$func_quote_arg_result" } fi @@ -696,7 +739,7 @@ eval 'func_dirname () # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. -# value retuned in "$func_basename_result" +# value returned in "$func_basename_result" # For efficiency, we do not delegate to the functions above but instead # duplicate the functionality here. eval 'func_dirname_and_basename () @@ -854,7 +897,7 @@ func_mkdir_p () # While some portion of DIR does not yet exist... while test ! -d "$_G_directory_path"; do # ...make a list in topmost first order. Use a colon delimited - # list incase some portion of path contains whitespace. + # list in case some portion of path contains whitespace. _G_dir_list=$_G_directory_path:$_G_dir_list # If the last portion added has no slash in it, the list is done @@ -1091,85 +1134,203 @@ func_relative_path () } -# func_quote_for_eval ARG... -# -------------------------- -# Aesthetically quote ARGs to be evaled later. -# This function returns two values: -# i) func_quote_for_eval_result -# double-quoted, suitable for a subsequent eval -# ii) func_quote_for_eval_unquoted_result -# has all characters that are still active within double -# quotes backslashified. -func_quote_for_eval () +# func_quote_portable EVAL ARG +# ---------------------------- +# Internal function to portably implement func_quote_arg. Note that we still +# keep attention to performance here so we as much as possible try to avoid +# calling sed binary (so far O(N) complexity as long as func_append is O(1)). +func_quote_portable () { $debug_cmd - func_quote_for_eval_unquoted_result= - func_quote_for_eval_result= - while test 0 -lt $#; do - case $1 in - *[\\\`\"\$]*) - _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;; - *) - _G_unquoted_arg=$1 ;; - esac - if test -n "$func_quote_for_eval_unquoted_result"; then - func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg" - else - func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg" + $require_check_ifs_backslash + + func_quote_portable_result=$2 + + # one-time-loop (easy break) + while true + do + if $1; then + func_quote_portable_result=`$ECHO "$2" | $SED \ + -e "$sed_double_quote_subst" -e "$sed_double_backslash"` + break fi - case $_G_unquoted_arg in - # Double-quote args containing shell metacharacters to delay - # word splitting, command substitution and variable expansion - # for a subsequent eval. - # Many Bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - _G_quoted_arg=\"$_G_unquoted_arg\" + # Quote for eval. + case $func_quote_portable_result in + *[\\\`\"\$]*) + # Fallback to sed for $func_check_bs_ifs_broken=:, or when the string + # contains the shell wildcard characters. + case $check_ifs_backshlash_broken$func_quote_portable_result in + :*|*[\[\*\?]*) + func_quote_portable_result=`$ECHO "$func_quote_portable_result" \ + | $SED "$sed_quote_subst"` + break + ;; + esac + + func_quote_portable_old_IFS=$IFS + for _G_char in '\' '`' '"' '$' + do + # STATE($1) PREV($2) SEPARATOR($3) + set start "" "" + func_quote_portable_result=dummy"$_G_char$func_quote_portable_result$_G_char"dummy + IFS=$_G_char + for _G_part in $func_quote_portable_result + do + case $1 in + quote) + func_append func_quote_portable_result "$3$2" + set quote "$_G_part" "\\$_G_char" + ;; + start) + set first "" "" + func_quote_portable_result= + ;; + first) + set quote "$_G_part" "" + ;; + esac + done + done + IFS=$func_quote_portable_old_IFS ;; - *) - _G_quoted_arg=$_G_unquoted_arg - ;; + *) ;; esac - - if test -n "$func_quote_for_eval_result"; then - func_append func_quote_for_eval_result " $_G_quoted_arg" - else - func_append func_quote_for_eval_result "$_G_quoted_arg" - fi - shift + break done + + func_quote_portable_unquoted_result=$func_quote_portable_result + case $func_quote_portable_result in + # double-quote args containing shell metacharacters to delay + # word splitting, command substitution and variable expansion + # for a subsequent eval. + # many bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_portable_result=\"$func_quote_portable_result\" + ;; + esac } -# func_quote_for_expand ARG -# ------------------------- -# Aesthetically quote ARG to be evaled later; same as above, -# but do not quote variable references. -func_quote_for_expand () -{ - $debug_cmd +# func_quotefast_eval ARG +# ----------------------- +# Quote one ARG (internal). This is equivalent to 'func_quote_arg eval ARG', +# but optimized for speed. Result is stored in $func_quotefast_eval. +if test xyes = `(x=; printf -v x %q yes; echo x"$x") 2>/dev/null`; then + printf -v _GL_test_printf_tilde %q '~' + if test '\~' = "$_GL_test_printf_tilde"; then + func_quotefast_eval () + { + printf -v func_quotefast_eval_result %q "$1" + } + else + # Broken older Bash implementations. Make those faster too if possible. + func_quotefast_eval () + { + case $1 in + '~'*) + func_quote_portable false "$1" + func_quotefast_eval_result=$func_quote_portable_result + ;; + *) + printf -v func_quotefast_eval_result %q "$1" + ;; + esac + } + fi +else + func_quotefast_eval () + { + func_quote_portable false "$1" + func_quotefast_eval_result=$func_quote_portable_result + } +fi - case $1 in - *[\\\`\"]*) - _G_arg=`$ECHO "$1" | $SED \ - -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;; - *) - _G_arg=$1 ;; + +# func_quote_arg MODEs ARG +# ------------------------ +# Quote one ARG to be evaled later. MODEs argument may contain zero or more +# specifiers listed below separated by ',' character. This function returns two +# values: +# i) func_quote_arg_result +# double-quoted (when needed), suitable for a subsequent eval +# ii) func_quote_arg_unquoted_result +# has all characters that are still active within double +# quotes backslashified. Available only if 'unquoted' is specified. +# +# Available modes: +# ---------------- +# 'eval' (default) +# - escape shell special characters +# 'expand' +# - the same as 'eval'; but do not quote variable references +# 'pretty' +# - request aesthetic output, i.e. '"a b"' instead of 'a\ b'. This might +# be used later in func_quote to get output like: 'echo "a b"' instead +# of 'echo a\ b'. This is slower than default on some shells. +# 'unquoted' +# - produce also $func_quote_arg_unquoted_result which does not contain +# wrapping double-quotes. +# +# Examples for 'func_quote_arg pretty,unquoted string': +# +# string | *_result | *_unquoted_result +# ------------+-----------------------+------------------- +# " | \" | \" +# a b | "a b" | a b +# "a b" | "\"a b\"" | \"a b\" +# * | "*" | * +# z="${x-$y}" | "z=\"\${x-\$y}\"" | z=\"\${x-\$y}\" +# +# Examples for 'func_quote_arg pretty,unquoted,expand string': +# +# string | *_result | *_unquoted_result +# --------------+---------------------+-------------------- +# z="${x-$y}" | "z=\"${x-$y}\"" | z=\"${x-$y}\" +func_quote_arg () +{ + _G_quote_expand=false + case ,$1, in + *,expand,*) + _G_quote_expand=: + ;; esac - case $_G_arg in - # Double-quote args containing shell metacharacters to delay - # word splitting and command substitution for a subsequent eval. - # Many Bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - _G_arg=\"$_G_arg\" + case ,$1, in + *,pretty,*|*,expand,*|*,unquoted,*) + func_quote_portable $_G_quote_expand "$2" + func_quote_arg_result=$func_quote_portable_result + func_quote_arg_unquoted_result=$func_quote_portable_unquoted_result + ;; + *) + # Faster quote-for-eval for some shells. + func_quotefast_eval "$2" + func_quote_arg_result=$func_quotefast_eval_result ;; esac +} + - func_quote_for_expand_result=$_G_arg +# func_quote MODEs ARGs... +# ------------------------ +# Quote all ARGs to be evaled later and join them into single command. See +# func_quote_arg's description for more info. +func_quote () +{ + $debug_cmd + _G_func_quote_mode=$1 ; shift + func_quote_result= + while test 0 -lt $#; do + func_quote_arg "$_G_func_quote_mode" "$1" + if test -n "$func_quote_result"; then + func_append func_quote_result " $func_quote_arg_result" + else + func_append func_quote_result "$func_quote_arg_result" + fi + shift + done } @@ -1215,8 +1376,8 @@ func_show_eval () _G_cmd=$1 _G_fail_exp=${2-':'} - func_quote_for_expand "$_G_cmd" - eval "func_notquiet $func_quote_for_expand_result" + func_quote_arg pretty,expand "$_G_cmd" + eval "func_notquiet $func_quote_arg_result" $opt_dry_run || { eval "$_G_cmd" @@ -1241,8 +1402,8 @@ func_show_eval_locale () _G_fail_exp=${2-':'} $opt_quiet || { - func_quote_for_expand "$_G_cmd" - eval "func_echo $func_quote_for_expand_result" + func_quote_arg expand,pretty "$_G_cmd" + eval "func_echo $func_quote_arg_result" } $opt_dry_run || { @@ -1369,30 +1530,26 @@ func_lt_ver () # End: #! /bin/sh -# Set a version string for this script. -scriptversion=2014-01-07.03; # UTC - # A portable, pluggable option parser for Bourne shell. # Written by Gary V. Vaughan, 2010 -# Copyright (C) 2010-2015 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# This is free software. There is NO warranty; not even for +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Copyright (C) 2010-2019, 2021, 2023-2024 Bootstrap Authors +# +# This file is dual licensed under the terms of the MIT license +# , and GPL version 2 or later +# . You must apply one of +# these licenses when using or redistributing this software or any of +# the files within it. See the URLs above, or the file `LICENSE` +# included in the Bootstrap distribution for the full license texts. -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# Please report bugs or propose patches to: +# -# Please report bugs or propose patches to gary@gnu.org. +# Set a version string for this script. +scriptversion=2019-02-19.15; # UTC ## ------ ## @@ -1415,7 +1572,7 @@ scriptversion=2014-01-07.03; # UTC # # In order for the '--version' option to work, you will need to have a # suitably formatted comment like the one at the top of this file -# starting with '# Written by ' and ending with '# warranty; '. +# starting with '# Written by ' and ending with '# Copyright'. # # For '-h' and '--help' to work, you will also need a one line # description of your script's purpose in a comment directly above the @@ -1427,7 +1584,7 @@ scriptversion=2014-01-07.03; # UTC # to display verbose messages only when your user has specified # '--verbose'. # -# After sourcing this file, you can plug processing for additional +# After sourcing this file, you can plug in processing for additional # options by amending the variables from the 'Configuration' section # below, and following the instructions in the 'Option parsing' # section further down. @@ -1476,8 +1633,8 @@ fatal_help="Try '\$progname --help' for more information." ## ------------------------- ## # This section contains functions for adding, removing, and running hooks -# to the main code. A hook is just a named list of of function, that can -# be run in order later on. +# in the main code. A hook is just a list of function names that can be +# run in order later on. # func_hookable FUNC_NAME # ----------------------- @@ -1510,7 +1667,8 @@ func_add_hook () # func_remove_hook FUNC_NAME HOOK_FUNC # ------------------------------------ -# Remove HOOK_FUNC from the list of functions called by FUNC_NAME. +# Remove HOOK_FUNC from the list of hook functions to be called by +# FUNC_NAME. func_remove_hook () { $debug_cmd @@ -1519,10 +1677,28 @@ func_remove_hook () } +# func_propagate_result FUNC_NAME_A FUNC_NAME_B +# --------------------------------------------- +# If the *_result variable of FUNC_NAME_A _is set_, assign its value to +# *_result variable of FUNC_NAME_B. +func_propagate_result () +{ + $debug_cmd + + func_propagate_result_result=: + if eval "test \"\${${1}_result+set}\" = set" + then + eval "${2}_result=\$${1}_result" + else + func_propagate_result_result=false + fi +} + + # func_run_hooks FUNC_NAME [ARG]... # --------------------------------- # Run all hook functions registered to FUNC_NAME. -# It is assumed that the list of hook functions contains nothing more +# It's assumed that the list of hook functions contains nothing more # than a whitespace-delimited list of legal shell function names, and # no effort is wasted trying to catch shell meta-characters or preserve # whitespace. @@ -1532,22 +1708,19 @@ func_run_hooks () case " $hookable_fns " in *" $1 "*) ;; - *) func_fatal_error "'$1' does not support hook funcions.n" ;; + *) func_fatal_error "'$1' does not support hook functions." ;; esac eval _G_hook_fns=\$$1_hooks; shift for _G_hook in $_G_hook_fns; do - eval $_G_hook '"$@"' - - # store returned options list back into positional - # parameters for next 'cmd' execution. - eval _G_hook_result=\$${_G_hook}_result - eval set dummy "$_G_hook_result"; shift + func_unset "${_G_hook}_result" + eval $_G_hook '${1+"$@"}' + func_propagate_result $_G_hook func_run_hooks + if $func_propagate_result_result; then + eval set dummy "$func_run_hooks_result"; shift + fi done - - func_quote_for_eval ${1+"$@"} - func_run_hooks_result=$func_quote_for_eval_result } @@ -1557,10 +1730,18 @@ func_run_hooks () ## --------------- ## # In order to add your own option parsing hooks, you must accept the -# full positional parameter list in your hook function, remove any -# options that you action, and then pass back the remaining unprocessed -# options in '_result', escaped suitably for -# 'eval'. Like this: +# full positional parameter list from your hook function. You may remove +# or edit any options that you action, and then pass back the remaining +# unprocessed options in '_result', escaped +# suitably for 'eval'. +# +# The '_result' variable is automatically unset +# before your hook gets called; for best performance, only set the +# *_result variable when necessary (i.e. don't call the 'func_quote' +# function unnecessarily because it can be an expensive operation on some +# machines). +# +# Like this: # # my_options_prep () # { @@ -1570,9 +1751,8 @@ func_run_hooks () # usage_message=$usage_message' # -s, --silent don'\''t print informational messages # ' -# -# func_quote_for_eval ${1+"$@"} -# my_options_prep_result=$func_quote_for_eval_result +# # No change in '$@' (ignored completely by this hook). Leave +# # my_options_prep_result variable intact. # } # func_add_hook func_options_prep my_options_prep # @@ -1581,25 +1761,36 @@ func_run_hooks () # { # $debug_cmd # -# # Note that for efficiency, we parse as many options as we can +# args_changed=false +# +# # Note that, for efficiency, we parse as many options as we can # # recognise in a loop before passing the remainder back to the # # caller on the first unrecognised argument we encounter. # while test $# -gt 0; do # opt=$1; shift # case $opt in -# --silent|-s) opt_silent=: ;; +# --silent|-s) opt_silent=: +# args_changed=: +# ;; # # Separate non-argument short options: # -s*) func_split_short_opt "$_G_opt" # set dummy "$func_split_short_opt_name" \ # "-$func_split_short_opt_arg" ${1+"$@"} # shift +# args_changed=: # ;; -# *) set dummy "$_G_opt" "$*"; shift; break ;; +# *) # Make sure the first unrecognised option "$_G_opt" +# # is added back to "$@" in case we need it later, +# # if $args_changed was set to 'true'. +# set dummy "$_G_opt" ${1+"$@"}; shift; break ;; # esac # done # -# func_quote_for_eval ${1+"$@"} -# my_silent_option_result=$func_quote_for_eval_result +# # Only call 'func_quote' here if we processed at least one argument. +# if $args_changed; then +# func_quote eval ${1+"$@"} +# my_silent_option_result=$func_quote_result +# fi # } # func_add_hook func_parse_options my_silent_option # @@ -1610,17 +1801,26 @@ func_run_hooks () # # $opt_silent && $opt_verbose && func_fatal_help "\ # '--silent' and '--verbose' options are mutually exclusive." -# -# func_quote_for_eval ${1+"$@"} -# my_option_validation_result=$func_quote_for_eval_result # } # func_add_hook func_validate_options my_option_validation # -# You'll alse need to manually amend $usage_message to reflect the extra +# You'll also need to manually amend $usage_message to reflect the extra # options you parse. It's preferable to append if you can, so that # multiple option parsing hooks can be added safely. +# func_options_finish [ARG]... +# ---------------------------- +# Finishing the option parse loop (call 'func_options' hooks ATM). +func_options_finish () +{ + $debug_cmd + + func_run_hooks func_options ${1+"$@"} + func_propagate_result func_run_hooks func_options_finish +} + + # func_options [ARG]... # --------------------- # All the functions called inside func_options are hookable. See the @@ -1630,17 +1830,27 @@ func_options () { $debug_cmd - func_options_prep ${1+"$@"} - eval func_parse_options \ - ${func_options_prep_result+"$func_options_prep_result"} - eval func_validate_options \ - ${func_parse_options_result+"$func_parse_options_result"} + _G_options_quoted=false - eval func_run_hooks func_options \ - ${func_validate_options_result+"$func_validate_options_result"} + for my_func in options_prep parse_options validate_options options_finish + do + func_unset func_${my_func}_result + func_unset func_run_hooks_result + eval func_$my_func '${1+"$@"}' + func_propagate_result func_$my_func func_options + if $func_propagate_result_result; then + eval set dummy "$func_options_result"; shift + _G_options_quoted=: + fi + done - # save modified positional parameters for caller - func_options_result=$func_run_hooks_result + $_G_options_quoted || { + # As we (func_options) are top-level options-parser function and + # nobody quoted "$@" for us yet, we need to do it explicitly for + # caller. + func_quote eval ${1+"$@"} + func_options_result=$func_quote_result + } } @@ -1649,9 +1859,8 @@ func_options () # All initialisations required before starting the option parse loop. # Note that when calling hook functions, we pass through the list of # positional parameters. If a hook function modifies that list, and -# needs to propogate that back to rest of this script, then the complete -# modified list must be put in 'func_run_hooks_result' before -# returning. +# needs to propagate that back to rest of this script, then the complete +# modified list must be put in 'func_run_hooks_result' before returning. func_hookable func_options_prep func_options_prep () { @@ -1662,9 +1871,7 @@ func_options_prep () opt_warning_types= func_run_hooks func_options_prep ${1+"$@"} - - # save modified positional parameters for caller - func_options_prep_result=$func_run_hooks_result + func_propagate_result func_run_hooks func_options_prep } @@ -1676,25 +1883,32 @@ func_parse_options () { $debug_cmd - func_parse_options_result= - + _G_parse_options_requote=false # this just eases exit handling while test $# -gt 0; do # Defer to hook functions for initial option parsing, so they # get priority in the event of reusing an option name. func_run_hooks func_parse_options ${1+"$@"} - - # Adjust func_parse_options positional parameters to match - eval set dummy "$func_run_hooks_result"; shift + func_propagate_result func_run_hooks func_parse_options + if $func_propagate_result_result; then + eval set dummy "$func_parse_options_result"; shift + # Even though we may have changed "$@", we passed the "$@" array + # down into the hook and it quoted it for us (because we are in + # this if-branch). No need to quote it again. + _G_parse_options_requote=false + fi # Break out of the loop if we already parsed every option. test $# -gt 0 || break + # We expect that one of the options parsed in this function matches + # and thus we remove _G_opt from "$@" and need to re-quote. + _G_match_parse_options=: _G_opt=$1 shift case $_G_opt in --debug|-x) debug_cmd='set -x' - func_echo "enabling shell trace mode" + func_echo "enabling shell trace mode" >&2 $debug_cmd ;; @@ -1704,7 +1918,10 @@ func_parse_options () ;; --warnings|--warning|-W) - test $# = 0 && func_missing_arg $_G_opt && break + if test $# = 0 && func_missing_arg $_G_opt; then + _G_parse_options_requote=: + break + fi case " $warning_categories $1" in *" $1 "*) # trailing space prevents matching last $1 above @@ -1757,15 +1974,24 @@ func_parse_options () shift ;; - --) break ;; + --) _G_parse_options_requote=: ; break ;; -*) func_fatal_help "unrecognised option: '$_G_opt'" ;; - *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + *) set dummy "$_G_opt" ${1+"$@"}; shift + _G_match_parse_options=false + break + ;; esac + + if $_G_match_parse_options; then + _G_parse_options_requote=: + fi done - # save modified positional parameters for caller - func_quote_for_eval ${1+"$@"} - func_parse_options_result=$func_quote_for_eval_result + if $_G_parse_options_requote; then + # save modified positional parameters for caller + func_quote eval ${1+"$@"} + func_parse_options_result=$func_quote_result + fi } @@ -1782,12 +2008,10 @@ func_validate_options () test -n "$opt_warning_types" || opt_warning_types=" $warning_categories" func_run_hooks func_validate_options ${1+"$@"} + func_propagate_result func_run_hooks func_validate_options # Bail if the options were screwed! $exit_cmd $EXIT_FAILURE - - # save modified positional parameters for caller - func_validate_options_result=$func_run_hooks_result } @@ -1843,8 +2067,8 @@ func_missing_arg () # func_split_equals STRING # ------------------------ -# Set func_split_equals_lhs and func_split_equals_rhs shell variables after -# splitting STRING at the '=' sign. +# Set func_split_equals_lhs and func_split_equals_rhs shell variables +# after splitting STRING at the '=' sign. test -z "$_G_HAVE_XSI_OPS" \ && (eval 'x=a/b/c; test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \ @@ -1859,8 +2083,9 @@ then func_split_equals_lhs=${1%%=*} func_split_equals_rhs=${1#*=} - test "x$func_split_equals_lhs" = "x$1" \ - && func_split_equals_rhs= + if test "x$func_split_equals_lhs" = "x$1"; then + func_split_equals_rhs= + fi }' else # ...otherwise fall back to using expr, which is often a shell builtin. @@ -1870,7 +2095,7 @@ else func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'` func_split_equals_rhs= - test "x$func_split_equals_lhs" = "x$1" \ + test "x$func_split_equals_lhs=" = "x$1" \ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'` } fi #func_split_equals @@ -1896,7 +2121,7 @@ else { $debug_cmd - func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'` + func_split_short_opt_name=`expr "x$1" : 'x\(-.\)'` func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'` } fi #func_split_short_opt @@ -1938,31 +2163,44 @@ func_usage_message () # func_version # ------------ # Echo version message to standard output and exit. +# The version message is extracted from the calling file's header +# comments, with leading '# ' stripped: +# 1. First display the progname and version +# 2. Followed by the header comment line matching /^# Written by / +# 3. Then a blank line followed by the first following line matching +# /^# Copyright / +# 4. Immediately followed by any lines between the previous matches, +# except lines preceding the intervening completely blank line. +# For example, see the header comments of this file. func_version () { $debug_cmd printf '%s\n' "$progname $scriptversion" $SED -n ' - /(C)/!b go - :more - /\./!{ - N - s|\n# | | - b more - } - :go - /^# Written by /,/# warranty; / { - s|^# || - s|^# *$|| - s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| - p + /^# Written by /!b + s|^# ||; p; n + + :fwd2blnk + /./ { + n + b fwd2blnk } - /^# Written by / { - s|^# || - p + p; n + + :holdwrnt + s|^# || + s|^# *$|| + /^Copyright /!{ + /./H + n + b holdwrnt } - /^warranty; /q' < "$progpath" + + s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2| + G + s|\(\n\)\n*|\1|g + p; q' < "$progpath" exit $? } @@ -1972,12 +2210,35 @@ func_version () # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) -# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC" +# time-stamp-pattern: "30/scriptversion=%:y-%02m-%02d.%02H; # UTC" # time-stamp-time-zone: "UTC" # End: # Set a version string. -scriptversion='(GNU libtool) 2.4.6' +scriptversion='(GNU libtool) 2.5.4' + +# func_version +# ------------ +# Echo version message to standard output and exit. +func_version () +{ + $debug_cmd + + year=`date +%Y` + + cat < +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. + +Originally written by Gordon Matzigkeit, 1996 +(See AUTHORS for complete contributor listing) +EOF + + exit $? +} # func_echo ARG... @@ -2000,18 +2261,6 @@ func_echo () } -# func_warning ARG... -# ------------------- -# Libtool warnings are not categorized, so override funclib.sh -# func_warning with this simpler definition. -func_warning () -{ - $debug_cmd - - $warning_func ${1+"$@"} -} - - ## ---------------- ## ## Options parsing. ## ## ---------------- ## @@ -2023,19 +2272,23 @@ usage='$progpath [OPTION]... [MODE-ARG]...' # Short help message in response to '-h'. usage_message="Options: - --config show all configuration variables - --debug enable verbose shell tracing - -n, --dry-run display commands without modifying any files - --features display basic configuration information and exit - --mode=MODE use operation mode MODE - --no-warnings equivalent to '-Wnone' - --preserve-dup-deps don't remove duplicate dependency libraries - --quiet, --silent don't print informational messages - --tag=TAG use configuration variables from tag TAG - -v, --verbose print more informational messages than default - --version print version information - -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] - -h, --help, --help-all print short, long, or detailed help message + --config show all configuration variables + --debug enable verbose shell tracing + -n, --dry-run display commands without modifying any files + --features display basic configuration information + --finish use operation '--mode=finish' + --mode=MODE use operation mode MODE + --no-finish don't update shared library cache + --no-quiet, --no-silent print default informational messages + --no-warnings equivalent to '-Wnone' + --preserve-dup-deps don't remove duplicate dependency libraries + --quiet, --silent don't print informational messages + --reorder-cache=DIRS reorder shared library cache for preferred DIRS + --tag=TAG use configuration variables from tag TAG + -v, --verbose print more informational messages than default + --version print version information + -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all] + -h, --help, --help-all print short, long, or detailed help message " # Additional text appended to 'usage_message' in response to '--help'. @@ -2068,13 +2321,13 @@ include the following information: compiler: $LTCC compiler flags: $LTCFLAGS linker: $LD (gnu? $with_gnu_ld) - version: $progname (GNU libtool) 2.4.6 + version: $progname $scriptversion automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q` autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q` Report bugs to . -GNU libtool home page: . -General help using GNU software: ." +GNU libtool home page: . +General help using GNU software: ." exit 0 } @@ -2264,12 +2517,17 @@ libtool_options_prep () opt_dry_run=false opt_help=false opt_mode= + opt_reorder_cache=false opt_preserve_dup_deps=false opt_quiet=false + opt_finishing=true + opt_warning= nonopt= preserve_args= + _G_rc_lt_options_prep=: + # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) @@ -2293,11 +2551,16 @@ libtool_options_prep () uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; + *) + _G_rc_lt_options_prep=false + ;; esac - # Pass back the list of options. - func_quote_for_eval ${1+"$@"} - libtool_options_prep_result=$func_quote_for_eval_result + if $_G_rc_lt_options_prep; then + # Pass back the list of options. + func_quote eval ${1+"$@"} + libtool_options_prep_result=$func_quote_result + fi } func_add_hook func_options_prep libtool_options_prep @@ -2309,9 +2572,12 @@ libtool_parse_options () { $debug_cmd + _G_rc_lt_parse_options=false + # Perform our own loop to consume as many options as possible in # each iteration. while test $# -gt 0; do + _G_match_lt_parse_options=: _G_opt=$1 shift case $_G_opt in @@ -2345,14 +2611,18 @@ libtool_parse_options () clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error - *) func_error "invalid argument for $_G_opt" + *) func_error "invalid argument '$1' for $_G_opt" exit_cmd=exit - break ;; esac shift ;; + --no-finish) + opt_finishing=false + func_append preserve_args " $_G_opt" + ;; + --no-silent|--no-quiet) opt_quiet=false func_append preserve_args " $_G_opt" @@ -2368,6 +2638,24 @@ libtool_parse_options () func_append preserve_args " $_G_opt" ;; + --reorder-cache) + opt_reorder_cache=true + shared_lib_dirs=$1 + if test -n "$shared_lib_dirs"; then + case $1 in + # Must begin with /: + /*) ;; + + # Catch anything else as an error (relative paths) + *) func_error "invalid argument '$1' for $_G_opt" + func_error "absolute paths are required for $_G_opt" + exit_cmd=exit + ;; + esac + fi + shift + ;; + --silent|--quiet) opt_quiet=: opt_verbose=false @@ -2386,19 +2674,36 @@ libtool_parse_options () func_append preserve_args " $_G_opt" ;; - # An option not handled by this hook function: - *) set dummy "$_G_opt" ${1+"$@"}; shift; break ;; + # An option not handled by this hook function: + *) set dummy "$_G_opt" ${1+"$@"} ; shift + _G_match_lt_parse_options=false + break + ;; esac + $_G_match_lt_parse_options && _G_rc_lt_parse_options=: done - - # save modified positional parameters for caller - func_quote_for_eval ${1+"$@"} - libtool_parse_options_result=$func_quote_for_eval_result + if $_G_rc_lt_parse_options; then + # save modified positional parameters for caller + func_quote eval ${1+"$@"} + libtool_parse_options_result=$func_quote_result + fi } func_add_hook func_parse_options libtool_parse_options +# func_warning ARG... +# ------------------- +# Libtool warnings are not categorized, so override funclib.sh +# func_warning with this simpler definition. +func_warning () +{ + if $opt_warning; then + $debug_cmd + $warning_func ${1+"$@"} + fi +} + # libtool_validate_options [ARG]... # --------------------------------- @@ -2415,10 +2720,10 @@ libtool_validate_options () # preserve --debug test : = "$debug_cmd" || func_append preserve_args " --debug" - case $host in + case $host_os in # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452 # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788 - *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*) + cygwin* | mingw* | windows* | pw32* | cegcc* | solaris2* | os2*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; @@ -2451,8 +2756,8 @@ libtool_validate_options () } # Pass back the unparsed argument list - func_quote_for_eval ${1+"$@"} - libtool_validate_options_result=$func_quote_for_eval_result + func_quote eval ${1+"$@"} + libtool_validate_options_result=$func_quote_result } func_add_hook func_validate_options libtool_validate_options @@ -2750,7 +3055,7 @@ EOF # func_convert_core_file_wine_to_w32 ARG # Helper function used by file name conversion functions when $build is *nix, -# and $host is mingw, cygwin, or some other w32 environment. Relies on a +# and $host is mingw, windows, cygwin, or some other w32 environment. Relies on a # correctly configured wine environment available, with the winepath program # in $build's $PATH. # @@ -2782,9 +3087,10 @@ func_convert_core_file_wine_to_w32 () # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and -# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly -# configured wine environment available, with the winepath program in $build's -# $PATH. Assumes ARG has no leading or trailing path separator characters. +# $host is mingw, windows, cygwin, or some other w32 environment. Relies on a +# correctly configured wine environment available, with the winepath program +# in $build's $PATH. Assumes ARG has no leading or trailing path separator +# characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. @@ -2927,6 +3233,15 @@ func_convert_path_front_back_pathsep () # end func_convert_path_front_back_pathsep +# func_convert_delimited_path PATH ORIG_DELIMITER NEW_DELIMITER +# Replaces a delimiter for a given path. +func_convert_delimited_path () +{ + converted_path=`$ECHO "$1" | $SED "s#$2#$3#g"` +} +# end func_convert_delimited_path + + ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## @@ -3261,6 +3576,65 @@ func_dll_def_p () } +# func_reorder_shared_lib_cache DIRS +# Reorder the shared library cache by unconfiguring previous shared library cache +# and configuring preferred search directories before previous search directories. +# Previous shared library cache: /usr/lib /usr/local/lib +# Preferred search directories: /tmp/testing +# Reordered shared library cache: /tmp/testing /usr/lib /usr/local/lib +func_reorder_shared_lib_cache () +{ + $debug_cmd + + case $host_os in + openbsd*) + get_search_directories=`PATH="$PATH:/sbin" ldconfig -r | $GREP "search directories" | $SED "s#.*search directories:\ ##g"` + func_convert_delimited_path "$get_search_directories" ':' '\ ' + save_search_directories=$converted_path + func_convert_delimited_path "$1" ':' '\ ' + + # Ensure directories exist + for dir in $converted_path; do + # Ensure each directory is an absolute path + case $dir in + /*) ;; + *) func_error "Directory '$dir' is not an absolute path" + exit $EXIT_FAILURE ;; + esac + # Ensure no trailing slashes + func_stripname '' '/' "$dir" + dir=$func_stripname_result + if test -d "$dir"; then + if test -n "$preferred_search_directories"; then + preferred_search_directories="$preferred_search_directories $dir" + else + preferred_search_directories=$dir + fi + else + func_error "Directory '$dir' does not exist" + exit $EXIT_FAILURE + fi + done + + PATH="$PATH:/sbin" ldconfig -U $save_search_directories + PATH="$PATH:/sbin" ldconfig -m $preferred_search_directories $save_search_directories + get_search_directories=`PATH="$PATH:/sbin" ldconfig -r | $GREP "search directories" | $SED "s#.*search directories:\ ##g"` + func_convert_delimited_path "$get_search_directories" ':' '\ ' + reordered_search_directories=$converted_path + + $ECHO "Original: $save_search_directories" + $ECHO "Reordered: $reordered_search_directories" + exit $EXIT_SUCCESS + ;; + *) + func_error "--reorder-cache is not supported for host_os=$host_os." + exit $EXIT_FAILURE + ;; + esac +} +# end func_reorder_shared_lib_cache + + # func_mode_compile arg... func_mode_compile () { @@ -3418,8 +3792,8 @@ func_mode_compile () esac done - func_quote_for_eval "$libobj" - test "X$libobj" != "X$func_quote_for_eval_result" \ + func_quote_arg pretty "$libobj" + test "X$libobj" != "X$func_quote_arg_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name '$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" @@ -3439,7 +3813,7 @@ func_mode_compile () # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in - cygwin* | mingw* | pw32* | os2* | cegcc*) + cygwin* | mingw* | windows* | pw32* | os2* | cegcc*) pic_mode=default ;; esac @@ -3492,8 +3866,8 @@ compiler." func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result - func_quote_for_eval "$srcfile" - qsrcfile=$func_quote_for_eval_result + func_quote_arg pretty "$srcfile" + qsrcfile=$func_quote_arg_result # Only build a PIC object if we are building libtool libraries. if test yes = "$build_libtool_libs"; then @@ -3648,7 +4022,8 @@ This mode accepts the following additional options: -prefer-non-pic try to build non-PIC objects only -shared do not build a '.o' file suitable for static linking -static only build a '.o' file suitable for static linking - -Wc,FLAG pass FLAG directly to the compiler + -Wc,FLAG + -Xcompiler FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a 'standard' object file from the given SOURCEFILE. @@ -3754,6 +4129,8 @@ The following components of LINK-COMMAND are treated specially: -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wa,FLAG + -Xassembler FLAG pass linker-specific FLAG directly to the assembler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) @@ -3830,6 +4207,12 @@ if $opt_help; then fi +# If option '--reorder-cache', reorder the shared library cache and exit. +if $opt_reorder_cache; then + func_reorder_shared_lib_cache $shared_lib_dirs +fi + + # func_mode_execute arg... func_mode_execute () { @@ -4014,7 +4397,7 @@ func_mode_finish () fi fi - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs" && $opt_finishing; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. @@ -4039,6 +4422,12 @@ func_mode_finish () for libdir in $libdirs; do $ECHO " $libdir" done + if test "false" = "$opt_finishing"; then + echo + echo "NOTE: finish_cmds were not executed during testing, so you must" + echo "manually run ldconfig to add a given test directory, LIBDIR, to" + echo "the search path for generated executables." + fi echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" @@ -4096,8 +4485,8 @@ func_mode_install () case $nonopt in *shtool*) :;; *) false;; esac then # Aesthetically quote it. - func_quote_for_eval "$nonopt" - install_prog="$func_quote_for_eval_result " + func_quote_arg pretty "$nonopt" + install_prog="$func_quote_arg_result " arg=$1 shift else @@ -4107,8 +4496,8 @@ func_mode_install () # The real first argument should be the name of the installation program. # Aesthetically quote it. - func_quote_for_eval "$arg" - func_append install_prog "$func_quote_for_eval_result" + func_quote_arg pretty "$arg" + func_append install_prog "$func_quote_arg_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; @@ -4165,12 +4554,12 @@ func_mode_install () esac # Aesthetically quote the argument. - func_quote_for_eval "$arg" - func_append install_prog " $func_quote_for_eval_result" + func_quote_arg pretty "$arg" + func_append install_prog " $func_quote_arg_result" if test -n "$arg2"; then - func_quote_for_eval "$arg2" + func_quote_arg pretty "$arg2" fi - func_append install_shared_prog " $func_quote_for_eval_result" + func_append install_shared_prog " $func_quote_arg_result" done test -z "$install_prog" && \ @@ -4181,8 +4570,8 @@ func_mode_install () if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else - func_quote_for_eval "$install_override_mode" - func_append install_shared_prog " -m $func_quote_for_eval_result" + func_quote_arg pretty "$install_override_mode" + func_append install_shared_prog " -m $func_quote_arg_result" fi fi @@ -4275,8 +4664,15 @@ func_mode_install () func_append dir "$objdir" if test -n "$relink_command"; then + # Strip any trailing slash from the destination. + func_stripname '' '/' "$libdir" + destlibdir=$func_stripname_result + + func_stripname '' '/' "$destdir" + s_destdir=$func_stripname_result + # Determine the prefix the user has applied to our future dir. - inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + inst_prefix_dir=`$ECHO "X$s_destdir" | $Xsed -e "s%$destlibdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that @@ -4313,7 +4709,7 @@ func_mode_install () 'exit $?' tstripme=$stripme case $host_os in - cygwin* | mingw* | pw32* | cegcc*) + cygwin* | mingw* | windows* | pw32* | cegcc*) case $realname in *.dll.a) tstripme= @@ -4426,7 +4822,7 @@ func_mode_install () # Do a test to see if this is really a libtool program. case $host in - *cygwin* | *mingw*) + *cygwin* | *mingw* | *windows*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result @@ -4478,8 +4874,8 @@ func_mode_install () relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_quiet || { - func_quote_for_expand "$relink_command" - eval "func_echo $func_quote_for_expand_result" + func_quote_arg expand,pretty "$relink_command" + eval "func_echo $func_quote_arg_result" } if eval "$relink_command"; then : else @@ -4654,7 +5050,7 @@ extern \"C\" { $RM $export_symbols eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *mingw* | *windows* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; @@ -4666,7 +5062,7 @@ extern \"C\" { eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *mingw* | *windows* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; @@ -4680,7 +5076,7 @@ extern \"C\" { func_basename "$dlprefile" name=$func_basename_result case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *mingw* | *windows* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" @@ -4706,8 +5102,16 @@ extern \"C\" { eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 - eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | - $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + case $host in + i[3456]86-*-mingw32*) + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + ;; + *) + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/__nm_//' >> '$nlist'" + ;; + esac } else # not an import lib $opt_dry_run || { @@ -4855,7 +5259,7 @@ static const void *lt_preloaded_setup() { # Transform the symbol file into the correct name. symfileobj=$output_objdir/${my_outputname}S.$objext case $host in - *cygwin* | *mingw* | *cegcc* ) + *cygwin* | *mingw* | *windows* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` @@ -4931,7 +5335,7 @@ func_win32_libid () *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | - $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64|pe-aarch64)' >/dev/null; then case $nm_interface in "MS dumpbin") if func_cygming_ms_implib_p "$1" || @@ -5198,7 +5602,7 @@ func_extract_archives () # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to -# incorporate the script contents within a cygwin/mingw +# incorporate the script contents within a cygwin/mingw/windows # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. @@ -5206,7 +5610,7 @@ func_extract_archives () # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory where it is stored is -# the $objdir directory. This is a cygwin/mingw-specific +# the $objdir directory. This is a cygwin/mingw/windows-specific # behavior. func_emit_wrapper () { @@ -5258,7 +5662,8 @@ else if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" - qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + func_quote_arg pretty "$ECHO" + qECHO=$func_quote_arg_result $ECHO "\ # A function that is used when there is no print builtin or printf. @@ -5268,7 +5673,7 @@ func_fallback_echo () \$1 _LTECHO_EOF' } - ECHO=\"$qECHO\" + ECHO=$qECHO fi # Very basic option parsing. These options are (a) specific to @@ -5330,7 +5735,7 @@ func_exec_program_core () " case $host in # Backslashes separate directories on plain windows - *-*-mingw | *-*-os2* | *-cegcc*) + *-*-mingw* | *-*-windows* | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2 @@ -5398,7 +5803,7 @@ func_exec_program () file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done - # Usually 'no', except on cygwin/mingw when embedded into + # Usually 'no', except on cygwin/mingw/windows when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then @@ -5530,7 +5935,7 @@ EOF #endif #include #include -#ifdef _MSC_VER +#if defined _WIN32 && !defined __GNUC__ # include # include # include @@ -5555,7 +5960,7 @@ EOF /* declarations of non-ANSI functions */ #if defined __MINGW32__ # ifdef __STRICT_ANSI__ -int _putenv (const char *); +_CRTIMP int __cdecl _putenv (const char *); # endif #elif defined __CYGWIN__ # ifdef __STRICT_ANSI__ @@ -5753,7 +6158,7 @@ main (int argc, char *argv[]) { EOF case $host in - *mingw* | *cygwin* ) + *mingw* | *windows* | *cygwin* ) # make stdout use "unix" line endings echo " setmode(1,_O_BINARY);" ;; @@ -5772,7 +6177,7 @@ EOF { /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX namespace, but it is not one of the ones we know about and - have already dealt with, above (inluding dump-script), then + have already dealt with, above (including dump-script), then report an error. Otherwise, targets might begin to believe they are allowed to use options in the LTWRAPPER_OPTION_PREFIX namespace. The first time any user complains about this, we'll @@ -5856,7 +6261,7 @@ EOF EOF case $host_os in - mingw*) + mingw* | windows*) cat <<"EOF" { char* p; @@ -5898,7 +6303,7 @@ EOF EOF case $host_os in - mingw*) + mingw* | windows*) cat <<"EOF" /* execv doesn't actually work on mingw as expected on unix */ newargz = prepare_spawn (newargz); @@ -6317,7 +6722,7 @@ lt_update_lib_path (const char *name, const char *value) EOF case $host_os in - mingw*) + mingw* | windows*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). @@ -6492,7 +6897,7 @@ func_mode_link () $debug_cmd case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # what system we are compiling for in order to pass an extra @@ -6516,6 +6921,7 @@ func_mode_link () finalize_command=$nonopt compile_rpath= + compile_rpath_tail= finalize_rpath= compile_shlibpath= finalize_shlibpath= @@ -6556,10 +6962,12 @@ func_mode_link () xrpath= perm_rpath= temp_rpath= + temp_rpath_tail= thread_safe=no vinfo= vinfo_number=no weak_libs= + rpath_arg= single_module=$wl-single_module func_infer_tag $base_compile @@ -6611,9 +7019,9 @@ func_mode_link () while test "$#" -gt 0; do arg=$1 shift - func_quote_for_eval "$arg" - qarg=$func_quote_for_eval_unquoted_result - func_append libtool_args " $func_quote_for_eval_result" + func_quote_arg pretty,unquoted "$arg" + qarg=$func_quote_arg_unquoted_result + func_append libtool_args " $func_quote_arg_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then @@ -6822,7 +7230,7 @@ func_mode_link () case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) - func_fatal_error "only absolute run-paths are allowed" + func_fatal_error "argument to -rpath is not absolute: $arg" ;; esac if test rpath = "$prev"; then @@ -6849,6 +7257,13 @@ func_mode_link () prev= continue ;; + xassembler) + func_append compiler_flags " -Xassembler $qarg" + prev= + func_append compile_command " -Xassembler $qarg" + func_append finalize_command " -Xassembler $qarg" + continue + ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" @@ -6991,7 +7406,7 @@ func_mode_link () ;; esac case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; @@ -7011,7 +7426,7 @@ func_mode_link () -l*) if test X-lc = "X$arg" || test X-lm = "X$arg"; then case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; @@ -7019,7 +7434,7 @@ func_mode_link () # These systems don't actually have a C library (as such) test X-lc = "X$arg" && continue ;; - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-midnightbsd*) # Do not include libc due to us having libc/libc_r. test X-lc = "X$arg" && continue ;; @@ -7039,7 +7454,7 @@ func_mode_link () esac elif test X-lc_r = "X$arg"; then case $host in - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-midnightbsd*) # Do not include libc_r directly, use -pthread flag. continue ;; @@ -7062,16 +7477,29 @@ func_mode_link () # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. - -model|-arch|-isysroot|--sysroot) + # -q