diff --git a/.gitignore b/.gitignore index daab6b5d6..8884f267c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ build.mic* build.min* build.nasty* build.cov* +build.gcc* +build.clang* +build.icc* build.analyze* build-ci* compile_commands.json @@ -21,7 +24,7 @@ dash/include/dash/util/StaticConfig.h *.log *.out ipm/*/GEN.* -my.*.sh +my.* .syntastic* .clang* tags diff --git a/.syntastic_c b/.syntastic_c deleted file mode 100644 index 160629d1d..000000000 --- a/.syntastic_c +++ /dev/null @@ -1,11 +0,0 @@ --I./dart-impl/base/include --I./dart-impl/mpi/include --I./dart-impl/shmem/include --I./dart-if/v3.2/include --I/opt/openmpi-1.8/include --std=c99 --Wall --Wextra --pedantic --Wno-unused-function - diff --git a/.syntastic_cpp b/.syntastic_cpp deleted file mode 100644 index 3b82ce45e..000000000 --- a/.syntastic_cpp +++ /dev/null @@ -1,14 +0,0 @@ --I./dash/include --I./dart-impl/mpi/include --I./dart-impl/base/include --I./dart-if/v3.2/include --I/opt/openmpi-1.8/include --I/home/fuchst/opt/gtest/include --std=c++11 --Wall --Wextra --pedantic --Wno-unused-function --Wno-unused-variable --Wno-missing-braces - diff --git a/CMakeExt/CompilerFlags.cmake b/CMakeExt/CompilerFlags.cmake index 6c32a5c06..4377e55eb 100644 --- a/CMakeExt/CompilerFlags.cmake +++ b/CMakeExt/CompilerFlags.cmake @@ -5,6 +5,8 @@ # -rdynamic Instructs the linker to add all symbols, not only used ones, # to the dynamic symbol table +set(CMAKE_CXX_STANDARD ${DASH_CXX_STANDARD}) + find_package(OpenMP) @@ -62,6 +64,8 @@ if (ENABLE_DEV_COMPILER_WARNINGS "${DASH_DEVELOPER_CCXX_FLAGS} -Wunused -Wtrigraphs") set (DASH_DEVELOPER_CCXX_FLAGS "${DASH_DEVELOPER_CCXX_FLAGS} -Wdeprecated -Wno-float-equal") + set (DASH_DEVELOPER_CCXX_FLAGS + "${DASH_DEVELOPER_CCXX_FLAGS} -ftemplate-backtrace-limit=0") if (OPENMP_FOUND) set (DASH_DEVELOPER_CCXX_FLAGS @@ -154,6 +158,11 @@ endif() # Set C++ compiler flags: if ("${CMAKE_CXX_COMPILER_ID}" MATCHES ".*Clang") # using Clang + set (CXX_GDB_FLAG "-g" + CACHE STRING "C++ compiler (clang++) debug symbols flag") + set (CXX_OMP_FLAG ${OpenMP_CXX_FLAGS}) + set (CC_OMP_FLAG ${OpenMP_CC_FLAGS}) + set (CXX_STD_FLAG "--std=c++${DASH_CXX_STD_PREFERED}" CACHE STRING "C++ compiler std flag") @@ -163,9 +172,14 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES ".*Clang") elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") # using GCC + set (CXX_GDB_FLAG "-ggdb3 -rdynamic" + CACHE STRING "C++ compiler GDB debug symbols flag") + set (CXX_OMP_FLAG ${OpenMP_CXX_FLAGS}) + set (CC_OMP_FLAG ${OpenMP_CC_FLAGS}) + set (CXX_STD_FLAG "--std=c++${DASH_CXX_STD_PREFERED}" CACHE STRING "C++ compiler std flag") - set (CXX_GDB_FLAG "-ggdb3 -rdynamic") + if(ENABLE_LT_OPTIMIZATION) set (CXX_LTO_FLAG "-flto -fwhole-program -fno-use-linker-plugin") endif() @@ -176,8 +190,12 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel") # using Intel C++ + set (CXX_OMP_FLAG ${OpenMP_CXX_FLAGS}) + set (CC_OMP_FLAG ${OpenMP_CC_FLAGS}) + set (CXX_STD_FLAG "-std=c++${DASH_CXX_STD_PREFERED}" CACHE STRING "C++ compiler std flag") + if(ENABLE_LT_OPTIMIZATION) set (CXX_LTO_FLAG "-ipo") endif() @@ -185,16 +203,15 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel") set (CC_REPORT_FLAG "-qopt-report=4 -qopt-report-phase ipo") endif() - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "15.0.0") message(FATAL_ERROR "Insufficient Intel compiler version (< 15.0.0)") endif() elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Cray") # Cray compiler not supported for C++ - message(FATAL_ERROR, - "Cray compiler does not support C++11 features and is only " - "eligible for building DART.") + message(WARNING, + "Cray compiler does not support C++11/14 features and is " + "only eligible for building DART.") endif() set (CC_GDB_FLAG "-g" diff --git a/CMakeLists.txt b/CMakeLists.txt index 08aa98a3e..a8b5009cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,8 @@ if(POLICY CMP0016) cmake_policy(SET CMP0016 OLD) endif(POLICY CMP0016) if(POLICY CMP0058) - cmake_policy(SET CMP0058 NEW) -endif() + cmake_policy(SET CMP0058 OLD) +endif(POLICY CMP0058) if("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") set(DEFAULT_COMPTIME_RED on) @@ -34,6 +34,9 @@ else() endif() ## Build options +set(DASH_CXX_STANDARD "14" + CACHE STRING "C++ standard version for DASH") + option(BUILD_TESTS "Whether tests should be built" on) option(INSTALL_TESTS @@ -122,14 +125,6 @@ include(${CMAKE_SOURCE_DIR}/CMakeExt/Platform.cmake) include(${CMAKE_SOURCE_DIR}/CMakeExt/Environment.cmake) include(${CMAKE_SOURCE_DIR}/CMakeExt/StdLib.cmake) -if (ENABLE_THREADSUPPORT) - include(${CMAKE_SOURCE_DIR}/CMakeExt/Threading.cmake) -endif() - -if (ENABLE_COMPTIME_RED) - include(${CMAKE_SOURCE_DIR}/CMakeExt/cotire.cmake) -endif() - # Load build modules to locate libraries after environment setup # has been loaded: include(${CMAKE_SOURCE_DIR}/CMakeExt/MPI.cmake) @@ -218,6 +213,14 @@ set(DASH_DART_BASE_INCLUDE_DIR ## Set compiler flags (depend on CMake options) include(${CMAKE_SOURCE_DIR}/CMakeExt/CompilerFlags.cmake) +if (ENABLE_THREADSUPPORT) + include(${CMAKE_SOURCE_DIR}/CMakeExt/Threading.cmake) +endif() + +if (ENABLE_COMPTIME_RED) + include(${CMAKE_SOURCE_DIR}/CMakeExt/cotire.cmake) +endif() + ## Build results output directories (/bin, /lib, /doc) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin) @@ -245,10 +248,19 @@ message(EMPH "Install prefix: (INSTALL_PREFIX) " ${CMAKE_INSTALL_PREFIX}) message(EMPH "Build type: (CMAKE_BUILD_TYPE) " ${CMAKE_BUILD_TYPE}) +message(EMPH "C compiler: (CMAKE_C_COMPILER) " + ${CMAKE_C_COMPILER_ID}) +message(EMPH "C++ compiler: (CMAKE_CXX_COMPILER) " + ${CMAKE_CXX_COMPILER_ID}) +message(EMPH "C++ standard version: (DASH_CXX_STANDARD) " + ${CMAKE_CXX_STANDARD}) message(EMPH "Generic build: (BUILD_GENERIC) " ${BUILD_GENERIC}) message(EMPH "Build shared libraries: (BUILD_SHARED_LIBS) " ${BUILD_SHARED_LIBS}) +if (MPI_FOUND) + message(EMPH "MPI implementation: " ${MPI_IMPL_ID}) +endif() message(INFO "Build tests: (BUILD_TESTS) " ${BUILD_TESTS}) @@ -305,12 +317,15 @@ message(INFO "HDF5 support: (ENABLE_HDF5) " ${ENABLE_HDF5}) message(INFO "Enabled DART backends: (DART_IMPLEMENTATIONS) " ${DART_IMPLEMENTATIONS}) + + message(INFO "C compiler id: ${CMAKE_C_COMPILER_ID}") message(INFO "C++ compiler id: ${CMAKE_CXX_COMPILER_ID}") if (DEFINED MPI_IMPL_ID) message(INFO "MPI implementation: " ${MPI_IMPL_ID}) endif() + if (ENABLE_PAPI) if (PAPI_FOUND) message(INFO "PAPI enabled") diff --git a/build.analyze.sh b/build-tools/build.analyze.sh similarity index 80% rename from build.analyze.sh rename to build-tools/build.analyze.sh index f5ba3d8da..eed8fff61 100755 --- a/build.analyze.sh +++ b/build-tools/build.analyze.sh @@ -1,4 +1,7 @@ #!/bin/sh + +if ! [ -z ${SOURCING+x} ]; then + # This script runs scan-build to perform a static code analysis # https://clang-analyzer.llvm.org/scan-build.html # @@ -6,12 +9,6 @@ # export CCC_CC=clang-3.8 # export CCC_CXX=clang++3.8 -BUILD_DIR=./build.analyze -REPORT_DIR=report # relative to BUILD_DIR -BUILD_WRAPPER="${SCANBUILD_BIN}"; - - - ## !! NOTE !! # # See documentation of scan-build for details on recommended build @@ -21,44 +18,6 @@ BUILD_WRAPPER="${SCANBUILD_BIN}"; # ## - - -# try to find build wrapper -if [ "$BUILD_WRAPPER" = "" ]; then - BUILD_WRAPPER="scan-build" -fi -if [ "$SCANBUILD_OPTS" = "" ]; then - SCANBUILD_OPTS="-analyze-headers -plist-html" -fi -SCANBUILD_OPTS="-o $REPORT_DIR ${SCANBUILD_OPTS}" -SCANBUILD_OPTS="--force-analyze-debug-code -v ${SCANBUILD_OPTS}" - -which $BUILD_WRAPPER || - (echo "This build requires $BUILD_WRAPPER. Set env. var SCANBUILD_BIN" \ - & exit 1); - -FORCE_BUILD=false -if [ "$1" = "-f" ]; then - FORCE_BUILD=true -fi - -await_confirm() { - if ! $FORCE_BUILD; then - echo "" - echo " To build and analyze using these settings, hit ENTER" - read confirm - fi -} - -exit_message() { - echo "--------------------------------------------------------" - echo "Done. To install DASH, run make install in $BUILD_DIR" -} - -if [ "${PAPI_HOME}" = "" ]; then - PAPI_HOME=$PAPI_BASE -fi - # To specify a build configuration for a specific system, use: # # -DENVIRONMENT_TYPE= \ @@ -86,11 +45,30 @@ fi # For likwid support, ensure that the likwid development headers are # installed. -# Configure with default release build settings: -rm -Rf $BUILD_DIR/* -mkdir -p $BUILD_DIR/$REPORT_DIR -(cd $BUILD_DIR && $BUILD_WRAPPER $SCANBUILD_OPTS \ - cmake3 -DCMAKE_BUILD_TYPE=Debug \ + +BUILD_DIR=build.analyze +REPORT_DIR=report # relative to BUILD_DIR +BUILD_WRAPPER="${SCANBUILD_BIN}"; + +# try to find build wrapper +if [ "$BUILD_WRAPPER" = "" ]; then + BUILD_WRAPPER="scan-build" +fi +if [ "$SCANBUILD_OPTS" = "" ]; then + SCANBUILD_OPTS="-analyze-headers -plist-html" +fi +SCANBUILD_OPTS="-o $REPORT_DIR ${SCANBUILD_OPTS}" +SCANBUILD_OPTS="--force-analyze-debug-code -v ${SCANBUILD_OPTS}" + +which $BUILD_WRAPPER || + (echo "This build requires $BUILD_WRAPPER. Set env. var SCANBUILD_BIN" \ + & exit 1); + +# custom cmake command +CMAKE_COMMAND="$BUILD_WRAPPER $SCANBUILD_OPTS cmake3" + +# default release build settings: +CMAKE_OPTIONS=" -DCMAKE_BUILD_TYPE=Debug \ -DENVIRONMENT_TYPE=default \ -DENABLE_COMPTIME_RED=OFF \ \ @@ -130,10 +108,14 @@ mkdir -p $BUILD_DIR/$REPORT_DIR -DIPM_PREFIX=${IPM_HOME} \ -DPAPI_PREFIX=${PAPI_HOME} \ \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ - ../ && \ - await_confirm && \ - $BUILD_WRAPPER $SCANBUILD_OPTS make) && \ - (cp $BUILD_DIR/compile_commands.json .) && \ -exit_message + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" + +# the make command used +MAKE_COMMAND="$BUILD_WRAPPER $SCANBUILD_OPTS make" + +else + + $(dirname $0)/build.sh analyze $@ + +fi diff --git a/build.cov.sh b/build-tools/build.cov.sh similarity index 77% rename from build.cov.sh rename to build-tools/build.cov.sh index 19c72ed04..2337114e9 100755 --- a/build.cov.sh +++ b/build-tools/build.cov.sh @@ -1,28 +1,6 @@ #!/bin/sh -BUILD_DIR=./build.cov - -FORCE_BUILD=false -if [ "$1" = "-f" ]; then - FORCE_BUILD=true -fi - -await_confirm() { - if ! $FORCE_BUILD; then - echo "" - echo " To build using these settings, hit ENTER" - read confirm - fi -} - -exit_message() { - echo "--------------------------------------------------------" - echo "Done. To run code coverage measurement, run make coverage in $BUILD_DIR" -} - -if [ "${PAPI_HOME}" = "" ]; then - PAPI_HOME=$PAPI_BASE -fi +if ! [ -z ${SOURCING+x} ]; then # To specify a build configuration for a specific system, use: # @@ -51,10 +29,14 @@ fi # For likwid support, ensure that the likwid development headers are # installed. -# Configure with default release build settings: -mkdir -p $BUILD_DIR -rm -Rf $BUILD_DIR/* -(cd $BUILD_DIR && cmake -DCMAKE_BUILD_TYPE=Debug \ +# relative to $ROOTDIR of dash +BUILD_DIR=$DASHDIR/build.cov + +# custom cmake command +CMAKE_COMMAND="cmake" + +# default release build settings: +CMAKE_OPTIONS=" -DCMAKE_BUILD_TYPE=Debug \ -DENVIRONMENT_TYPE=default \ -DINSTALL_PREFIX=$HOME/opt/dash-0.3.0/ \ -DDART_IMPLEMENTATIONS=mpi \ @@ -89,8 +71,14 @@ rm -Rf $BUILD_DIR/* -DBUILD_DOCS=OFF \ \ -DIPM_PREFIX=${IPM_HOME} \ - -DPAPI_PREFIX=${PAPI_HOME} \ - ../ && \ - await_confirm && \ - make -j 4) && \ -exit_message + -DPAPI_PREFIX=${PAPI_HOME}" + +# the mak e command used +MAKE_COMMAND="make -j 4" + +else + + $(dirname $0)/build.sh cov $@ + +fi + diff --git a/build.debug.sh b/build-tools/build.debug.sh similarity index 77% rename from build.debug.sh rename to build-tools/build.debug.sh index 3a737a295..c706d4201 100755 --- a/build.debug.sh +++ b/build-tools/build.debug.sh @@ -1,28 +1,6 @@ #!/bin/sh -BUILD_DIR=./build.dev - -FORCE_BUILD=false -if [ "$1" = "-f" ]; then - FORCE_BUILD=true -fi - -await_confirm() { - if ! $FORCE_BUILD; then - echo "" - echo " To build using these settings, hit ENTER" - read confirm - fi -} - -exit_message() { - echo "--------------------------------------------------------" - echo "Done. To install DASH, run make install in $BUILD_DIR" -} - -if [ "${PAPI_HOME}" = "" ]; then - PAPI_HOME=$PAPI_BASE -fi +if ! [ -z ${SOURCING+x} ]; then # To specify a build configuration for a specific system, use: # @@ -53,10 +31,14 @@ fi # For likwid support, ensure that the likwid development headers are # installed. -# Configure with default debug build settings: -mkdir -p $BUILD_DIR -rm -Rf $BUILD_DIR/* -(cd $BUILD_DIR && cmake -DCMAKE_BUILD_TYPE=Debug \ +# relative to $ROOTDIR of dash +BUILD_DIR=build.dev + +# custom cmake command +CMAKE_COMMAND="cmake" + +# default debug build settings: +CMAKE_OPTIONS=" -DCMAKE_BUILD_TYPE=Debug \ -DENVIRONMENT_TYPE=default \ -DINSTALL_PREFIX=$HOME/opt/dash-0.3.0-dev/ \ -DDART_IMPLEMENTATIONS=mpi \ @@ -93,9 +75,14 @@ rm -Rf $BUILD_DIR/* -DIPM_PREFIX=${IPM_HOME} \ -DPAPI_PREFIX=${PAPI_HOME} \ \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ - ../ && \ - await_confirm && \ - make -j 4) && (cp $BUILD_DIR/compile_commands.json .) && \ -exit_message + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" + +# the make command used +MAKE_COMMAND="make -j 4" + +else + + $(dirname $0)/build.sh debug $@ + +fi diff --git a/build-tools/build.default.sh b/build-tools/build.default.sh new file mode 100755 index 000000000..6e3d7575a --- /dev/null +++ b/build-tools/build.default.sh @@ -0,0 +1,88 @@ +#!/bin/sh + +if ! [ -z ${SOURCING+x} ]; then + +# To specify a build configuration for a specific system, use: +# +# -DENVIRONMENT_TYPE= \ +# +# For available types, see the files in folder ./config. +# To specify a custom build configuration, use: +# +# -DENVIRONMENT_CONFIG_PATH= \ +# + +# To use an existing installation of gtest instead of downloading the sources +# from the google test subversion repository, use: +# +# -DGTEST_LIBRARY_PATH=${HOME}/gtest \ +# -DGTEST_INCLUDE_PATH=${HOME}/gtest/include \ +# + +# To build with MKL support, set environment variables MKLROOT and INTELROOT. +# + +# To enable IPM runtime support, use: +# +# -DIPM_PREFIX= \ + +# For likwid support, ensure that the likwid development headers are +# installed. + +# relative to $ROOTDIR of dash +BUILD_DIR=build + +# custom cmake command +CMAKE_COMMAND="cmake" + +# default release build settings: +CMAKE_OPTIONS=" -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_GENERIC=OFF \ + -DENVIRONMENT_TYPE=default \ + -DINSTALL_PREFIX=$HOME/opt/dash-0.3.0/ \ + -DDART_IMPLEMENTATIONS=mpi \ + -DENABLE_THREADSUPPORT=ON \ + -DENABLE_DEV_COMPILER_WARNINGS=OFF \ + -DENABLE_EXT_COMPILER_WARNINGS=OFF \ + -DENABLE_LT_OPTIMIZATION=OFF \ + -DENABLE_ASSERTIONS=ON \ + \ + -DENABLE_SHARED_WINDOWS=ON \ + -DENABLE_DYNAMIC_WINDOWS=ON \ + -DENABLE_UNIFIED_MEMORY_MODEL=ON \ + -DENABLE_DEFAULT_INDEX_TYPE_LONG=ON \ + \ + -DENABLE_LOGGING=OFF \ + -DENABLE_TRACE_LOGGING=OFF \ + -DENABLE_DART_LOGGING=OFF \ + \ + -DENABLE_LIBNUMA=ON \ + -DENABLE_LIKWID=OFF \ + -DENABLE_HWLOC=ON \ + -DENABLE_PAPI=ON \ + -DENABLE_MKL=ON \ + -DENABLE_BLAS=ON \ + -DENABLE_LAPACK=ON \ + -DENABLE_SCALAPACK=ON \ + -DENABLE_PLASMA=ON \ + -DENABLE_HDF5=ON \ + \ + -DBUILD_EXAMPLES=ON \ + -DBUILD_TESTS=ON \ + -DBUILD_DOCS=ON \ + \ + -DIPM_PREFIX=${IPM_HOME} \ + -DPAPI_PREFIX=${PAPI_HOME} \ + \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" + +# the make command used +MAKE_COMMAND="make -j 4" + +else + + $(dirname $0)/build.sh $@ + +fi + diff --git a/build.dev.sh b/build-tools/build.dev.sh similarity index 77% rename from build.dev.sh rename to build-tools/build.dev.sh index 1d793d56f..f4df6291e 100755 --- a/build.dev.sh +++ b/build-tools/build.dev.sh @@ -1,28 +1,6 @@ #!/bin/sh -BUILD_DIR=./build.dev - -FORCE_BUILD=false -if [ "$1" = "-f" ]; then - FORCE_BUILD=true -fi - -await_confirm() { - if ! $FORCE_BUILD; then - echo "" - echo " To build using these settings, hit ENTER" - read confirm - fi -} - -exit_message() { - echo "--------------------------------------------------------" - echo "Done. To install DASH, run make install in $BUILD_DIR" -} - -if [ "${PAPI_HOME}" = "" ]; then - PAPI_HOME=$PAPI_BASE -fi +if ! [ -z ${SOURCING+x} ]; then # To specify a build configuration for a specific system, use: # @@ -53,10 +31,14 @@ fi # For likwid support, ensure that the likwid development headers are # installed. -# Configure with default developer build settings: -mkdir -p $BUILD_DIR -rm -Rf $BUILD_DIR/* -(cd $BUILD_DIR && cmake -DCMAKE_BUILD_TYPE=Debug \ +# relative to $ROOTDIR of dash +BUILD_DIR=build.dev + +# custom cmake command +CMAKE_COMMAND="cmake" + +# default developer build settings: +CMAKE_OPTIONS=" -DCMAKE_BUILD_TYPE=Debug \ -DENVIRONMENT_TYPE=default \ -DINSTALL_PREFIX=$HOME/opt/dash-0.3.0-dev/ \ -DDART_IMPLEMENTATIONS=mpi \ @@ -93,9 +75,14 @@ rm -Rf $BUILD_DIR/* -DIPM_PREFIX=${IPM_HOME} \ -DPAPI_PREFIX=${PAPI_HOME} \ \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ - ../ && \ - await_confirm && \ - make -j 4) && (cp $BUILD_DIR/compile_commands.json .) && \ -exit_message + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" + +# the make command used +MAKE_COMMAND="make -j 4" + +else + + $(dirname $0)/build.sh dev $@ + +fi diff --git a/build.mic.sh b/build-tools/build.mic.sh similarity index 76% rename from build.mic.sh rename to build-tools/build.mic.sh index 0ed0ab666..cde5c8a21 100755 --- a/build.mic.sh +++ b/build-tools/build.mic.sh @@ -1,28 +1,6 @@ #!/bin/sh -BUILD_DIR=./build.mic - -FORCE_BUILD=false -if [ "$1" = "-f" ]; then - FORCE_BUILD=true -fi - -await_confirm() { - if ! $FORCE_BUILD; then - echo "" - echo " To build using these settings, hit ENTER" - read confirm - fi -} - -exit_message() { - echo "------------------------------------------------------------" - echo "Done. To install DASH, run make install in $BUILD_DIR" -} - -if [ "${PAPI_HOME}" = "" ]; then - PAPI_HOME=$PAPI_BASE -fi +if ! [ -z ${SOURCING+x} ]; then # To use an existing installation of gtest instead of downloading the sources # from the google test subversion repository, use: @@ -41,10 +19,14 @@ fi # To build with MKL support, set environment variables MKLROOT and INTELROOT. -# Configure with default release build settings: -mkdir -p $BUILD_DIR -rm -Rf $BUILD_DIR/* -(cd $BUILD_DIR && cmake -DCMAKE_BUILD_TYPE=Release \ +# relative to $ROOTDIR of dash +BUILD_DIR=build.mic + +# custom cmake command +CMAKE_COMMAND="cmake" + +# default release build settings for supermic environment: +CMAKE_OPTIONS=" -DCMAKE_BUILD_TYPE=Release \ -DENVIRONMENT_TYPE=supermic \ -DCMAKE_C_COMPILER=mpiicc \ -DCMAKE_CXX_COMPILER=mpiicc \ @@ -80,8 +62,14 @@ rm -Rf $BUILD_DIR/* -DBUILD_DOCS=OFF \ \ -DPAPI_PREFIX=${PAPI_HOME} \ - -DIPM_PREFIX=${IPM_BASE} \ - ../ && \ - await_confirm && \ - make -j 5) && \ -exit_message + -DIPM_PREFIX=${IPM_BASE}" + +# the make command used +MAKE_COMMAND="make -j 5" + +else + + $(dirname $0)/build.sh mic $@ + +fi + diff --git a/build.minimal.sh b/build-tools/build.minimal.sh similarity index 76% rename from build.minimal.sh rename to build-tools/build.minimal.sh index 90f5ae48c..9c4d6f34d 100755 --- a/build.minimal.sh +++ b/build-tools/build.minimal.sh @@ -1,28 +1,6 @@ #!/bin/sh -BUILD_DIR=./build - -FORCE_BUILD=false -if [ "$1" = "-f" ]; then - FORCE_BUILD=true -fi - -await_confirm() { - if ! $FORCE_BUILD; then - echo "" - echo " To build using these settings, hit ENTER" - read confirm - fi -} - -exit_message() { - echo "--------------------------------------------------------" - echo "Done. To install DASH, run make install in $BUILD_DIR" -} - -if [ "${PAPI_HOME}" = "" ]; then - PAPI_HOME=$PAPI_BASE -fi +if ! [ -z ${SOURCING+x} ]; then # To specify a build configuration for a specific system, use: # @@ -45,10 +23,14 @@ fi # # -DIPM_PREFIX= \ -# Configure with default release build settings: -mkdir -p $BUILD_DIR -rm -Rf $BUILD_DIR/* -(cd $BUILD_DIR && cmake -DCMAKE_BUILD_TYPE=Release \ +# relative to $ROOTDIR of dash +BUILD_DIR=build + +# custom cmake command +CMAKE_COMMAND="cmake" + +# minimal release build settings: +CMAKE_OPTIONS=" -DCMAKE_BUILD_TYPE=Release \ -DENVIRONMENT_TYPE=default \ -DINSTALL_PREFIX=$HOME/opt/dash-0.3.0/ \ -DDART_IMPLEMENTATIONS=mpi \ @@ -85,8 +67,14 @@ rm -Rf $BUILD_DIR/* -DIPM_PREFIX=${IPM_HOME} \ -DPAPI_PREFIX=${PAPI_HOME} \ \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ - ../ && \ - await_confirm && \ - make -j 4) && (cp $BUILD_DIR/compile_commands.json .) && \ -exit_message + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" + +# the make command used +MAKE_COMMAND="make -j 4" + +else + + $(dirname $0)/build.sh minimal $@ + +fi + diff --git a/build.nasty.sh b/build-tools/build.nasty.sh similarity index 78% rename from build.nasty.sh rename to build-tools/build.nasty.sh index 81cbb9b58..90f70d832 100755 --- a/build.nasty.sh +++ b/build-tools/build.nasty.sh @@ -1,28 +1,6 @@ #!/bin/sh -BUILD_DIR=./build.nasty - -FORCE_BUILD=false -if [ "$1" = "-f" ]; then - FORCE_BUILD=true -fi - -await_confirm() { - if ! $FORCE_BUILD; then - echo "" - echo " To build using these settings, hit ENTER" - read confirm - fi -} - -exit_message() { - echo "--------------------------------------------------------" - echo "Done. To install DASH, run make install in $BUILD_DIR" -} - -if [ "${PAPI_HOME}" = "" ]; then - PAPI_HOME=$PAPI_BASE -fi +if ! [ -z ${SOURCING+x} ]; then # To specify a build configuration for a specific system, use: # @@ -58,10 +36,14 @@ fi # # !!!!!!!!!!!!!!!!!!!!! DO NOT ENABLE IN PRODUCTION !!!!!!!!!!!!!!!!!!!!!!!! -# Configure with default release build settings: -mkdir -p $BUILD_DIR -rm -Rf $BUILD_DIR/* -(cd $BUILD_DIR && cmake -DCMAKE_BUILD_TYPE=Release \ +# relative to $ROOTDIR of dash +BUILD_DIR=build.nasty + +# custom cmake command +CMAKE_COMMAND="cmake" + +# default release build settings with nasty mpi: +CMAKE_OPTIONS=" -DCMAKE_BUILD_TYPE=Release \ -DENVIRONMENT_TYPE=default \ -DINSTALL_PREFIX=$HOME/opt/dash-0.3.0-nasty \ -DDART_IMPLEMENTATIONS=mpi \ @@ -100,9 +82,14 @@ rm -Rf $BUILD_DIR/* -DIPM_PREFIX=${IPM_HOME} \ -DPAPI_PREFIX=${PAPI_HOME} \ \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ - ../ && \ - await_confirm && \ - make -j 4) && (cp $BUILD_DIR/compile_commands.json .) && \ -exit_message + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" + +# the make command used +MAKE_COMMAND="make -j 4" + +else + + $(dirname $0)/build.sh nasty $@ + +fi diff --git a/build-tools/build.sh b/build-tools/build.sh new file mode 100755 index 000000000..f36d20bd3 --- /dev/null +++ b/build-tools/build.sh @@ -0,0 +1,75 @@ +#!/bin/sh + +# traverse symlinks of the script and find the original scriptdir +find_scriptdir() { + ( + SCRIPT=$1 + while [ -h $SCRIPT ] + do + BASE=$(dirname $SCRIPT) + SCRIPT=$(readlink $SCRIPT) + cd $BASE + done + + cd $(dirname $SCRIPT) && pwd -P + ) +} + +# find the root of the project +# when given the scriptdir as parameter +find_rootdir() { + ( cd $1/.. && pwd -P ) +} + +await_confirm() { + if ! $FORCE_BUILD; then + echo "" + echo " To build using these settings, hit ENTER" + read confirm + fi +} + +exit_message() { + echo "--------------------------------------------------------" + echo "Done. To install DASH, run make install in $BUILD_DIR" +} + +SCRIPTDIR=$(find_scriptdir $0) +ROOTDIR=$(find_rootdir $SCRIPTDIR) + +SOURCING=true +# load default options +. $SCRIPTDIR/build.default.sh + +FORCE_BUILD=false +# go through parameters +while [ $# -gt 0 ]; do + if [ "$1" = "-f" ]; then + FORCE_BUILD=true + fi + + # load options from seperate file(s) + if [ -x $SCRIPTDIR/build.$1.sh ]; then + . $SCRIPTDIR/build.$1.sh + fi + if [ -x $SCRIPTDIR/my.build.$1.sh ]; then + . $SCRIPTDIR/my.build.$1.sh + fi + + shift +done + + +if [ "${PAPI_HOME}" = "" ]; then + PAPI_HOME=$PAPI_BASE +fi + +# Configure with build settings loaded previously: +mkdir -p $ROOTDIR/$BUILD_DIR +rm -Rf $ROOTDIR/$BUILD_DIR/* +(cd $ROOTDIR/$BUILD_DIR && $CMAKE_COMMAND $CMAKE_OPTIONS \ + $ROOTDIR && \ + await_confirm && \ + $MAKE_COMMAND) && \ +exit_message + diff --git a/build.sh b/build.sh deleted file mode 100755 index 06355aef2..000000000 --- a/build.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/sh - -BUILD_DIR=./build - -FORCE_BUILD=false -if [ "$1" = "-f" ]; then - FORCE_BUILD=true -fi - -await_confirm() { - if ! $FORCE_BUILD; then - echo "" - echo " To build using these settings, hit ENTER" - read confirm - fi -} - -exit_message() { - echo "--------------------------------------------------------" - echo "Done. To install DASH, run make install in $BUILD_DIR" -} - -if [ "${PAPI_HOME}" = "" ]; then - PAPI_HOME=$PAPI_BASE -fi - -# To specify a build configuration for a specific system, use: -# -# -DENVIRONMENT_TYPE= \ -# -# For available types, see the files in folder ./config. -# To specify a custom build configuration, use: -# -# -DENVIRONMENT_CONFIG_PATH= \ -# - -# To use an existing installation of gtest instead of downloading the sources -# from the google test subversion repository, use: -# -# -DGTEST_LIBRARY_PATH=${HOME}/gtest \ -# -DGTEST_INCLUDE_PATH=${HOME}/gtest/include \ -# - -# To build with MKL support, set environment variables MKLROOT and INTELROOT. -# - -# To enable IPM runtime support, use: -# -# -DIPM_PREFIX= \ - -# For likwid support, ensure that the likwid development headers are -# installed. - -# Configure with default release build settings: -mkdir -p $BUILD_DIR -rm -Rf $BUILD_DIR/* -(cd $BUILD_DIR && cmake -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_SHARED_LIBS=OFF \ - -DBUILD_GENERIC=OFF \ - -DENVIRONMENT_TYPE=default \ - -DINSTALL_PREFIX=$HOME/opt/dash-0.3.0/ \ - -DDART_IMPLEMENTATIONS=mpi \ - -DENABLE_THREADSUPPORT=ON \ - -DENABLE_DEV_COMPILER_WARNINGS=OFF \ - -DENABLE_EXT_COMPILER_WARNINGS=OFF \ - -DENABLE_LT_OPTIMIZATION=OFF \ - -DENABLE_ASSERTIONS=ON \ - \ - -DENABLE_SHARED_WINDOWS=ON \ - -DENABLE_DYNAMIC_WINDOWS=ON \ - -DENABLE_UNIFIED_MEMORY_MODEL=ON \ - -DENABLE_DEFAULT_INDEX_TYPE_LONG=ON \ - \ - -DENABLE_LOGGING=OFF \ - -DENABLE_TRACE_LOGGING=OFF \ - -DENABLE_DART_LOGGING=OFF \ - \ - -DENABLE_LIBNUMA=ON \ - -DENABLE_LIKWID=OFF \ - -DENABLE_HWLOC=ON \ - -DENABLE_PAPI=ON \ - -DENABLE_MKL=ON \ - -DENABLE_BLAS=ON \ - -DENABLE_LAPACK=ON \ - -DENABLE_SCALAPACK=ON \ - -DENABLE_PLASMA=ON \ - -DENABLE_HDF5=ON \ - \ - -DBUILD_EXAMPLES=ON \ - -DBUILD_TESTS=ON \ - -DBUILD_DOCS=ON \ - \ - -DIPM_PREFIX=${IPM_HOME} \ - -DPAPI_PREFIX=${PAPI_HOME} \ - \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ - ../ && \ - await_confirm && \ - make -j 4) && (cp $BUILD_DIR/compile_commands.json .) && \ -exit_message - diff --git a/build.sh b/build.sh new file mode 120000 index 000000000..1aee1d51f --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +build-tools/build.sh \ No newline at end of file diff --git a/config/supermic.cmake b/config/supermic.cmake index caa7db4b5..f7fd151cd 100644 --- a/config/supermic.cmake +++ b/config/supermic.cmake @@ -6,7 +6,7 @@ # export CC=`which mpiicc` # export CXX=`which mpiicc` # -set(ENV{CXX} mpiicc) +set(ENV{CXX} mpiicpc) set(ENV{CC} mpiicc) set(DASH_ENV_HOST_SYSTEM_ID "supermic" CACHE STRING @@ -21,11 +21,13 @@ set(CC_ENV_SETUP_FLAGS "${CC_ENV_SETUP_FLAGS} -qopenmp -mmic -mkl") set(CC_ENV_SETUP_FLAGS "${CC_ENV_SETUP_FLAGS} -mt_mpi") set(CC_ENV_SETUP_FLAGS "${CC_ENV_SETUP_FLAGS} -qopt-streaming-stores always") set(CC_ENV_SETUP_FLAGS "${CC_ENV_SETUP_FLAGS} -qopt-prefetch-distance=64,8") +set(CC_ENV_SETUP_FLAGS "${CC_ENV_SETUP_FLAGS} -Wl,-rpath,$ENV{MIC_LD_LIBRARY_PATH}") set(CXX_ENV_SETUP_FLAGS "${CXX_ENV_SETUP_FLAGS} -qopenmp -mmic -mkl") set(CXX_ENV_SETUP_FLAGS "${CXX_ENV_SETUP_FLAGS} -mt_mpi") set(CXX_ENV_SETUP_FLAGS "${CXX_ENV_SETUP_FLAGS} -qopt-streaming-stores always") set(CXX_ENV_SETUP_FLAGS "${CXX_ENV_SETUP_FLAGS} -qopt-prefetch-distance=64,8") +set(CXX_ENV_SETUP_FLAGS "${CXX_ENV_SETUP_FLAGS} -Wl,-rpath,$ENV{MIC_LD_LIBRARY_PATH}") set(MKLROOT $ENV{MKLROOT}) diff --git a/config/supermuc.cmake b/config/supermuc.cmake index 8c055b82d..c5db7839c 100644 --- a/config/supermuc.cmake +++ b/config/supermuc.cmake @@ -6,7 +6,7 @@ # export CC=`which icc` # export CXX=`which icc` # -set(ENV{CXX} mpiicc) +set(ENV{CXX} mpiicpc) set(ENV{CC} mpiicc) set(DASH_ENV_HOST_SYSTEM_ID "supermuc" CACHE STRING diff --git a/dart-impl/base/CMakeLists.txt b/dart-impl/base/CMakeLists.txt index 9166ee745..a94c1130b 100644 --- a/dart-impl/base/CMakeLists.txt +++ b/dart-impl/base/CMakeLists.txt @@ -9,6 +9,8 @@ file(GLOB_RECURSE DASH_DART_BASE_HEADERS "include/*.h") set(DASH_DART_IF_INCLUDE_DIR ${DASH_DART_IF_INCLUDE_DIR} PARENT_SCOPE) +set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS} + PARENT_SCOPE) set(ENABLE_DART_LOGGING ${ENABLE_DART_LOGGING} PARENT_SCOPE) set(ENABLE_UNIFIED_MEMORY_MODEL ${ENABLE_UNIFIED_MEMORY_MODEL} @@ -107,6 +109,13 @@ add_library( ${DASH_DART_BASE_SOURCES} # sources ${DASH_DART_BASE_HEADERS} # headers ) +if (${BUILD_SHARED_LIBS}) + add_library( + ${DASH_DART_BASE_LIBRARY} SHARED # library name + ${DASH_DART_BASE_SOURCES} # sources + ${DASH_DART_BASE_HEADERS} # headers + ) +endif() # Link dependencies target_link_libraries( diff --git a/dart-impl/mpi/CMakeLists.txt b/dart-impl/mpi/CMakeLists.txt index a4d3db993..dbb78615c 100644 --- a/dart-impl/mpi/CMakeLists.txt +++ b/dart-impl/mpi/CMakeLists.txt @@ -19,6 +19,8 @@ file(GLOB_RECURSE DASH_DART_IMPL_MPI_HEADERS "include/*.h") # Load global build settings set(DASH_DART_IF_INCLUDE_DIR ${DASH_DART_IF_INCLUDE_DIR} PARENT_SCOPE) +set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS} + PARENT_SCOPE) set(ENABLE_DART_LOGGING ${ENABLE_DART_LOGGING} PARENT_SCOPE) set(ENABLE_UNIFIED_MEMORY_MODEL ${ENABLE_UNIFIED_MEMORY_MODEL} @@ -195,6 +197,13 @@ add_library( ${DASH_DART_IMPL_MPI_SOURCES} # sources ${DASH_DART_IMPL_MPI_HEADERS} # headers ) +if (${BUILD_SHARED_LIBS}) + add_library( + ${DASH_DART_IMPL_MPI_LIBRARY} SHARED # library name + ${DASH_DART_IMPL_MPI_SOURCES} # sources + ${DASH_DART_IMPL_MPI_HEADERS} # headers + ) +endif() # Link dependencies target_link_libraries( ${DASH_DART_IMPL_MPI_LIBRARY} diff --git a/dart-impl/mpi/src/dart_communication.c b/dart-impl/mpi/src/dart_communication.c index bc61cf434..c15ba23c4 100644 --- a/dart-impl/mpi/src/dart_communication.c +++ b/dart-impl/mpi/src/dart_communication.c @@ -1374,7 +1374,7 @@ dart_ret_t dart_wait( if (handle->num_reqs > 0) { DART_LOG_DEBUG("dart_wait: -- MPI_Wait"); CHECK_MPI_RET( - MPI_Waitall(handle->num_reqs, handle->reqs, MPI_STATUSES_IGNORE), + MPI_Waitall(handle->num_reqs, handle->reqs, MPI_STATUS_IGNORE), "MPI_Waitall"); if (handle->needs_flush) { @@ -1415,8 +1415,8 @@ dart_ret_t dart_waitall_local( if (handles[i] != DART_HANDLE_NULL) { for (uint8_t j = 0; j < handles[i]->num_reqs; ++j) { if (handles[i]->reqs[j] != MPI_REQUEST_NULL){ - DART_LOG_TRACE("dart_waitall_local: -- handle[%"PRIu64"]: %p)", - i, (void*)handles[i]->reqs[j]); + DART_LOG_TRACE("dart_waitall_local: -- handle[%"PRIu64"]: 0x%x)", + i, handles[i]->reqs[j]); DART_LOG_TRACE("dart_waitall_local: handle[%"PRIu64"]->dest: %d", i, handles[i]->dest); mpi_req[r_n] = handles[i]->reqs[j]; @@ -1512,9 +1512,9 @@ dart_ret_t dart_waitall( if (handles[i] != DART_HANDLE_NULL) { for (uint8_t j = 0; j < handles[i]->num_reqs; ++j) { if (handles[i]->reqs[j] != MPI_REQUEST_NULL){ - DART_LOG_DEBUG("dart_waitall: -- handle[%zu](%p): " + DART_LOG_DEBUG("dart_waitall: -- handle[%zu](0x%x): " "dest:%d win:%"PRIu64, - i, (void*)handles[i]->reqs[0], + i, handles[i]->reqs[0], handles[i]->dest, (unsigned long)handles[i]->win); mpi_req[r_n] = handles[i]->reqs[j]; diff --git a/dash/examples/bench.05.array-range/main.cpp b/dash/examples/bench.05.array-range/main.cpp index 8a857255f..66086314d 100644 --- a/dash/examples/bench.05.array-range/main.cpp +++ b/dash/examples/bench.05.array-range/main.cpp @@ -20,9 +20,7 @@ typedef dash::util::Timer< dash::util::TimeMeasure::Clock > Timer; -#ifndef TYPE -#define TYPE int -#endif +typedef int value_t; typedef dash::TilePattern< 1, @@ -31,12 +29,12 @@ typedef dash::TilePattern< > TilePattern_t; typedef dash::Array< - TYPE, + value_t, int, TilePattern_t > ArrayTiledDist_t; -typedef dash::Array +typedef dash::Array ArrayBlockedDist_t; template @@ -74,15 +72,15 @@ int main(int argc, char* argv[]) { std::deque> tests; tests.push_back({0 , 0}); // this prints the header - tests.push_back({4 , 1000000}); - tests.push_back({16 , 100000}); - tests.push_back({64 , 100000}); - tests.push_back({256 , 10000}); - tests.push_back({1024 , 10000}); - tests.push_back({4096 , 1000}); - tests.push_back({4*4096 , 5000}); + tests.push_back({4 , 10000000}); + tests.push_back({16 , 1000000}); + tests.push_back({64 , 1000000}); + tests.push_back({256 , 100000}); + tests.push_back({1024 , 100000}); + tests.push_back({4096 , 10000}); + tests.push_back({4*4096 , 2500}); tests.push_back({16*4096 , 1000}); - tests.push_back({64*4096 , 500}); + tests.push_back({64*4096 , 250}); for (auto test: tests) { perform_test(test.first, test.second); @@ -202,12 +200,12 @@ double test_view_gups( for (auto i = 0; i < REPEAT; ++i) { for (auto lidx = 0; lidx < a.lsize(); ++lidx) { - auto lrange = dash::index( - dash::local( - dash::sub( + auto lrange = a | dash::sub( lbegin_gidx, - lbegin_gidx + lidx, - a) ) ); + lbegin_gidx + lidx) + | dash::local() + | dash::index(); + int lrange_begin = *dash::begin(lrange); int lrange_end = *dash::end(lrange); @@ -245,6 +243,7 @@ double test_algo_gups( auto a_size = a.size(); auto ts_start = Timer::Now(); auto myid = pattern.team().myid(); + for (auto i = 0; i < REPEAT; ++i) { for (auto lidx = 1; lidx < a.lsize(); ++lidx) { auto lrange = dash::local_index_range( diff --git a/dash/examples/ex.02.array-copy/main.cpp b/dash/examples/ex.02.array-copy/main.cpp index b95c8552c..24ffb2ab4 100644 --- a/dash/examples/ex.02.array-copy/main.cpp +++ b/dash/examples/ex.02.array-copy/main.cpp @@ -1,12 +1,15 @@ /* * \example ex.02.array-copy\main.cpp - * Example illustrating the use of \c dash::copy with a local array as destination. + * + * Example illustrating the use of \c dash::copy with a local array + * as destination. */ #include #include #include #include +#include #ifdef DASH_ENABLE_IPM #include @@ -18,6 +21,44 @@ using std::cout; using std::endl; +template +auto initialize_array(ArrayT & array) +-> typename std::enable_if< + std::is_floating_point::value, + void >::type +{ + auto block_size = array.pattern().blocksize(0); + for (auto li = 0; li != array.local.size(); ++li) { + auto block_lidx = li / block_size; + auto block_gidx = (block_lidx * dash::size()) + dash::myid().id; + auto gi = (block_gidx * block_size) + (li % block_size); + array.local[li] = // unit + (1.0000 * dash::myid().id) + + // local offset + (0.0100 * (li+1)) + + // global offset + (0.0001 * gi); + } + array.barrier(); +} + +template +static std::string range_str( + const ValueRange & vrange) { + typedef typename ValueRange::value_type value_t; + std::ostringstream ss; + auto idx = dash::index(vrange); + int i = 0; + for (const auto & v : vrange) { + ss << std::setw(2) << *(dash::begin(idx) + i) << "|" + << std::fixed << std::setprecision(4) + << static_cast(v) << " "; + ++i; + } + return ss.str(); +} + + int main(int argc, char* argv[]) { dash::init(&argc, &argv); @@ -26,16 +67,16 @@ int main(int argc, char* argv[]) size_t num_units = dash::Team::All().size(); size_t num_elems_unit = (argc > 1) ? static_cast(atoi(argv[1])) - : 20; + : 8; + size_t num_elems_total = num_elems_unit * num_units; size_t start_index = (argc > 2) ? static_cast(atoi(argv[2])) - : 10; + : num_elems_total / 4; size_t num_elems_copy = (argc > 3) ? static_cast(atoi(argv[3])) - : 20; - size_t num_elems_total = num_elems_unit * num_units; + : num_elems_total / 2; - dash::Array array(num_elems_total); + dash::Array array(num_elems_total, dash::BLOCKCYCLIC(3)); if (myid == 0) { cout << endl @@ -44,45 +85,82 @@ int main(int argc, char* argv[]) << "Elements to copy: " << num_elems_copy << endl; } - // fill the local part of the global array each unit is holding with - // it's DASH ID (\c dash::myid). - std::fill(array.lbegin(), array.lend(), myid); - - array.barrier(); + initialize_array(array); if (myid == 0) { cout << "Array size: " << array.size() << endl; + cout << range_str(array) << endl; } - // destination array - int * local_array = new int[num_elems_copy]; + // ---------------------------------------------------------------------- + // global-to-local copy: + // ---------------------------------------------------------------------- -#ifdef DASH_ENABLE_IPM - MPI_Pcontrol(0, "on"); // turn monitoring on - MPI_Pcontrol(0, "clear"); // clear all performance data -#endif + if (myid == 0) { + cout << "=== Global to Local =================================" << endl; + } + + // destination array + std::vector local_array(num_elems_copy); - // each unit copies from the global array into it's own local array - // note: each unit has the same data in it's local array at the end dash::copy(array.begin() + start_index, array.begin() + start_index + num_elems_copy, - local_array); + local_array.data()); -#ifdef DASH_ENABLE_IPM - MPI_Pcontrol(0, "off"); // turn monitoring off -#endif + array.barrier(); std::ostringstream ss; ss << "Local copy at unit " << myid << ": "; for(size_t i = 0; i < num_elems_copy; ++i) { ss << local_array[i] << " "; } - ss << endl; - cout << ss.str(); + cout << ss.str() << endl; + + array.barrier(); + + // ---------------------------------------------------------------------- + // global-to-global copy: + // ---------------------------------------------------------------------- + + if (myid == 0) { + cout << "=== Global to Global ================================" << endl; + + auto g_out_range = + dash::make_range( + array.begin() + (array.size() / 4), + array.begin() + (array.size() / 4) + (num_elems_total / 2)); + cout << range_str(g_out_range) << endl; + } + + dash::Array src_array(num_elems_total / 2, dash::BLOCKCYCLIC(2)); + + std::fill(src_array.lbegin(), src_array.lend(), (myid + 1) * 10); + + if (myid == 0) { + cout << "copy target: "; + cout << range_str(array) << endl; + cout << "copy target index range: " + << "[" << (array.size() / 4) + << "," << ((array.size() / 4) + src_array.size()) + << ")" + << endl; + cout << "copy source: "; + cout << range_str(src_array) << endl; + } array.barrier(); - delete[] local_array; + dash::copy(src_array.begin(), + src_array.end(), + array.begin() + (array.size() / 4)); + + array.barrier(); + + if (myid == 0) { + cout << "after copy:" << endl; + cout << range_str(array) + << endl; + } dash::finalize(); diff --git a/dash/examples/ex.02.array-views/main.cpp b/dash/examples/ex.02.array-views/main.cpp new file mode 100644 index 000000000..e439d53ea --- /dev/null +++ b/dash/examples/ex.02.array-views/main.cpp @@ -0,0 +1,131 @@ +#include +#include "../util.h" + +using std::cout; +using std::cerr; +using std::clog; +using std::cin; +using std::endl; +using std::vector; + + +template +auto initialize_array(ArrayT & array) +-> typename std::enable_if< + std::is_floating_point::value, + void >::type +{ + auto block_size = array.pattern().blocksize(0); + for (auto li = 0; li != array.local.size(); ++li) { + auto block_lidx = li / block_size; + auto block_gidx = (block_lidx * dash::size()) + dash::myid().id; + auto gi = (block_gidx * block_size) + (li % block_size); + array.local[li] = // unit + (1.0000 * dash::myid().id) + + // local offset + + (0.0100 * li); + // global offset + // + (0.0001 * gi); + } + array.barrier(); +} + +int main(int argc, char *argv[]) +{ + using namespace dash; + + dash::init(&argc, &argv); + + int elem_additional = 2; + int block_size = 2; + int elem_per_unit = block_size * 2; + int array_size = dash::size() * elem_per_unit + + std::min(elem_additional, dash::size()); + + { + dash::Array a(array_size, dash::BLOCKCYCLIC(block_size)); + initialize_array(a); + + if (dash::myid() == 0) { + print("a: " << range_str(a)); + + STEP("- a | sub"); + auto s_array = a | sub(1, a.size()-2); + print(" a | sub: " << range_str(s_array)); + + STEP("- a | sub | blocks"); + auto sb_array = a | sub(1, a.size()-2) | blocks(); + for (const auto & b : sb_array) { + print(" a | sub | blocks: " << range_str(b)); + } + } + dash::barrier(); + + auto l_array = a | local(); + STEP("- a | local: " << range_str(l_array)); + dash::barrier(); + + auto sl_array = a | sub(1, a.size()-2) | local(); + STEP("- a | sub | local: " << range_str(sl_array)); + dash::barrier(); + + STEP("- a | sub | local | blocks"); + auto slb_array = a | sub(1, a.size()-2) | local() | blocks(); + auto slb_arr_i = slb_array | index(); + int i = 0; + for (const auto & b : slb_array) { + print(" a | sub | local | block(" << slb_arr_i[i] << "): " << + range_str(b)); + ++i; + } + + auto copy_num_elem = a.size() / 2; + auto copy_dest_begin_idx = a.size() / 4 - 1; + auto copy_dest_end_idx = copy_dest_begin_idx + copy_num_elem; + + int buf_i = 0; + std::vector buf(copy_num_elem); + std::transform(buf.begin(), buf.end(), + buf.begin(), + [&](const double & a) { + return a + 6 + (0.01 * ++buf_i); + }); + + a.barrier(); + + if (dash::myid() == 0) { + STEP("copy to index range " + << "[" << copy_dest_begin_idx + << "," << copy_dest_end_idx << ")"); + + auto copy_begin_it = a.begin() + copy_dest_begin_idx; + auto copy_end_it_exp = copy_begin_it + copy_num_elem; + + auto dest_range = dash::make_range(copy_begin_it, + copy_end_it_exp); + auto dest_blocks = dash::blocks(dest_range); + + // Printing temporaries from view expressions instead of + // named values for testing: + STEP("target index set: " << dash::index(dest_range)); + STEP("target block set: " << dash::index(dash::blocks(dest_range))); + STEP("copy target range: " << range_str(dest_range)); + + for (const auto & block : dest_blocks) { + print("copy to block: " << range_str(block)); + } + + // copy local buffer to global array + auto copy_end_it = dash::copy( + buf.data(), + buf.data() + copy_num_elem, + copy_begin_it); + } + a.barrier(); + + print("modified array: " << range_str(a)); + } + + dash::finalize(); +} + diff --git a/dash/examples/ex.02.matrix-copy-views/main.cpp b/dash/examples/ex.02.matrix-copy-views/main.cpp new file mode 100644 index 000000000..5da3e2faa --- /dev/null +++ b/dash/examples/ex.02.matrix-copy-views/main.cpp @@ -0,0 +1,88 @@ +#include +#include "../util.h" + + +int main(int argc, char *argv[]) +{ + using namespace dash; + + typedef dash::SeqTilePattern<2> pattern_t; + typedef typename pattern_t::index_type index_t; + typedef float value_t; + + dash::init(&argc, &argv); + + auto myid = dash::Team::All().myid(); + auto nunits = dash::size(); + + const size_t block_size_x = 2; + const size_t block_size_y = 2; + const size_t block_size = block_size_x * block_size_y; + size_t extent_x = block_size_x * (nunits + 1); + size_t extent_y = block_size_y * (nunits + 1); + + dash::TeamSpec<2> teamspec(dash::Team::All()); + teamspec.balance_extents(); + + pattern_t pattern( + dash::SizeSpec<2>( + extent_y, + extent_x), + dash::DistributionSpec<2>( + dash::TILE(block_size_y), + dash::TILE(block_size_x)), + teamspec + ); + + dash::Matrix + matrix_a(pattern); + + dash::Matrix + matrix_b(pattern); + + int li; + + li = 0; + std::generate(matrix_a.lbegin(), + matrix_a.lend(), + [&]() { + return dash::myid() + 0.01 * li++; + }); + li = 0; + std::generate(matrix_b.lbegin(), + matrix_b.lend(), + [&]() { + return dash::myid() + 0.01 * li++; + }); + dash::barrier(); + + if (myid == 0) { + print("matrix_a:" << + nview_str(matrix_a | sub(0,extent_y)) << '\n'); + print("matrix_b:" << + nview_str(matrix_b | sub(0,extent_y)) << '\n'); + + print("matrix number of blocks:" <<(matrix_b | blocks()).size()); + } + dash::barrier(); + + index_t n_lblocks = (matrix_b | local() | blocks()).size(); + print("matrix number of local blocks:" <<(matrix_b | blocks()).size()); + + + index_t dst_block = dash::myid() + 1; + +// auto copy_end = dash::copy(matrix_a | local() | block(1), +// matrix_b | block(dst_block)); + + if (myid == 0) { + print("matrix:" << + nview_str(matrix_b | sub(0,extent_y)) << '\n'); + + print("matrix number of blocks:" <<(matrix_b | blocks()).size()); + } + + + dash::finalize(); + return EXIT_SUCCESS; +} diff --git a/dash/examples/ex.02.matrix-halo-views/main.cpp b/dash/examples/ex.02.matrix-halo-views/main.cpp new file mode 100644 index 000000000..25ed8c4a1 --- /dev/null +++ b/dash/examples/ex.02.matrix-halo-views/main.cpp @@ -0,0 +1,118 @@ +#include +#include "../util.h" + +using std::cout; +using std::cerr; +using std::cin; +using std::endl; +using std::vector; + +using uint = unsigned int; + + +int main(int argc, char *argv[]) +{ + using dash::local; + using dash::expand; + using dash::shift; + using dash::sub; + using dash::blocks; + using dash::index; + + dash::init(&argc, &argv); + + auto myid = dash::myid(); + auto nunits = dash::size(); + + const size_t block_size_x = 2; + const size_t block_size_y = 2; + size_t num_blocks_x = nunits - 1; + size_t num_blocks_y = nunits; + size_t extent_x = block_size_x * num_blocks_x; + size_t extent_y = block_size_y * num_blocks_y; + + typedef dash::TilePattern<2> pattern_t; + typedef typename pattern_t::index_type index_t; + typedef float value_t; + + dash::TeamSpec<2> teamspec(dash::Team::All()); + teamspec.balance_extents(); + + pattern_t pattern( + dash::SizeSpec<2>( + extent_y, + extent_x), + dash::DistributionSpec<2>( + dash::TILE(block_size_y), + dash::TILE(block_size_x)), + teamspec + ); + + dash::Matrix + matrix(pattern); + + // Initialize matrix values: + int li = 0; + std::generate(matrix.lbegin(), + matrix.lend(), + [&]() { + return dash::myid() + 0.01 * li++; + }); + dash::barrier(); + + if (myid == 0) { + auto matrix_view = dash::sub(0, matrix.extents()[0], matrix); + print("matrix" << nview_str(matrix_view, 2)); + + auto matrix_blocks = matrix | dash::blocks(); + auto matrix_b_idx = matrix_blocks | dash::index(); + int b_idx = 0; + for (const auto & m_block : matrix_blocks) { + auto b_offsets = m_block.offsets(); + auto b_extents = m_block.extents(); + + // matrix block view: + STEP("\n-- matrix | block[" << matrix_b_idx[b_idx] << "]:" << + "\n " << + "offsets: " << b_offsets[0] << "," << b_offsets[1] << " " << + "extents: " << b_extents[0] << "," << b_extents[1] << + nview_str(m_block, 2)); + + // matrix block halo view: + auto b_halo = m_block | dash::expand<0>(-1, 1) + | dash::expand<1>(-1, 1); + + auto bh_offsets = b_halo.offsets(); + auto bh_extents = b_halo.extents(); + STEP(" matrix | block[" << matrix_b_idx[b_idx] << "] | " << + "expand({ -1,1 }, { -1,1 }):" << + "\n " << + "offsets: " << bh_offsets[0] << "," << bh_offsets[1] << " " << + "extents: " << bh_extents[0] << "," << bh_extents[1] << + nview_str(b_halo, 2)); + + // matrix shifted block halo: + auto b_halo_s = b_halo | shift<1>(1); + + auto bhs_offsets = b_halo_s.offsets(); + auto bhs_extents = b_halo_s.extents(); + STEP(" matrix | block[" << matrix_b_idx[b_idx] << "] | " << + "expand({ -1,1 }, { -1,1 }) | shift<1>(1):" << + "\n " << + "offsets: " << bhs_offsets[0] << "," << bhs_offsets[1] << " " << + "extents: " << bhs_extents[0] << "," << bhs_extents[1] << + nview_str(b_halo_s, 2)); + + auto bhs_blocks = b_halo_s | dash::blocks(); + STEP(" matrix | block[" << matrix_b_idx[b_idx] << "] | " << + "expand({ -1,1 }, { -1,1 }) | shift<1>(1) | block[0]" << + nview_str(bhs_blocks[0], 2)); + + ++b_idx; + } + } + dash::barrier(); + + dash::finalize(); + return EXIT_SUCCESS; +} diff --git a/dash/examples/ex.02.matrix-local-views/main.cpp b/dash/examples/ex.02.matrix-local-views/main.cpp new file mode 100644 index 000000000..b0a991016 --- /dev/null +++ b/dash/examples/ex.02.matrix-local-views/main.cpp @@ -0,0 +1,163 @@ + +#include +#include "../util.h" +#include "../pattern_params.h" + +#include +#include + +using std::cout; +using std::endl; + +using namespace dash; + +template +void run_example(MatrixT & matrix); + +#define RUN_EXAMPLE(pattern_type__) do { \ + auto pattern = make_ ## pattern_type__ ## _pattern( \ + params, sizespec, teamspec); \ + if (dash::myid() == 0) { \ + std::cout << "Pattern:\n " \ + << pattern_to_string(pattern) \ + << std::endl; \ + } \ + dash::Matrix \ + matrix(pattern); \ + run_example(matrix); \ +} while(0) + + +int main(int argc, char **argv) +{ + using dash::sub; + using dash::local; + using dash::index; + using dash::blocks; + + typedef dash::TilePattern<2> pattern_t; + typedef typename pattern_t::index_type index_t; + typedef float value_t; + + dash::init(&argc, &argv); + + auto myid = dash::myid(); + auto nunits = dash::size(); + + cli_params defaults = default_params; + defaults.type = "seq"; + defaults.size = {{ 8, 6 }}; + defaults.tile = {{ 0, 0 }}; + defaults.units = {{ 1, static_cast(nunits) }}; + defaults.blocked_display = false; + defaults.balance_extents = false; + defaults.cout = false; + + auto params = parse_args(argc, argv, defaults); + + if (dash::myid() == 0) { + print_params(params); + } + + dash::SizeSpec<2, extent_t> sizespec(params.size[0], + params.size[1]); + dash::TeamSpec<2, index_t> teamspec(params.units[0], + params.units[1]); + + if(params.balance_extents) { + teamspec.balance_extents(); + } + if (params.tile[0] == 0 && params.tile[1] == 0) { + auto max_team_extent = std::max(teamspec.extent(0), + teamspec.extent(1)); + params.tile[0] = sizespec.extent(0) / max_team_extent; + params.tile[1] = sizespec.extent(1) / max_team_extent; + } + + if (params.type == "summa") { + RUN_EXAMPLE(summa); + } else if (params.type == "block") { + RUN_EXAMPLE(block); + } else if (params.type == "tile") { + RUN_EXAMPLE(tile); + } else if (params.type == "shift") { + RUN_EXAMPLE(shift_tile); + } else if (params.type == "seq") { + RUN_EXAMPLE(seq_tile); + } else { + print_usage(argv); + exit(EXIT_FAILURE); + } + + dash::finalize(); + return 0; +} + +template +void run_example(MatrixT & matrix) { + typedef typename MatrixT::pattern_type pattern_t; + typedef typename pattern_t::index_type index_t; + typedef typename MatrixT::value_type value_t; + + int li = 0; + std::generate(matrix.lbegin(), + matrix.lend(), + [&]() { + return dash::myid() + 0.01 * li++; + }); + + dash::barrier(); + + if (dash::myid() == 0) { + print("matrix:" << + nview_str(matrix | sub(0,matrix.extents()[0]))); + + std::vector tmp(10); + auto copy_end = std::copy(matrix.begin() + 11, + matrix.begin() + 21, + tmp.data()); + STEP("matrix.begin()[11...20]: " << range_str(tmp, 2)); + } + + dash::barrier(); + + auto l_matrix = matrix | local(); + + STEP("matrix | local() | index():" << dash::typestr(l_matrix)); + + STEP("matrix | local() | index():" << dash::typestr(l_matrix | index())); + STEP("matrix | local():" << nview_str(l_matrix)); + + dash::barrier(); + + // Copy local block + { + auto l_blocks = matrix | local() | blocks(); + STEP("-- matrix | local() | blocks(): " << + "size: " << l_blocks.size() << " " << + "offsets: " << l_blocks.offsets() << " " << + "extents: " << l_blocks.extents()); + + int l_bi = 0; + for (const auto & lb : l_blocks) { + DASH_LOG_DEBUG("matrix | local() | blocks()", "[", l_bi, "]", + "size:", lb.size(), + "offsets:", lb.offsets(), + "extents:", lb.extents()); + + STEP(" matrix | local() | blocks()[" << l_bi << "]: " << + nview_str(lb)); + + std::vector tmp(lb.size()); + auto copy_end = std::copy(lb.begin(), + lb.end(), + tmp.data()); + STEP(" matrix | local() | blocks()[" << l_bi << "] copy: " << + range_str(tmp, 2)); + + ++l_bi; + } + dash::barrier(); + } +} + diff --git a/dash/examples/ex.02.matrix-ranges/main.cpp b/dash/examples/ex.02.matrix-ranges/main.cpp new file mode 100644 index 000000000..c47e635dd --- /dev/null +++ b/dash/examples/ex.02.matrix-ranges/main.cpp @@ -0,0 +1,194 @@ +#include +#include "../util.h" + +using std::cout; +using std::cerr; +using std::cin; +using std::endl; +using std::vector; + +using uint = unsigned int; + + +int main(int argc, char *argv[]) +{ + using namespace dash; + + dash::init(&argc, &argv); + + auto myid = dash::myid(); + auto nunits = dash::size(); + + const size_t block_size_x = 2; + const size_t block_size_y = 3; + const size_t block_size = block_size_x * block_size_y; + size_t num_local_blocks_x = 2; + size_t num_local_blocks_y = 2; + size_t num_blocks_x = nunits * num_local_blocks_x; + size_t num_blocks_y = nunits * num_local_blocks_y; + size_t num_blocks_total = num_blocks_x * num_blocks_y; + size_t extent_x = block_size_x * num_blocks_x; + size_t extent_y = block_size_y * num_blocks_y; + size_t num_elem_total = extent_x * extent_y; + // Assuming balanced mapping: + size_t num_elem_per_unit = num_elem_total / nunits; + size_t num_blocks_per_unit = num_elem_per_unit / block_size; + + typedef dash::ShiftTilePattern<2> pattern_t; + typedef typename pattern_t::index_type index_t; + typedef float value_t; + + pattern_t pattern( + dash::SizeSpec<2>( + extent_y, + extent_x), + dash::DistributionSpec<2>( + dash::TILE(block_size_y), + dash::TILE(block_size_x)) + ); + + dash::Matrix + matrix(pattern); + + // Initialize matrix values: + int li = 0; + std::generate(matrix.lbegin(), + matrix.lend(), + [&]() { + auto u = dash::myid(); + return u + 0.01 * li++; + }); + dash::barrier(); + + if (myid == 0) { + print("matrix:" << + nview_str(dash::sub(0, matrix.extents()[0], matrix))); + + auto matrix_region = dash::size() > 1 + ? dash::sub<0>( + 2, matrix.extents()[0] - 2, + dash::sub<1>( + 2, matrix.extents()[1] - 3, + matrix)) + : dash::sub<0>( + 0, matrix.extents()[0], + dash::sub<1>( + 0, matrix.extents()[1], + matrix)); + + print("matrix | sub<0>(2,-2) | sub<1>(2,-3) \n" << + nview_str(matrix_region)); + + auto matrix_reg_blocks = dash::blocks(matrix_region); + for (const auto & reg_block : matrix_reg_blocks) { + auto sreg_block = dash::sub<0>(1,2, reg_block); + + DASH_LOG_DEBUG("MatrixViewsExample", "==============================", + nview_str(reg_block)); + DASH_LOG_DEBUG("MatrixViewsExample", + dash::typestr(sreg_block.begin())); + DASH_LOG_DEBUG("MatrixViewsExample", + nview_str(sreg_block)); + + auto block_rg = dash::make_range(reg_block.begin(), + reg_block.end()); + auto block_srg = dash::sub<0>(1,2, block_rg); + + DASH_LOG_DEBUG("MatrixViewsExample", "------------------------------", + nview_str(block_rg)); + DASH_LOG_DEBUG("MatrixViewsExample", "block range origin iterator:", + dash::typestr(dash::origin(block_srg).begin())); + // DASH_LOG_DEBUG("MatrixViewsExample", "block range origin:", + // nview_str(dash::origin(block_srg))); + // DASH_LOG_DEBUG("MatrixViewsExample", + // nview_str(block_srg)); + } + } + dash::barrier(); + + // Array to store local copy: + std::vector local_copy(num_elem_per_unit); + // Pointer to first value in next copy destination range: + value_t * copy_dest_begin = local_copy.data(); + value_t * copy_dest_last = local_copy.data(); + + for (size_t gb = 0; gb < num_blocks_total; ++gb) { + // View of block at global block index gb: + auto g_block_view = pattern.block(gb); + // Unit assigned to block at global block index gb: + auto g_block_unit = pattern.unit_at( + std::array {0,0}, + g_block_view); + dash::team_unit_t remote_unit_id( + (dash::Team::All().myid().id + 1) % nunits); + if (g_block_unit == remote_unit_id) { + DASH_LOG_DEBUG("MatrixViewsExample", "==========================="); + DASH_LOG_DEBUG("MatrixViewsExample", + "block gidx", gb, + "at unit", g_block_unit.id); + DASH_LOG_DEBUG("MatrixViewsExample", "vvvvvvvvvvvvvvvvvvvvvvvvvvv"); + // Block is assigned to selecte remote unit, create local copy: + auto remote_block_matrix = matrix.block(gb); + + auto remote_block_view = dash::blocks(matrix)[gb]; + + // Test number of copied elements: + auto num_copied = copy_dest_last - copy_dest_begin; + DASH_ASSERT(num_copied == block_size); + + // Advance local copy destination pointer: + copy_dest_begin = copy_dest_last; + + auto remote_block_range = dash::sub(1,3, + dash::make_range( + remote_block_view.begin(), + remote_block_view.end())); + + DASH_LOG_DEBUG("MatrixViewsExample", + "source block range:", "-- type:", + dash::typestr(remote_block_range)); + DASH_LOG_DEBUG("MatrixViewsExample", "-- type:", + "source block range iterator:", + dash::typestr(remote_block_range.begin())); + DASH_LOG_DEBUG("MatrixViewsExample", "-- type:", + "source block range domain:", + dash::typestr(dash::domain(remote_block_range))); + DASH_LOG_DEBUG("MatrixViewsExample", "-- type:", + "source block range origin:", + dash::typestr(dash::origin(remote_block_range))); + + DASH_LOG_DEBUG("MatrixViewsExample", + "source block range:", + "extents:", remote_block_range.extents(), + "offsets:", remote_block_range.offsets(), + "size:", remote_block_range.size()); + DASH_LOG_DEBUG("MatrixViewsExample", + "source block range domain:", + "extents:", dash::domain(remote_block_range).extents(), + "offsets:", dash::domain(remote_block_range).offsets(), + "size:", dash::domain(remote_block_range).size()); + DASH_LOG_DEBUG("MatrixViewsExample", + "begin.pos:", remote_block_range.begin().pos(), + "end.pos:", remote_block_range.end().pos(), + "begin.gpos:", remote_block_range.begin().gpos(), + "end.gpos:", remote_block_range.end().gpos()); + DASH_LOG_DEBUG("MatrixViewsExample", "block range index:", + nview_str(dash::index(remote_block_range))); + DASH_LOG_DEBUG("MatrixViewsExample", "block range index is strided:", + dash::index(remote_block_range).is_strided()); + DASH_LOG_DEBUG("MatrixViewsExample", "block range:", + nview_str(remote_block_range)); + DASH_LOG_DEBUG("MatrixViewsExample", "local(block range):", + nview_str(dash::local(remote_block_range))); + + copy_dest_last = dash::copy(remote_block_range, + copy_dest_begin); + + DASH_LOG_DEBUG("MatrixViewsExample", "^^^^^^^^^^^^^^^^^^^^^^^^^^^"); + } + } + print("local copy of all remote values:\n" << local_copy); + + dash::finalize(); + return EXIT_SUCCESS; +} diff --git a/dash/examples/ex.02.matrix-strides/main.cpp b/dash/examples/ex.02.matrix-strides/main.cpp new file mode 100644 index 000000000..ef7b11afa --- /dev/null +++ b/dash/examples/ex.02.matrix-strides/main.cpp @@ -0,0 +1,10 @@ + +#include + + +int main(int argc, char * argv[]) +{ + + return EXIT_SUCCESS; +} + diff --git a/dash/examples/ex.02.matrix-sub-views/main.cpp b/dash/examples/ex.02.matrix-sub-views/main.cpp new file mode 100644 index 000000000..22ef3d673 --- /dev/null +++ b/dash/examples/ex.02.matrix-sub-views/main.cpp @@ -0,0 +1,84 @@ +#include +#include "../util.h" + +#include +#include + + +int main(int argc, char *argv[]) +{ + using namespace dash; + + typedef dash::SeqTilePattern<2> pattern_t; + typedef typename pattern_t::index_type index_t; + typedef float value_t; + + dash::init(&argc, &argv); + + auto myid = dash::Team::All().myid(); + auto nunits = dash::size(); + + const size_t block_size_x = 2; + const size_t block_size_y = 2; + const size_t block_size = block_size_x * block_size_y; + size_t extent_x = block_size_x * (nunits + 1); + size_t extent_y = block_size_y * (nunits + 1); + + dash::TeamSpec<2> teamspec(dash::Team::All()); + teamspec.balance_extents(); + + pattern_t pattern( + dash::SizeSpec<2>( + extent_y, + extent_x), + dash::DistributionSpec<2>( + dash::TILE(block_size_y), + dash::TILE(block_size_x)), + teamspec + ); + + dash::Matrix + matrix(pattern); + + int li = 0; + std::generate(matrix.lbegin(), + matrix.lend(), + [&]() { + return dash::myid() + 0.01 * li++; + }); + + dash::barrier(); + + if (myid == 0) { + print("matrix:" << + nview_str(matrix | sub(0,extent_y)) << '\n'); + + STEP("mat | sub<0>(3,-1) | sub<1>(1,-1)"); + + auto matrix_sub = matrix | sub<0>(3, extent_y-1) + | sub<1>(1, extent_x-1); + + print(nview_str(matrix_sub) << "\n\n"); + + STEP("mat | sub<0>(3,-1) | sub<1>(1,-1) | blocks()"); + { + auto m_s_blocks = matrix_sub | blocks(); + auto m_s_blocks_idx = matrix_sub | blocks() | index(); + int b_idx = 0; + for (const auto & blk : m_s_blocks) { + STEP("block " << std::left << std::setw(2) + << (blk | index()) << '\n'); + print(" " << + (blk.is_strided() ? "strided, " : "contiguous, ") << + (blk.is_local_at(myid) ? "local" : "remote") << + nview_str(blk) << std::endl); + ++b_idx; + } + } + } + + dash::finalize(); + return EXIT_SUCCESS; +}; + + diff --git a/dash/examples/ex.02.matrix_views/Makefile b/dash/examples/ex.02.matrix-views/Makefile similarity index 100% rename from dash/examples/ex.02.matrix_views/Makefile rename to dash/examples/ex.02.matrix-views/Makefile diff --git a/dash/examples/ex.02.matrix-views/main.cpp b/dash/examples/ex.02.matrix-views/main.cpp new file mode 100644 index 000000000..fa176032f --- /dev/null +++ b/dash/examples/ex.02.matrix-views/main.cpp @@ -0,0 +1,227 @@ +#include +#include "../util.h" + +using std::cout; +using std::cerr; +using std::cin; +using std::endl; +using std::vector; + +using namespace dash; + +using uint = unsigned int; + +template +auto transform_in_view(MatrixT & mat, ViewMods && vmods) { + print("transform_in_view: " << nview_str(mat | vmods)); + return 0; +} + + +int main(int argc, char *argv[]) +{ + using dash::sub; + using dash::local; + using dash::index; + using dash::blocks; + + dash::init(&argc, &argv); + + auto myid = dash::myid(); + auto nunits = dash::size(); + + const size_t block_size_x = 2; + const size_t block_size_y = 3; + const size_t block_size = block_size_x * block_size_y; + size_t num_local_blocks_x = 2; + size_t num_local_blocks_y = 2; + size_t num_blocks_x = nunits * num_local_blocks_x; + size_t num_blocks_y = nunits * num_local_blocks_y; + size_t num_blocks_total = num_blocks_x * num_blocks_y; + size_t extent_x = block_size_x * num_blocks_x; + size_t extent_y = block_size_y * num_blocks_y; + size_t num_elem_total = extent_x * extent_y; + // Assuming balanced mapping: + size_t num_elem_per_unit = num_elem_total / nunits; + size_t num_blocks_per_unit = num_elem_per_unit / block_size; + + + typedef dash::ShiftTilePattern<2> pattern_t; + typedef typename pattern_t::index_type index_t; + typedef float value_t; + + pattern_t pattern( + dash::SizeSpec<2>( + extent_y, + extent_x), + dash::DistributionSpec<2>( + dash::TILE(block_size_y), + dash::TILE(block_size_x)) + ); + + dash::Matrix + matrix(pattern); + + // Initialize matrix values: + int li = 0; + std::generate(matrix.lbegin(), + matrix.lend(), + [&]() { + auto u = dash::myid(); + return u + 0.01 * li++; + }); + dash::barrier(); + + if (myid == 0) { + print("matrix:" << + nview_str(dash::sub(0, matrix.extents()[0], matrix))); + + transform_in_view(matrix, sub<0>(2,4) | sub<1>(2,6)); + + auto matrix_region = dash::size() > 1 + ? dash::sub<0>( + 2, matrix.extents()[0] - 2, + dash::sub<1>( + 2, matrix.extents()[1] - 3, + matrix)) + : dash::sub<0>( + 0, matrix.extents()[0], + dash::sub<1>( + 0, matrix.extents()[1], + matrix)); + + print("matrix | sub<0>(2,-2) | sub<1>(2,-3) \n" << + nview_str(matrix_region)); + + auto matrix_reg_blocks = matrix_region | blocks(); + int bi = 0; + for (const auto & reg_block : matrix_reg_blocks) { + print("matrix | sub | sub | block[" << bi << "] " << + "extents: " << reg_block.extents() << " " << + "offsets: " << reg_block.offsets()); + print(nview_str(reg_block) << '\n'); + + // auto sreg_block = reg_block | dash::intersect( + // ViewSpec<2>({ 1,2 })); + // if (!sreg_block) { continue; } + // DASH_LOG_DEBUG("MatrixViewsExample", sreg_block.size()); + // DASH_LOG_DEBUG("MatrixViewsExample", + // dash::typestr(sreg_block.begin())); + // DASH_LOG_DEBUG("MatrixViewsExample", + // nview_str(sreg_block)); + ++bi; + } + } + dash::barrier(); + + // Array to store local copy: + std::vector local_copy(num_elem_per_unit); + // Pointer to first value in next copy destination range: + value_t * copy_dest_begin = local_copy.data(); + value_t * copy_dest_last = local_copy.data(); + + print("Number of blocks: " << num_blocks_total); + + for (size_t gb = 0; gb < num_blocks_total; ++gb) { + // View of block at global block index gb: + auto g_block_view = pattern.block(gb); + // Unit assigned to block at global block index gb: + auto g_block_unit = pattern.unit_at( + std::array {0,0}, + g_block_view); + dash::team_unit_t remote_unit_id( + (dash::Team::All().myid().id + 1) % nunits); + if (g_block_unit == remote_unit_id) { + DASH_LOG_DEBUG("MatrixViewsExample", "==========================="); + print("--- block gidx " << gb << " at unit " << g_block_unit.id); + + DASH_LOG_DEBUG("MatrixViewsExample", "vvvvvvvvvvvvvvvvvvvvvvvvvvv"); + // Block is assigned to selecte remote unit, create local copy: + auto remote_block_matrix = dash::sub(1,5, matrix.block(gb)); + + auto remote_block_view = dash::sub(1,5, dash::blocks(matrix)[gb]); + + DASH_LOG_DEBUG("MatrixViewsExample", "-- type:", + dash::typestr(remote_block_view)); + DASH_LOG_DEBUG("MatrixViewsExample", "-- type:", + "source block view iterator:", + dash::typestr(remote_block_view.begin())); + DASH_LOG_DEBUG("MatrixViewsExample", "-- type:", + "source block view domain:", + dash::typestr(dash::domain(remote_block_view))); + DASH_LOG_DEBUG("MatrixViewsExample", "-- type:", + "source block view origin:", + dash::typestr(dash::origin(remote_block_view))); + + DASH_LOG_DEBUG("MatrixViewsExample", + "source block view:", + "extents:", remote_block_view.extents(), + "offsets:", remote_block_view.offsets(), + "size:", remote_block_view.size()); + DASH_LOG_DEBUG("MatrixViewsExample", + "source block view domain:", + "extents:", dash::domain(remote_block_view).extents(), + "offsets:", dash::domain(remote_block_view).offsets(), + "size:", dash::domain(remote_block_view).size()); + DASH_LOG_DEBUG("MatrixViewsExample", + "begin.pos:", remote_block_view.begin().pos(), + "end.pos:", remote_block_view.end().pos(), + "begin.gpos:", remote_block_view.begin().gpos(), + "end.gpos:", remote_block_view.end().gpos()); + DASH_LOG_DEBUG("MatrixViewsExample", "block view:", + nview_str(remote_block_view)); + + DASH_LOG_DEBUG("MatrixViewsExample", "block view index type:", + dash::typestr( + dash::index(remote_block_view))); + DASH_LOG_DEBUG("MatrixViewsExample", "block view index is strided:", + dash::index(remote_block_view) + .is_strided()); + + DASH_LOG_DEBUG("MatrixViewsExample", "local block view index type:", + dash::typestr( + dash::index(dash::local(remote_block_view)))); + DASH_LOG_DEBUG("MatrixViewsExample", + "local block view index is strided:", + dash::index(dash::local(remote_block_view)) + .is_strided()); + + DASH_LOG_DEBUG("MatrixViewsExample", + "local block view index domain type:", + dash::typestr( + dash::domain( + dash::index(dash::local(remote_block_view))))); + DASH_LOG_DEBUG("MatrixViewsExample", + "local block view index domain is strided:", + dash::domain( + dash::index(dash::local(remote_block_view))) + .is_strided()); + + DASH_LOG_DEBUG("MatrixViewsExample", + "local block view index set size:", + dash::index(dash::local(remote_block_view)) + .size()); + + DASH_ASSERT(remote_block_matrix.offsets() == + dash::index(remote_block_view).offsets()); + DASH_ASSERT(remote_block_matrix.extents() == + dash::index(remote_block_view).extents()); + + copy_dest_last = dash::copy(remote_block_view, + copy_dest_begin); + + // Test number of copied elements: + auto num_copied = copy_dest_last - copy_dest_begin; + DASH_ASSERT(num_copied == block_size); + + // Advance local copy destination pointer: + copy_dest_begin = copy_dest_last; + + DASH_LOG_DEBUG("MatrixViewsExample", "^^^^^^^^^^^^^^^^^^^^^^^^^^^"); + } + } + print("local copy of all remote values:\n" << local_copy); + + dash::finalize(); + return EXIT_SUCCESS; +} diff --git a/dash/examples/ex.02.matrix_views/main.cpp b/dash/examples/ex.02.matrix_views/main.cpp deleted file mode 100644 index cd48906c7..000000000 --- a/dash/examples/ex.02.matrix_views/main.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include - -using std::cout; -using std::cin; -using std::endl; -using std::vector; - -using uint = unsigned int; - -inline void sum(const uint nelts, - const dash::NArray &matIn, - const uint myid) { - uint lclRows = matIn.pattern().local_extents()[0]; - - uint const *mPtr; - uint localSum = 0; - - for (uint i = 0; i < lclRows; ++i) { - mPtr = matIn.local.row(i).lbegin(); - - for (uint j = 0; j < nelts; ++j) { - localSum += *(mPtr++); - } - } -} - -int main(int argc, char *argv[]) -{ - dash::init(&argc, &argv); - - uint myid = static_cast(dash::Team::GlobalUnitID().id); - - const uint nelts = 40; - - dash::NArray mat(nelts, nelts); - - // Initialize matrix values: - uint counter = myid + 20; - if (0 == myid) { - for (uint *i = mat.lbegin(); i < mat.lend(); ++i) { - *i = ++counter; - } - } - dash::barrier(); - - sum(nelts, mat, myid); - - dash::finalize(); -} diff --git a/dash/examples/ex.05.transform/Makefile b/dash/examples/ex.05.transform/Makefile new file mode 100644 index 000000000..f3c00dab1 --- /dev/null +++ b/dash/examples/ex.05.transform/Makefile @@ -0,0 +1 @@ +include ../Makefile_cpp \ No newline at end of file diff --git a/dash/examples/ex.05.transform/main.cpp b/dash/examples/ex.05.transform/main.cpp new file mode 100644 index 000000000..9f930fa18 --- /dev/null +++ b/dash/examples/ex.05.transform/main.cpp @@ -0,0 +1,62 @@ +#include + +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::setw; +using std::setprecision; + +// ========================================================================== +// Type definitions +// ========================================================================== + +typedef double + ElementType; +typedef dash::default_index_t + IndexType; + +typedef dash::LoadBalancePattern<1> + PatternType; + +typedef dash::Array + ArrayType; + + +int main(int argc, char **argv) +{ + static const int NELEM = 100; + + dash::init(&argc, &argv); + + dash::util::TeamLocality tloc(dash::Team::All()); + PatternType pattern( + dash::SizeSpec<1>(NELEM), + tloc); + + ArrayType arr_a(pattern); + ArrayType arr_b(pattern); + ArrayType arr_c(pattern); + + for (size_t li = 0; li < arr_a.lsize(); li++) { + arr_a.local[li] = 1 + ((42 * (li + 1)) % 1024); + arr_b.local[li] = 1 + ((42 * (li + 1)) % 1024); + } + + dash::barrier(); + + auto min_git = dash::transform(arr_a.begin(), arr_a.end(), + arr_b.begin(), + arr_c.begin(), + dash::plus()); + + DASH_LOG_DEBUG("perform_test", "Waiting for completion of all units"); + dash::barrier(); + + dash::finalize(); + + return 0; +} + diff --git a/dash/examples/ex.06.make-pattern/main.cpp b/dash/examples/ex.06.make-pattern/main.cpp new file mode 100644 index 000000000..53814d554 --- /dev/null +++ b/dash/examples/ex.06.make-pattern/main.cpp @@ -0,0 +1,62 @@ + +#include +#include "../util.h" +#include "../pattern_params.h" + +using namespace dash; + + +int main(int argc, char * argv[]) +{ + dash::init(&argc, &argv); + + auto params = parse_args(argc, argv); + + if (dash::myid() == 0) { + print_params(params); + + try { + dash::SizeSpec<2, extent_t> sizespec(params.size[0], params.size[1]); + dash::TeamSpec<2, index_t> teamspec(params.units[0], params.units[1]); + + if(params.balance_extents) { + teamspec.balance_extents(); + } + if (params.tile[0] < 0 && params.tile[1] < 0) { + auto max_team_extent = std::max(teamspec.extent(0), + teamspec.extent(1)); + params.tile[0] = sizespec.extent(0) / max_team_extent; + params.tile[1] = sizespec.extent(1) / max_team_extent; + } + if (params.type == "summa") { + auto pattern = make_summa_pattern(params, sizespec, teamspec); + std::cout << "Pattern type:\n " + << pattern_to_string(pattern) << std::endl; + } else if (params.type == "block") { + auto pattern = make_block_pattern(params, sizespec, teamspec); + std::cout << "Pattern type:\n " + << pattern_to_string(pattern) << std::endl; + } else if (params.type == "tile") { + auto pattern = make_tile_pattern(params, sizespec, teamspec); + std::cout << "Pattern type:\n " + << pattern_to_string(pattern) << std::endl; + } else if (params.type == "shift") { + auto pattern = make_shift_tile_pattern(params, sizespec, teamspec); + std::cout << "Pattern type:\n " + << pattern_to_string(pattern) << std::endl; + } else if (params.type == "seq") { + auto pattern = make_seq_tile_pattern(params, sizespec, teamspec); + std::cout << "Pattern type:\n " + << pattern_to_string(pattern) << std::endl; + } else { + print_usage(argv); + exit(EXIT_FAILURE); + } + } catch (std::exception & excep) { + std::cerr << excep.what() << std::endl; + } + } + dash::finalize(); + return EXIT_SUCCESS; +} + diff --git a/dash/examples/ex.06.pattern-block-visualizer/main.cpp b/dash/examples/ex.06.pattern-block-visualizer/main.cpp index c91e3116e..8d7d6ad7f 100644 --- a/dash/examples/ex.06.pattern-block-visualizer/main.cpp +++ b/dash/examples/ex.06.pattern-block-visualizer/main.cpp @@ -19,10 +19,13 @@ #include #include +#include // needed for basename() #include +#include "../util.h" + using std::cout; using std::cerr; @@ -66,6 +69,7 @@ void print_usage(char **argv); static cli_params parse_args(int argc, char * argv[]); + static void print_params(const cli_params & params); @@ -214,9 +218,10 @@ int main(int argc, char* argv[]) dash::init(&argc, &argv); auto params = parse_args(argc, argv); - print_params(params); if (dash::myid() == 0) { + print_params(params); + try { dash::SizeSpec<2, extent_t> sizespec(params.size_y, params.size_x); dash::TeamSpec<2, index_t> teamspec(params.units_y, params.units_x); @@ -360,41 +365,6 @@ void print_params(const cli_params & params) << endl; } -/** - * Create string describing of pattern instance. - */ -template -static -std::string pattern_to_string( - const PatternType & pattern) -{ - typedef typename PatternType::index_type index_t; - - dim_t ndim = pattern.ndim(); - - std::string storage_order = pattern.memory_order() == ROW_MAJOR - ? "ROW_MAJOR" - : "COL_MAJOR"; - - std::array blocksize; - blocksize[0] = pattern.blocksize(0); - blocksize[1] = pattern.blocksize(1); - - std::ostringstream ss; - ss << "dash::" - << PatternType::PatternName - << "<" - << ndim << "," - << storage_order << "," - << typeid(index_t).name() - << ">(" << endl - << " SizeSpec: " << pattern.sizespec().extents() << "," << endl - << " TeamSpec: " << pattern.teamspec().extents() << "," << endl - << " BlockSpec: " << pattern.blockspec().extents() << "," << endl - << " BlockSize: " << blocksize << " )"; - - return ss.str(); -} /** * Create filename describing of pattern instance. diff --git a/dash/examples/pattern_params.h b/dash/examples/pattern_params.h new file mode 100644 index 000000000..3645b34c6 --- /dev/null +++ b/dash/examples/pattern_params.h @@ -0,0 +1,211 @@ +#ifndef DASH__EXAMPLES__PATTERN_PARAMS_H__INCLUDED +#define DASH__EXAMPLES__PATTERN_PARAMS_H__INCLUDED + +typedef dash::default_extent_t extent_t; +typedef dash::default_index_t index_t; + +typedef struct cli_params_t { + std::string type = "tile"; + std::array size {{ 12, 12 }}; + std::array tile {{ 3, 4 }}; + std::array units; + bool blocked_display = false; + bool balance_extents = false; + bool cout = false; +} cli_params; + +cli_params default_params; + +void print_usage(char **argv); +cli_params parse_args(int argc, char * argv[]); +void print_params(const cli_params & params); + + +cli_params parse_args(int argc, char * argv[], const cli_params & defaults) +{ + cli_params params = defaults; + + for (auto i = 1; i < argc; i += 3) { + std::string flag = argv[i]; + if (flag == "-h") { + print_usage(argv); + exit(EXIT_SUCCESS); + } + if (flag == "-s") { + params.type = argv[i+1]; + i -= 1; + } else if (flag == "-n") { + params.size = { static_cast(atoi(argv[i+1])), + static_cast(atoi(argv[i+2])) }; + } else if (flag == "-u") { + params.units = { static_cast(atoi(argv[i+1])), + static_cast(atoi(argv[i+2])) }; + } else if (flag == "-t") { + params.tile = { static_cast(atoi(argv[i+1])), + static_cast(atoi(argv[i+2])) }; + } else if (flag == "-b") { + params.balance_extents = true; + i -= 2; + } else { + print_usage(argv); + exit(EXIT_FAILURE); + } + } + return params; +} + +cli_params parse_args(int argc, char * argv[]) { + return parse_args(argc, argv, default_params); +} + +void print_usage(char **argv) +{ + if (dash::myid() == 0) { + std::cerr << "Usage: \n" + << basename(argv[0]) << " " + << "-h | " + << "[-s pattern] " + << "[-n size_spec] " + << "[-u unit_spec] " + << "[-t tile_spec] " + << "[-p] " + << "\n\n"; + std::cerr << "-s pattern: [summa|block|tile|seq|shift]\n" + << "-n size_spec: [ " + << default_params.size[0] << " " << default_params.size[1] << " ]\n" + << "-u unit_spec: [ " + << default_params.units[0] << " " << default_params.units[1] << " ]\n" + << "-t tile_spec: [ automatically determined ]\n" + << "-p : print to stdout instead of stderr\n" + << "-h : print help and exit" + << std::endl; + } +} + +void print_params(const cli_params & params) +{ + int w_size = std::log10(std::max(params.size[0], params.size[1])); + int w_units = std::log10(std::max(params.units[0], params.units[1])); + int w_tile = std::log10(std::max(params.tile[0], params.tile[1])); + int w = std::max({ w_size, w_units, w_tile }) + 1; + + std::cerr << "Parameters:\n" + << " type (-s): " << params.type + << '\n' + << " size (-n ): ( " + << std::fixed << std::setw(w) << params.size[0] << ", " + << std::fixed << std::setw(w) << params.size[1] << " )" + << '\n' + << " team (-u ): ( " + << std::fixed << std::setw(w) << params.units[0] << ", " + << std::fixed << std::setw(w) << params.units[1] << " )" + << '\n' + << " balance extents (-e): " + << (params.balance_extents ? "yes" : "no") + << '\n' + << " tile (-t ): ( " + << std::fixed << std::setw(w) << params.tile[0] << ", " + << std::fixed << std::setw(w) << params.tile[1] << " )" + << '\n' + << std::endl; +} + +dash::TilePattern<2, dash::ROW_MAJOR, index_t> +make_summa_pattern( + const cli_params & params, + const dash::SizeSpec<2, extent_t> & sizespec, + const dash::TeamSpec<2, index_t> & teamspec) +{ + auto pattern = dash::make_pattern< + dash::summa_pattern_partitioning_constraints, + dash::summa_pattern_mapping_constraints, + dash::summa_pattern_layout_constraints >( + sizespec, + teamspec); + + if (params.tile[1] >= 0 || params.tile[0] >= 0) { + // change tile sizes of deduced pattern: + typedef decltype(pattern) pattern_t; + pattern_t custom_pattern(sizespec, + dash::DistributionSpec<2>( + params.tile[0] > 0 + ? dash::TILE(params.tile[0]) + : dash::NONE, + params.tile[1] > 0 + ? dash::TILE(params.tile[1]) + : dash::NONE), + teamspec); + pattern = custom_pattern; + } + return pattern; +} + +dash::ShiftTilePattern<2, dash::ROW_MAJOR, index_t> +make_shift_tile_pattern( + const cli_params & params, + const dash::SizeSpec<2, extent_t> & sizespec, + const dash::TeamSpec<2, index_t> & teamspec) +{ + // Example: -n 1680 1680 -u 28 1 -t 60 60 + typedef dash::ShiftTilePattern<2> pattern_t; + pattern_t pattern(sizespec, + dash::DistributionSpec<2>( + dash::TILE(params.tile[0]), + dash::TILE(params.tile[1])), + teamspec); + return pattern; +} + +dash::SeqTilePattern<2, dash::ROW_MAJOR, index_t> +make_seq_tile_pattern( + const cli_params & params, + const dash::SizeSpec<2, extent_t> & sizespec, + const dash::TeamSpec<2, index_t> & teamspec) +{ + // Example: -n 30 30 -u 4 1 -t 10 10 + typedef dash::SeqTilePattern<2> pattern_t; + pattern_t pattern(sizespec, + dash::DistributionSpec<2>( + dash::TILE(params.tile[0]), + dash::TILE(params.tile[1])), + teamspec); + return pattern; +} + +dash::TilePattern<2, dash::ROW_MAJOR, index_t> +make_tile_pattern( + const cli_params & params, + const dash::SizeSpec<2, extent_t> & sizespec, + const dash::TeamSpec<2, index_t> & teamspec) +{ + // Example: -n 30 30 -u 4 1 -t 10 10 + typedef dash::TilePattern<2> pattern_t; + pattern_t pattern(sizespec, + dash::DistributionSpec<2>( + dash::TILE(params.tile[0]), + dash::TILE(params.tile[1])), + teamspec); + return pattern; +} + +dash::Pattern<2, dash::ROW_MAJOR, index_t> +make_block_pattern( + const cli_params & params, + const dash::SizeSpec<2, extent_t> & sizespec, + const dash::TeamSpec<2, index_t> & teamspec) +{ + // Example: -n 30 30 -u 4 1 -t 10 10 + typedef dash::Pattern<2> pattern_t; + pattern_t pattern(sizespec, + dash::DistributionSpec<2>( + (params.tile[0] > 0 + ? dash::BLOCKCYCLIC(params.tile[0]) + : dash::NONE), + (params.tile[1] > 0 + ? dash::BLOCKCYCLIC(params.tile[1]) + : dash::NONE)), + teamspec); + return pattern; +} + +#endif // DASH__EXAMPLES__PATTERN_PARAMS_H__INCLUDED diff --git a/dash/examples/util.h b/dash/examples/util.h new file mode 100644 index 000000000..2248dbe6c --- /dev/null +++ b/dash/examples/util.h @@ -0,0 +1,158 @@ +#ifndef DASH__EXAMPLES__UTIL_H__INCLUDED +#define DASH__EXAMPLES__UTIL_H__INCLUDED + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + + +#define print(stream_expr__) \ + do { \ + std::ostringstream mss; \ + mss << stream_expr__; \ + std::ostringstream oss; \ + std::istringstream iss(mss.str()); \ + std::string item; \ + while (std::getline(iss, item)) { \ + DASH_LOG_DEBUG("print", item); \ + oss << "[ U:" << dash::myid() << " ] "; \ + oss << item << std::endl; \ + } \ + std::cout << oss.str(); \ + } while(0) + +#define STEP(stream_m__) do { \ + if (dash::myid() == 0) { \ + std::cin.ignore(); \ + } \ + print(stream_m__); \ +} while(0) + + +using namespace dash; +using namespace dash::internal::logging; + +template +static std::string range_str( + const ValueRange & vrange, + int prec = 2) { + typedef typename ValueRange::value_type value_t; + std::ostringstream ss; + int i = 0; + for (const auto & v : vrange) { + const value_t val = v; + ss << std::setw(2 + prec) << std::right + << std::fixed << std::setprecision(prec) + << TermColorMod(unit_term_colors[(int)val]) + << val + << TermColorMod(TCOL_DEFAULT); + ++i; + } + return ss.str(); +} + +template +std::string nview_str( + const NViewType & nview, + int prec = 2) +{ + using value_t = typename NViewType::value_type; + const auto view_nrows = nview.extents()[0]; + const auto view_ncols = nview.extents()[1]; + const auto nindex = dash::index(nview); + std::ostringstream ss; + + for (int r = 0; r < view_nrows; ++r) { + ss << "\n "; + for (int c = 0; c < view_ncols; ++c) { + int offset = r * view_ncols + c; + value_t val = nview.begin()[offset]; + ss << std::fixed << std::setw(3) + << nindex[offset] + << TermColorMod(unit_term_colors[(int)val]) + << " " + << std::fixed << std::setprecision(prec) << val + << " " + << TermColorMod(TCOL_DEFAULT); + } + } + return ss.str(); +} + +template +std::string nviewrc_str( + const NViewType & nview, + int prec = 2) +{ + using value_t = typename NViewType::value_type; + const auto view_nrows = nview.extents()[0]; + const auto view_ncols = nview.extents()[1]; + const auto nindex = dash::index(nview); + std::ostringstream ss; + + ss << "\n "; + for (int c = 0; c < view_ncols; ++c) { + ss << std::setw(8 + prec) << std::left << c; + } + for (int r = 0; r < view_nrows; ++r) { + ss << '\n' << std::right << std::setw(3) << r << " "; + for (int c = 0; c < view_ncols; ++c) { + int offset = r * view_ncols + c; + value_t val = nview.begin()[offset]; + ss << std::fixed << std::setw(3) + << nindex[offset] + << TermColorMod(unit_term_colors[(int)val]) + << " " + << std::fixed << std::setprecision(prec) << val + << " " + << TermColorMod(TCOL_DEFAULT); + } + } + return ss.str(); +} + +/** + * Create string describing of pattern instance. + */ +template +static +std::string pattern_to_string( + const PatternType & pattern) +{ + typedef typename PatternType::index_type index_t; + + dash::dim_t ndim = pattern.ndim(); + + std::string storage_order = pattern.memory_order() == dash::ROW_MAJOR + ? "ROW_MAJOR" + : "COL_MAJOR"; + + std::array blocksize; + blocksize[0] = pattern.blocksize(0); + blocksize[1] = pattern.blocksize(1); + + std::ostringstream ss; + ss << "dash::" + << PatternType::PatternName + << "<" + << ndim << "," + << storage_order << "," + << typeid(index_t).name() + << ">(\n" + << " SizeSpec: " << pattern.sizespec().extents() << ",\n" + << " TeamSpec: " << pattern.teamspec().extents() << ",\n" + << " BlockSpec: " << pattern.blockspec().extents() << ",\n" + << " BlockSize: " << blocksize << " )"; + + return ss.str(); +} + +#endif // DASH__EXAMPLES__UTIL_H__INCLUDED diff --git a/dash/include/dash/Array.h b/dash/include/dash/Array.h index 29b602d7d..1c9813ca9 100644 --- a/dash/include/dash/Array.h +++ b/dash/include/dash/Array.h @@ -286,8 +286,8 @@ class AsyncArrayRef typedef T * pointer; typedef const T * const_pointer; - typedef GlobAsyncRef async_reference; - typedef typename GlobAsyncRef::const_type const_async_reference; + typedef GlobAsyncRef< T> async_reference; + typedef GlobAsyncRef const_async_reference; public: typedef std::integral_constant @@ -363,7 +363,7 @@ class AsyncArrayRef * Subscript operator, access to local array element at given position. */ constexpr const_async_reference operator[](const size_type n) const { - return const_async_reference( + return async_reference( (*(_array->begin() + n)).dart_gptr()); } @@ -660,8 +660,8 @@ class Array typedef std::reverse_iterator< iterator> reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; - typedef GlobRef reference; - typedef typename GlobRef::const_type const_reference; + typedef GlobRef< value_type> reference; + typedef GlobRef const_reference; typedef GlobIter< value_type, PatternType> pointer; typedef GlobIter const_pointer; @@ -718,6 +718,8 @@ class Array private: /// Team containing all units interacting with the array dash::Team * m_team = nullptr; + /// DART id of the unit that created the array + team_unit_t m_myid; /// Element distribution pattern PatternType m_pattern; /// Global memory allocation and -access @@ -736,10 +738,18 @@ class Array ElementType * m_lbegin = nullptr; /// Native pointer past last local element in the array ElementType * m_lend = nullptr; - /// DART id of the unit that created the array - team_unit_t m_myid; - /// Whether or not the array was actually allocated - bool m_registered = false; + +public: +/* + Check requirements on element type + is_trivially_copyable is not implemented presently, and is_trivial + is too strict (e.g. fails on std::pair). + + static_assert(std::is_trivially_copyable::value, + "Element type must be trivially copyable"); + static_assert(std::is_trivial::value, + "Element type must be trivially copyable"); +*/ public: /** @@ -892,30 +902,7 @@ class Array * The pattern has to be movable or copyable * The underlying memory does not have to be movable (it might). */ - Array(self_t && other) - : local(this), - async(this), - m_team(other.m_team), - m_myid(other.m_myid), - m_pattern(std::move(other.m_pattern)), - m_globmem(std::move(other.m_globmem)), - m_begin(other.m_begin), - m_end(other.m_end), - m_size(other.m_size), - m_lsize(other.m_lsize), - m_lcapacity(other.m_lcapacity), - m_lbegin(other.m_lbegin), - m_lend(other.m_lend) { - - other.m_globmem = nullptr; - other.m_lbegin = nullptr; - other.m_lend = nullptr; - // Register deallocator of this array instance at the team - // instance that has been used to initialized it: - m_team->register_deallocator( - this, std::bind(&Array::deallocate, this)); - m_registered = true; - } + Array(self_t && other) = default; /** * Assignment operator is deleted to prevent unintentional copies of @@ -944,38 +931,7 @@ class Array * The pattern has to be movable or copyable * The underlying memory does not have to be movable (it might). */ - self_t & operator=(self_t && other) { - - if (this == &other) return *this; - - deallocate(); - - this->m_begin = other.m_begin; - this->m_end = other.m_end; - this->m_globmem = std::move(other.m_globmem); - this->m_lbegin = other.m_lbegin; - this->m_lcapacity = other.m_lcapacity; - this->m_lend = other.m_lend; - this->m_lsize = other.m_lsize; - this->m_myid = other.m_myid; - this->m_pattern = std::move(other.m_pattern); - this->m_size = other.m_size; - this->m_team = other.m_team; - - other.m_globmem = nullptr; - other.m_lbegin = nullptr; - other.m_lend = nullptr; - - // Re-register deallocator of this array instance at the team - // instance that has been used to initialized it: - if (this->m_globmem != nullptr) { - m_team->register_deallocator( - this, std::bind(&Array::deallocate, this)); - m_registered = true; - } - - return *this; - } + self_t & operator=(self_t && other) = default; /** * Destructor, deallocates array elements. @@ -1374,10 +1330,8 @@ class Array } // Remove this function from team deallocator list to avoid // double-free: - if (m_registered) { - m_team->unregister_deallocator( - this, std::bind(&Array::deallocate, this)); - } + m_team->unregister_deallocator( + this, std::bind(&Array::deallocate, this)); // Actual destruction of the array instance: DASH_LOG_TRACE_VAR("Array.deallocate()", m_globmem.get()); if (m_globmem != nullptr) { @@ -1427,7 +1381,6 @@ class Array // instance that has been used to initialized it: m_team->register_deallocator( this, std::bind(&Array::deallocate, this)); - m_registered = true; // Assure all units are synchronized after allocation, otherwise // other units might start working on the array before allocation // completed at all units: @@ -1478,7 +1431,6 @@ class Array // instance that has been used to initialized it: m_team->register_deallocator( this, std::bind(&Array::deallocate, this)); - m_registered = true; // Assure all units are synchronized after allocation, otherwise // other units might start working on the array before allocation // completed at all units: diff --git a/dash/include/dash/Cartesian.h b/dash/include/dash/Cartesian.h index 8ed374ecb..420aa2eeb 100644 --- a/dash/include/dash/Cartesian.h +++ b/dash/include/dash/Cartesian.h @@ -6,6 +6,8 @@ #include #include +#include + #include #include #include @@ -251,16 +253,16 @@ class CartesianIndexSpace typedef SizeType size_type; typedef std::array extents_type; - template + template friend std::ostream & operator<<( - std::ostream & os, - const CartesianIndexSpace & cartesian_space); + std::ostream & os, + const CartesianIndexSpace & cartesian_space); protected: /// Number of elements in the cartesian space spanned by this instance. SizeType _size = 0; /// Number of dimensions in the cartesian space. - SizeType _rank = NumDimensions; + SizeType _rank = 0; /// Extents of the cartesian space by dimension. extents_type _extents = { }; /// Cumulative index offsets of the index space by dimension respective @@ -348,12 +350,10 @@ class CartesianIndexSpace */ template void resize(SizeType arg, Args... args) { - static_assert( - sizeof...(Args) == NumDimensions-1, - "Invalid number of arguments"); - std::array extents = - {{ arg, (SizeType)(args)... }}; - resize(extents); + resize( + std::array {{ + arg, (SizeType)(args)... + }} ); } /** @@ -363,9 +363,18 @@ class CartesianIndexSpace void resize(const std::array & extents) { // Update size: _size = 1; + _rank = 0; for(auto i = 0; i < NumDimensions; i++ ) { _extents[i] = static_cast(extents[i]); _size *= _extents[i]; + if (_extents[i] > 1) { + ++_rank; + } + } + if (_size == 0) { + _rank = 0; + } else if (_rank == 0) { + _rank = 1; } // Update offsets: _offset_row_major[NumDimensions-1] = 1; @@ -467,6 +476,7 @@ class CartesianIndexSpace return offs; } + /** * Convert the given cartesian point to a linear index, respective to * the offsets specified in the given ViewSpec. @@ -489,6 +499,28 @@ class CartesianIndexSpace return at(coords); } + /** + * Convert the given cartesian point to a linear index, respective to + * the specified offsets. + * + * \param point An array containing the coordinates, ordered by + * dimension (x, y, z, ...) + * \param offsets Offsets to apply on point coordinates + * before resolving the linear index. + */ + template< + MemArrange AtArrangement = Arrangement, + typename OffsetType> + IndexType at( + const std::array & point, + const std::array & offsets) const { + std::array coords; + for (auto d = 0; d < NumDimensions; ++d) { + coords[d] = point[d] + offsets[d]; + } + return at(coords); + } + /** * Convert given linear offset (index) to cartesian coordinates. * Inverse of \c at(...). @@ -766,6 +798,33 @@ class LocalMemoryLayout : return at(coords); } + /** + * Convert the given cartesian point to a linear index, respective to + * the specified offsets. + * + * \param point An array containing the coordinates, ordered by + * dimension (x, y, z, ...) + * \param offsets Offsets to apply on point coordinates + * before resolving the linear index. + */ + template< + MemArrange AtArrangement = Arrangement, + typename OffsetType> + IndexType at( + const std::array & point, + const std::array & offsets) const { + std::array coords; + for (auto d = 0; d < NumDimensions; ++d) { + coords[d] = point[d] + offsets[d]; + } + if (!_distspec.is_tiled()) { + // Default case, no tiles + return parent_t::at(coords); + } + // Tiles in at least one dimension + return at(coords); + } + /** * Convert given linear offset (index) to cartesian coordinates. * Inverse of \c at(...). @@ -805,17 +864,16 @@ std::ostream & operator<<( return operator<<(os, ss.str()); } -template < - dash::dim_t NumDimensions > +template std::ostream & operator<<( - std::ostream & os, - const dash::CartesianIndexSpace & cartesian_space) + std::ostream & os, + const CartesianIndexSpace & cartesian_space) { std::ostringstream ss; ss << dash::typestr(cartesian_space) << ": " << "extents("; - for (auto dim = 0; dim < NumDimensions; ++dim) { + for (auto dim = 0; dim < NDim_; ++dim) { if (dim > 0) { ss << ","; } diff --git a/dash/include/dash/Dimensional.h b/dash/include/dash/Dimensional.h index f58984327..e54b5b230 100644 --- a/dash/include/dash/Dimensional.h +++ b/dash/include/dash/Dimensional.h @@ -57,6 +57,7 @@ constexpr dim_t ndim(const DimensionalType & d) { return d.ndim(); } +#if 0 /** * \concept{DashDimensionalConcept} */ @@ -64,6 +65,7 @@ template constexpr dim_t rank(const DimensionalType & d) { return d.rank(); } +#endif /** * \concept{DashDimensionalConcept} @@ -343,368 +345,6 @@ std::ostream & operator<<( return os; } -/** - * Offset and extent in a single dimension. - */ -template -struct ViewPair { - typedef typename std::make_unsigned::type SizeType; - /// Offset in dimension. - IndexType offset; - /// Extent in dimension. - SizeType extent; -}; - -/** - * Representation of a ViewPair as region specified by origin and end - * coordinates. - */ -template< - dim_t NumDimensions, - typename IndexType = dash::default_index_t> -struct ViewRegion { - // Region origin coordinates. - std::array begin; - // Region end coordinates. - std::array end; -}; - -template< - typename IndexType = dash::default_index_t> -struct ViewRange { - // Range begin offset. - IndexType begin; - // Range end offset. - IndexType end; -}; - -template -std::ostream & operator<<( - std::ostream & os, - const ViewRange & viewrange) { - os << "dash::ViewRange<" << typeid(IndexType).name() << ">(" - << "begin:" << viewrange.begin << " " - << "end:" << viewrange.end << ")"; - return os; -} - -/** - * Equality comparison operator for ViewPair. - */ -template -static bool operator==( - const ViewPair & lhs, - const ViewPair & rhs) { - if (&lhs == &rhs) { - return true; - } - return ( - lhs.offset == rhs.offset && - lhs.extent == rhs.extent); -} - -/** - * Inequality comparison operator for ViewPair. - */ -template -static bool operator!=( - const ViewPair & lhs, - const ViewPair & rhs) { - return !(lhs == rhs); -} - -template -std::ostream & operator<<( - std::ostream & os, - const ViewPair & viewpair) { - os << "dash::ViewPair<" << typeid(IndexType).name() << ">(" - << "offset:" << viewpair.offset << " " - << "extent:" << viewpair.extent << ")"; - return os; -} - -/** - * Specifies view parameters for implementing submat, rows and cols - * - * \concept(DashCartesianSpaceConcept) - */ -template< - dim_t NumDimensions, - typename IndexType = dash::default_index_t > -class ViewSpec -{ -private: - typedef ViewSpec - self_t; - typedef typename std::make_unsigned::type - SizeType; - typedef ViewPair - ViewPair_t; - -public: - typedef ViewRegion region_type; - typedef ViewRange range_type; - -public: - template - friend std::ostream& operator<<( - std::ostream & os, - const ViewSpec & viewspec); - -private: - SizeType _size = 0; - SizeType _rank = NumDimensions; - std::array _extents = {{ }}; - std::array _offsets = {{ }}; - -public: - /** - * Default constructor, initialize with extent and offset 0 in all - * dimensions. - */ - ViewSpec() - : _size(0), - _rank(NumDimensions) - { - for (dim_t i = 0; i < NumDimensions; i++) { - _extents[i] = 0; - _offsets[i] = 0; - } - } - - /** - * Constructor, initialize with given extents and offset 0 in all - * dimensions. - */ - ViewSpec( - const std::array & extents) - : _size(1), - _rank(NumDimensions), - _extents(extents) - { - for (auto i = 0; i < NumDimensions; ++i) { - _offsets[i] = 0; - _size *= _extents[i]; - } - } - - /** - * Constructor, initialize with given extents and offsets. - */ - ViewSpec( - const std::array & offsets, - const std::array & extents) - : _size(1), - _rank(NumDimensions), - _extents(extents), - _offsets(offsets) - { - for (auto i = 0; i < NumDimensions; ++i) { - _size *= _extents[i]; - } - } - - /** - * Copy constructor. - */ - constexpr ViewSpec(const self_t & other) = default; - - /** - * Move constructor. - */ - constexpr ViewSpec(self_t && other) = default; - - /** - * Assignment operator. - */ - self_t & operator=(const self_t & other) = default; - - /** - * Move-assignment operator. - */ - self_t & operator=(self_t && other) = default; - - /** - * Equality comparison operator. - */ - constexpr bool operator==(const self_t & other) const - { - return (_extents == other._extents && - _offsets == other._offsets && - _rank == other._rank); - } - - /** - * Equality comparison operator. - */ - constexpr bool operator!=(const self_t & other) const - { - return !(*this == other); - } - - /** - * Change the view specification's extent in every dimension. - */ - template - void resize(SizeType arg, Args... args) - { - static_assert( - sizeof...(Args) == (NumDimensions-1), - "Invalid number of arguments"); - std::array extents = - { arg, (SizeType)(args)... }; - resize(extents); - } - - /** - * Change the view specification's extent and offset in every dimension. - */ - void resize(const std::array & view) - { - _rank = NumDimensions; - for (dim_t i = 0; i < NumDimensions; i++) { - _offsets[i] = view[i].offset; - _extents[i] = view[i].extent; - } - update_size(); - } - - /** - * Change the view specification's extent in every dimension. - */ - template - void resize(const std::array & extents) - { - _rank = NumDimensions; - for (dim_t i = 0; i < NumDimensions; i++) { - _extents[i] = extents[i]; - } - update_size(); - } - - /** - * Change the view specification's extent and offset in the - * given dimension. - */ - void resize_dim( - dim_t dimension, - IndexType offset, - SizeType extent) - { - _offsets[dimension] = offset; - _extents[dimension] = extent; - update_size(); - } - - /** - * Slice the view in the specified dimension at the given offset. - * This is different from resizing the dimension to extent 1 - * (\c resize_dim) which does not affect the view dimensionality or - * rank. - * Slicing removes the specified dimension and reduces the view - * dimensionality by 1. - * - * All dimensions higher than the sliced dimension are projected - * downwards. - * Example: - * - * dimensions: 0 1 2 3 - * : : : : - * extents: 3 4 5 6 - * | - * slice_dim(1, 2) - * | - * v - * dimensions: 0 x 1 2 - * : : : - * extents: 3 5 6 - * - * \return A copy if this view spec as a new instance of `ViewSpec` - * with the sliced dimension removed - */ - ViewSpec - slice(dim_t dimension) - { - std::array slice_extents; - std::array slice_offsets; - for (dim_t d = dimension; d < _rank-1; d++) { - slice_offsets[d] = _offsets[d+1]; - slice_extents[d] = _extents[d+1]; - } - return ViewSpec(slice_offsets, - slice_extents); - } - - /** - * Set rank of the view spec to a dimensionality between 1 and - * \c NumDimensions. - */ - void set_rank(dim_t dimensions) - { - DASH_ASSERT_LT( - dimensions, NumDimensions+1, - "Maximum dimension for ViewSpec::set_rank is " << NumDimensions); - _rank = dimensions; - update_size(); - } - - constexpr SizeType size() const - { - return _size; - } - - constexpr SizeType size(dim_t dimension) const - { - return _extents[dimension]; - } - - constexpr const std::array & extents() const - { - return _extents; - } - - constexpr SizeType extent(dim_t dim) const { - return _extents[dim]; - } - - constexpr const std::array & offsets() const - { - return _offsets; - } - - constexpr range_type range(dim_t dim) const - { - return range_type { - static_cast(_offsets[dim]), - static_cast(_offsets[dim] + _extents[dim]) }; - } - - constexpr IndexType offset(dim_t dim) const - { - return _offsets[dim]; - } - - region_type region() const - { - region_type reg; - reg.begin = _offsets; - reg.end = _offsets; - for (dim_t d = 0; d < NumDimensions; ++d) { - reg.end[d] += static_cast(_extents[d]); - } - return reg; - } - -private: - void update_size() - { - _size = 1; - for (SizeType d = 0; d < NumDimensions; ++d) { - _size *= _extents[d]; - } - } -}; - template std::ostream & operator<<( std::ostream & os, @@ -721,31 +361,6 @@ std::ostream & operator<<( return operator<<(os, ss.str()); } -template -std::ostream& operator<<( - std::ostream & os, - const ViewSpec & viewspec) -{ - std::ostringstream ss; - ss << "dash::ViewSpec<" << NumDimensions << ">" - << "(offsets:"; - for (auto d = 0; d < NumDimensions; ++d) { - if (d > 0) { - ss << ","; - } - ss << viewspec.offsets()[d]; - } - ss << " extents:"; - for (auto d = 0; d < NumDimensions; ++d) { - if (d > 0) { - ss << ","; - } - ss << viewspec.extents()[d]; - } - ss << ")"; - return operator<<(os, ss.str()); -} - } // namespace dash #endif // DASH__DIMENSIONAL_H_ diff --git a/dash/include/dash/Exception.h b/dash/include/dash/Exception.h index 71c01e797..814d7f864 100644 --- a/dash/include/dash/Exception.h +++ b/dash/include/dash/Exception.h @@ -1,6 +1,9 @@ #ifndef DASH__EXCEPTION_H_ #define DASH__EXCEPTION_H_ +#include +#include + #include #include #include @@ -8,10 +11,11 @@ #include #include -#include -#include +#include #include +#include + #define DASH_STACK_TRACE() do { \ dash__print_stacktrace(); \ @@ -22,6 +26,7 @@ os << "[ Unit " << dash::myid() << " ] "; \ os << msg_stream; \ DASH_LOG_ERROR(dash__toxstr(excep_type), os.str()); \ + DASH_STACK_TRACE(); \ throw(excep_type(os.str())); \ } while(0) diff --git a/dash/include/dash/GlobAsyncRef.h b/dash/include/dash/GlobAsyncRef.h index f1570bd7a..d80137093 100644 --- a/dash/include/dash/GlobAsyncRef.h +++ b/dash/include/dash/GlobAsyncRef.h @@ -9,20 +9,6 @@ namespace dash { - -template -struct add_const_from_type -{ - using type = TargetT; -}; - -template -struct add_const_from_type -{ - using type = typename std::add_const::type; -}; - - /** * Global value reference for asynchronous / non-blocking operations. * @@ -60,20 +46,24 @@ class GlobAsyncRef friend class GlobAsyncRef; public: - using value_type = T; - using const_value_type = typename std::add_const::type; - using nonconst_value_type = typename std::remove_const::type; - using self_t = GlobAsyncRef; - using const_type = GlobAsyncRef; - using nonconst_type = GlobAsyncRef; + typedef GlobAsyncRef + self_t; + + typedef T value_type; + + typedef typename std::remove_const::type + nonconst_value_type; + + typedef typename std::add_const::type + const_value_type; private: /// Pointer to referenced element in global memory dart_gptr_t _gptr; /// Temporary value required for non-blocking put - mutable nonconst_value_type _value; + nonconst_value_type _value; /// DART handle for asynchronous transfers - mutable dart_handle_t _handle = DART_HANDLE_NULL; + dart_handle_t _handle = DART_HANDLE_NULL; private: @@ -117,13 +107,14 @@ class GlobAsyncRef { } /** - * Conctructor, creates an GlobRefAsync object referencing an element in - * global memory. + * Constructor, creates an GlobRef object referencing an element in global + * memory. */ + template explicit GlobAsyncRef( /// Pointer to referenced object in global memory - const GlobRef & gref) - : GlobAsyncRef(gref.dart_gptr()) + const GlobConstPtr & gptr) + : GlobAsyncRef(gptr.dart_gptr()) { } /** @@ -132,31 +123,9 @@ class GlobAsyncRef */ explicit GlobAsyncRef( /// Pointer to referenced object in global memory - const GlobRef & gref) + const GlobRef & gref) : GlobAsyncRef(gref.dart_gptr()) - { - static_assert(std::is_same::value, - "Cannot create GlobAsyncRef from GlobRef!"); - } - - /** - * Implicit conversion to const. - */ - template::value,void>> - operator GlobAsyncRef() { - return GlobAsyncRef(_gptr); - } - - /** - * Excpliti conversion to non-const. - */ - template::value,void>> - explicit - operator GlobAsyncRef() { - return GlobAsyncRef(_gptr); - } + { } /** * Like native references, global reference types cannot be copied. @@ -190,28 +159,24 @@ class GlobAsyncRef * specified offset */ template - GlobAsyncRef::type> - member(size_t offs) const { - return GlobAsyncRef::type>(*this, offs); + GlobAsyncRef member(size_t offs) const { + return GlobAsyncRef(*this, offs); } /** * Get the member via pointer to member */ template - GlobAsyncRef::type> - member( + GlobAsyncRef member( const MEMTYPE P::*mem) const { size_t offs = (size_t) &( reinterpret_cast(0)->*mem); - return member::type>(offs); + return member(offs); } /** * Swap values with synchronous reads and asynchronous writes. */ friend void swap(self_t & a, self_t & b) { - static_assert(std::is_same::value, - "Cannot swap GlobAsyncRef!"); nonconst_value_type temp = a->get(); a = b->get(); b = temp; @@ -254,9 +219,7 @@ class GlobAsyncRef * This operation is guaranteed to be complete after a call to \ref flush * and the pointer \c tptr should not be reused before completion. */ - void set(const_value_type* tptr) const { - static_assert(std::is_same::value, - "Cannot modify value through GlobAsyncRef!"); + void set(const_value_type* tptr) { DASH_LOG_TRACE_VAR("GlobAsyncRef.set()", *tptr); DASH_LOG_TRACE_VAR("GlobAsyncRef.set()", _gptr); dash::internal::put(_gptr, tptr, 1); @@ -268,9 +231,7 @@ class GlobAsyncRef * This operation is guaranteed to be complete after a call to \ref flush, * but the value referenced by \c new_value can be re-used immediately. */ - void set(const_value_type& new_value) const { - static_assert(std::is_same::value, - "Cannot modify value through GlobAsyncRef!"); + void set(const_value_type& new_value) { DASH_LOG_TRACE_VAR("GlobAsyncRef.set()", new_value); DASH_LOG_TRACE_VAR("GlobAsyncRef.set()", _gptr); _value = new_value; @@ -289,8 +250,8 @@ class GlobAsyncRef * This operation is guaranteed to be complete after a call to \ref flush, * but the value referenced by \c new_value can be re-used immediately. */ - const self_t & - operator=(const_value_type & new_value) const + self_t & + operator=(const_value_type & new_value) { set(new_value); return *this; @@ -315,7 +276,7 @@ class GlobAsyncRef /** * Flush all pending asynchronous operations on this asynchronous reference. */ - void flush() const + void flush() { DASH_ASSERT_RETURNS( dart_flush(_gptr), diff --git a/dash/include/dash/GlobPtr.h b/dash/include/dash/GlobPtr.h index e69612750..c461b6ab2 100644 --- a/dash/include/dash/GlobPtr.h +++ b/dash/include/dash/GlobPtr.h @@ -50,14 +50,6 @@ template class GlobConstPtr; template class GlobPtr; -template -dash::gptrdiff_t distance( - const GlobPtr & gbegin, - const GlobPtr & gend); - /** * Pointer in global memory space with random access arithmetics. * @@ -84,7 +76,11 @@ class GlobPtr typedef typename MemorySpace::index_type index_type; typedef typename MemorySpace::size_type size_type; + typedef value_type * local_type; + typedef self_t global_type; + typedef index_type gptrdiff_t; + typedef index_type difference_type; public: template @@ -95,14 +91,6 @@ class GlobPtr std::ostream & os, const GlobPtr & gptr); - template - friend dash::gptrdiff_t dash::distance( - const GlobPtr & gptr_begin, - const GlobPtr & gptr_end); - public: /// Convert GlobPtr to GlobPtr. template @@ -281,10 +269,57 @@ class GlobPtr /** * Pointer offset difference operator. + * + * Defined with independent value types allow calculation + * of distance between \c GlobPtr and \c GlobPtr. + * Refernced value types must have identical size. + * + * \todo + * Validate compatibility of memory space types using memory space traits + * once they are available. + * + * \return Global pointer distance between the first and second + * global pointer, corresponds to pointer distance + * \c (gend - gbegin) + * + * \concept{DashMemorySpaceConcept} */ - constexpr index_type operator-(const self_t & rhs) const noexcept + template + difference_type operator-( + const GlobPtr & rhs) const noexcept { - return dash::distance(rhs, *this); + using val_type_b = typename std::decay::type::value_type; + using val_type_e = value_type; + + static_assert( + sizeof(val_type_b) == sizeof(val_type_e), + "value types of global pointers are not compatible for dash::distance"); + + // Both pointers in same unit space: + if (rhs._rbegin_gptr.unitid == _rbegin_gptr.unitid || + rhs._mem_space == nullptr) { + return ( _rbegin_gptr.addr_or_offs.offset - + rhs._rbegin_gptr.addr_or_offs.offset ) + / sizeof(value_type); + } + // If unit of begin pointer is after unit of end pointer, + // return negative distance with swapped argument order: + if (rhs._rbegin_gptr.unitid > _rbegin_gptr.unitid) { + return -(rhs - *this); + } + // Pointers span multiple unit spaces, accumulate sizes of + // local unit memory ranges in the pointer range: + index_type dist = rhs._mem_space->local_size( + dart_team_unit_t { rhs.dart_gptr().unitid }) + - (rhs.dart_gptr().addr_or_offs.offset + / sizeof(value_type)) + + (dart_gptr().addr_or_offs.offset + / sizeof(value_type)); + for (int u = rhs.dart_gptr().unitid+1; + u < dart_gptr().unitid; ++u) { + dist += _mem_space->local_size(dart_team_unit_t { u }); + } + return dist; } /** @@ -597,6 +632,9 @@ class GlobConstPtr typedef typename base_t::index_type index_type; typedef typename base_t::gptrdiff_t gptrdiff_t; + typedef value_type * local_type; + typedef self_t global_type; + template friend std::ostream & operator<<( std::ostream & os, @@ -782,70 +820,6 @@ std::ostream & operator<<( #endif // DOXYGEN -/** - * Specialization of \c dash::distance for \c dash::GlobPtr as default - * definition of pointer distance in global memory spaces. - * - * Equivalent to \c (gend - gbegin). - * - * \note - * Defined with independent value types T1 and T2 to allow calculation - * of distance between \c GlobPtr and \c GlobPtr. - * The pointer value types must have identical size. - * - * \todo - * Validate compatibility of memory space types using memory space traits - * once they are available. - * - * \return Number of elements in the range between the first and second - * global pointer - * - * \concept{DashMemorySpaceConcept} - */ -template -dash::gptrdiff_t distance( - // First global pointer in range - const GlobPtr & gbegin, - // Final global pointer in range - const GlobPtr & gend) { - using index_type = dash::gptrdiff_t; - using val_type_b = typename std::decay::type::value_type; - using val_type_e = typename std::decay::type::value_type; - using value_type = val_type_b; - - static_assert( - sizeof(val_type_b) == sizeof(val_type_e), - "value types of global pointers are not compatible for dash::distance"); - - // Both pointers in same unit space: - if (gbegin._rbegin_gptr.unitid == gend._rbegin_gptr.unitid || - gbegin._mem_space == nullptr) { - return ( gend._rbegin_gptr.addr_or_offs.offset - - gbegin._rbegin_gptr.addr_or_offs.offset ) - / sizeof(value_type); - } - // If unit of begin pointer is after unit of end pointer, - // return negative distance with swapped argument order: - if (gbegin._rbegin_gptr.unitid > gend._rbegin_gptr.unitid) { - return -(dash::distance(gend, gbegin)); - } - // Pointers span multiple unit spaces, accumulate sizes of - // local unit memory ranges in the pointer range: - index_type dist = gbegin._mem_space->local_size( - dart_team_unit_t { gbegin.dart_gptr().unitid }) - - (gbegin.dart_gptr().addr_or_offs.offset - / sizeof(value_type)) - + (gend.dart_gptr().addr_or_offs.offset - / sizeof(value_type)); - for (int u = gbegin.dart_gptr().unitid+1; - u < gend.dart_gptr().unitid; ++u) { - dist += gend._mem_space->local_size(dart_team_unit_t { u }); - } - return dist; -} /** * Resolve the number of elements between two global pointers. diff --git a/dash/include/dash/GlobRef.h b/dash/include/dash/GlobRef.h index 6f7affc4a..2f22c03e5 100644 --- a/dash/include/dash/GlobRef.h +++ b/dash/include/dash/GlobRef.h @@ -38,13 +38,21 @@ class GlobRef typename ElementT > friend class GlobRef; + typedef typename std::remove_const::type + nonconst_value_type; + + typedef typename std::add_const::type + const_value_type; public: - using value_type = T; - using const_value_type = typename std::add_const::type; - using nonconst_value_type = typename std::remove_const::type; - using self_t = GlobRef; - using const_type = GlobRef; + typedef T value_type; + + typedef GlobRef const_type; +private: + typedef GlobRef + self_t; + typedef GlobRef + self_const_t; private: dart_gptr_t _gptr; @@ -132,7 +140,7 @@ class GlobRef /** * Value-assignment operator. */ - const self_t & operator=(const value_type& val) const { + self_t & operator=(const T val) { set(val); return *this; } @@ -140,7 +148,7 @@ class GlobRef /** * Assignment operator. */ - const self_t & operator=(const self_t & other) const + self_t & operator=(const self_t & other) { set(static_cast(other)); return *this; @@ -150,7 +158,7 @@ class GlobRef * Assignment operator. */ template - const self_t & operator=(GlobRefOrElementT && other) const + self_t & operator=(GlobRefOrElementT && other) { set(std::forward(other)); return *this; @@ -188,30 +196,7 @@ class GlobRef return !(*this == value); } - /** - * Implicit cast to const. - */ - template::value,void>> - operator GlobRef () const { - return GlobRef(_gptr); - } - - /** - * Explicit cast to non-const - */ - template::value,void>> - explicit - operator GlobRef () const { - return GlobRef(_gptr); - } - - void - set(const value_type & val) const { - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); - + void set(const_value_type & val) { DASH_LOG_TRACE_VAR("GlobRef.set()", val); DASH_LOG_TRACE_VAR("GlobRef.set", _gptr); // TODO: Clarify if dart-call can be avoided if @@ -240,28 +225,19 @@ class GlobRef dash::internal::get_blocking(_gptr, &tref, 1); } - void - put(const_value_type& tref) const { - static_assert(std::is_same::value, - "Cannot assign to GlobRef!"); + void put(const_value_type& tref) { DASH_LOG_TRACE("GlobRef.put(T&)", "explicit put of provided ref"); DASH_LOG_TRACE_VAR("GlobRef.T()", _gptr); dash::internal::put_blocking(_gptr, &tref, 1); } - void - put(const_value_type* tptr) const { - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); + void put(const_value_type* tptr) { DASH_LOG_TRACE("GlobRef.put(T*)", "explicit put of provided ptr"); DASH_LOG_TRACE_VAR("GlobRef.T()", _gptr); dash::internal::put_blocking(_gptr, tptr, 1); } - const self_t & - operator+=(const nonconst_value_type& ref) const { - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); + self_t & operator+=(const nonconst_value_type& ref) { #if 0 // TODO: Alternative implementation, possibly more efficient: T add_val = ref; @@ -282,78 +258,54 @@ class GlobRef return *this; } - const self_t & - operator-=(const nonconst_value_type& ref) const { - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); + self_t & operator-=(const nonconst_value_type& ref) { nonconst_value_type val = operator nonconst_value_type(); val -= ref; operator=(val); return *this; } - const self_t & - operator++() const { - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); + self_t & operator++() { nonconst_value_type val = operator nonconst_value_type(); operator=(++val); return *this; } - nonconst_value_type - operator++(int) const { - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); + nonconst_value_type operator++(int) { nonconst_value_type val = operator nonconst_value_type(); nonconst_value_type res = val++; operator=(val); return res; } - const self_t & - operator--() const { - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); + self_t & operator--() { nonconst_value_type val = operator nonconst_value_type(); operator=(--val); return *this; } - nonconst_value_type - operator--(int) const { - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); + nonconst_value_type operator--(int) { nonconst_value_type val = operator nonconst_value_type(); nonconst_value_type res = val--; operator=(val); return res; } - const self_t & - operator*=(const_value_type& ref) const { - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); + self_t & operator*=(const_value_type& ref) { nonconst_value_type val = operator nonconst_value_type(); val *= ref; operator=(val); return *this; } - const self_t & - operator/=(const_value_type& ref) const { - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); + self_t & operator/=(const_value_type& ref) { nonconst_value_type val = operator nonconst_value_type(); val /= ref; operator=(val); return *this; } - const self_t & - operator^=(const_value_type& ref) const { - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); + self_t & operator^=(const_value_type& ref) { nonconst_value_type val = operator nonconst_value_type(); val ^= ref; operator=(val); @@ -392,33 +344,29 @@ class GlobRef * specified offset */ template - GlobRef::type> - member(size_t offs) const { + GlobRef member(size_t offs) const { dart_gptr_t dartptr = _gptr; DASH_ASSERT_RETURNS( dart_gptr_incaddr(&dartptr, offs), DART_OK); - return GlobRef::type>(dartptr); + return GlobRef(dartptr); } /** * Get the member via pointer to member */ template - GlobRef::type> - member( + GlobRef member( const MEMTYPE P::*mem) const { // TODO: Thaaaat ... looks hacky. size_t offs = (size_t) &( reinterpret_cast(0)->*mem); - return member::type>(offs); + return member(offs); } /** * specialization which swappes the values of two global references */ - inline void swap(dash::GlobRef & b) const{ - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); + inline void swap(dash::GlobRef & b){ T tmp = static_cast(*this); *this = b; b = tmp; diff --git a/dash/include/dash/Iterator.h b/dash/include/dash/Iterator.h index 60fde2651..2725e5fe5 100644 --- a/dash/include/dash/Iterator.h +++ b/dash/include/dash/Iterator.h @@ -49,6 +49,16 @@ namespace dash { +namespace detail { + DASH__META__DEFINE_TRAIT__HAS_TYPE(value_type); + DASH__META__DEFINE_TRAIT__HAS_TYPE(iterator); + DASH__META__DEFINE_TRAIT__HAS_TYPE(const_iterator); + DASH__META__DEFINE_TRAIT__HAS_TYPE(reference); + DASH__META__DEFINE_TRAIT__HAS_TYPE(const_reference); + DASH__META__DEFINE_TRAIT__HAS_TYPE(pointer); + DASH__META__DEFINE_TRAIT__HAS_TYPE(const_pointer); +} + /** * diff --git a/dash/include/dash/Meta.h b/dash/include/dash/Meta.h index dd4e144b0..77fafc3b2 100644 --- a/dash/include/dash/Meta.h +++ b/dash/include/dash/Meta.h @@ -3,6 +3,7 @@ #include #include +#include #include @@ -13,12 +14,13 @@ template \ struct has_type_##DepType { \ private: \ + typedef typename std::decay::type DT; \ typedef char yes; \ typedef struct { char array[2]; } no; \ template static yes test(typename C:: DepType *); \ template static no test(...); \ public: \ - static constexpr bool value = sizeof(test(0)) == sizeof(yes); \ + static constexpr bool value = sizeof(test
(0)) == sizeof(yes); \ }; #endif // DOXYGEN @@ -71,6 +73,26 @@ DASH__META__DEFINE_TRAIT__HAS_TYPE(const_reference) */ DASH__META__DEFINE_TRAIT__HAS_TYPE(value_type) +/** + * Definition of type trait \c dash::detail::has_type_pattern_type + * with static member \c value indicating whether type \c T provides + * dependent type \c pattern_type. + */ +DASH__META__DEFINE_TRAIT__HAS_TYPE(pattern_type); + +/** + * Definition of type trait \c dash::detail::has_type_const_type + * with static member \c value indicating whether type \c T provides + * dependent type \c const_type. + */ +DASH__META__DEFINE_TRAIT__HAS_TYPE(const_type); + +/** + * Definition of type trait \c dash::detail::has_type_const_type + * with static member \c value indicating whether type \c T provides + * dependent type \c nonconst_type. + */ +DASH__META__DEFINE_TRAIT__HAS_TYPE(nonconst_type); } // namespace dash @@ -81,6 +103,92 @@ DASH__META__DEFINE_TRAIT__HAS_TYPE(value_type) namespace dash { +// ========================================================================== +// dash::const_value_cast::type -> const T & +// dash::const_value_cast::type -> const T * +// dash::const_value_cast::type -> const T +// -------------------------------------------------------------------------- + +template +struct const_value_cast; + +template +struct const_value_cast { + typedef const T * type; +}; + +template +struct const_value_cast { + typedef const T & type; +}; + +template +struct const_value_cast { + typedef typename + std::conditional< + dash::has_type_const_type::value, + typename T::const_type, + const T + >::type + type; +}; + + +// ========================================================================== +// dash::nonconst_value_cast::type -> T & +// dash::nonconst_value_cast::type -> T * +// dash::nonconst_value_cast::type -> T +// -------------------------------------------------------------------------- + +template +struct nonconst_value_cast; + +template +struct nonconst_value_cast { + typedef T * type; +}; + +template +struct nonconst_value_cast { + typedef T & type; +}; + +template +struct nonconst_value_cast { + typedef typename + std::conditional< + dash::has_type_nonconst_type::value, + typename T::nonconst_type, + typename std::remove_const::type + >::type + type; +}; + + +// ========================================================================== +// dash::array_value_cast(std::array)::type -> std::array +// -------------------------------------------------------------------------- + +namespace detail { + +template +constexpr auto array_value_cast_indexed( + const std::array &a, dash::ce::index_sequence) + -> std::array { + return {{ static_cast(std::get(a))... }}; +} + +} // namespace detail + +template +constexpr auto array_value_cast( + const std::array & a) -> std::array { + // tag dispatch to helper with array indices + return detail::array_value_cast_indexed( + a, dash::ce::make_index_sequence()); +} + + /* * For reference, see * diff --git a/dash/include/dash/Range.h b/dash/include/dash/Range.h index 490f9f4ca..b017d9bb5 100644 --- a/dash/include/dash/Range.h +++ b/dash/include/dash/Range.h @@ -4,6 +4,12 @@ /** * \defgroup DashRangeConcept Multidimensional Range Concept * + * TODO: The Range concept as specified in the following diverges from + * the conventional definition of ranges as in Boost and rangesV3 + * (begin, end, next operations). + * It should be renamed to *Span*. + * + * * \ingroup DashNDimConcepts * \{ * \par Description @@ -46,70 +52,19 @@ */ -#include -#include - -#include - - -namespace dash { - - -#ifndef DOXYGEN - - // Related: boost::range // // https://github.com/boostorg/range/tree/develop/include/boost/range // -template -struct view_traits; - -// Forward-declaration -template -class IndexSetIdentity; - -// Forward-declaration -template -class IteratorRange; - -// Forward-declaration -template -class IteratorRange; -#endif - - - -/** - * \concept{DashRangeConcept} - */ -template -constexpr auto begin(RangeType && range) - -> decltype(std::forward(range).begin()) { - return std::forward(range).begin(); -} +#include +#include -/** - * \concept{DashRangeConcept} - */ -template -constexpr auto end(RangeType && range) - -> decltype(std::forward(range).end()) { - return std::forward(range).end(); -} +#include -/** - * \concept{DashRangeConcept} - */ -template -constexpr auto -size(RangeType && r) - -> decltype(std::forward(r).size()) { - return std::forward(r).size(); -} +namespace dash { namespace detail { @@ -120,44 +75,8 @@ struct _is_range_type typedef char yes; typedef long no; - typedef typename std::remove_reference< - typename std::remove_const::type - >::type - ValueT; + typedef typename std::decay::type ValueT; -#ifdef __TODO__ -private: - // Test if dash::begin(x) is valid expression: - template static yes has_dash_begin( - decltype( - dash::begin( - std::move(std::declval()) - ) - ) * ); - template static no has_dash_begin(...); - - // Test if dash::end(x) is valid expression: - template static yes has_dash_end( - decltype( - dash::end( - std::move(std::declval()) - ) - ) * ); - template static no has_dash_end(...); - -public: - enum { value = ( - sizeof(has_dash_begin(static_cast(nullptr))) == sizeof(yes) - && sizeof(has_dash_end(static_cast(nullptr))) == sizeof(yes) - ) }; - - //template()) - // )) > - //static yes has_dash_begin(C *); -#endif // Test if x.begin() is valid expression and type x::iterator is // defined: template @@ -209,7 +128,7 @@ struct _is_range_type * * * Example: - * + *: * \code * bool g_array_is_range = dash::is_range< * dash::Array @@ -240,230 +159,83 @@ struct _is_range_type * \endcode */ template -struct is_range : dash::detail::_is_range_type { }; - -template < - typename RangeType, - typename Iterator, - typename Sentinel = Iterator > -class RangeBase { -public: - typedef Iterator iterator; - typedef Sentinel sentinel; - typedef dash::default_index_t index_type; -protected: - RangeType & derived() { - return static_cast(*this); - } - const RangeType & derived() const { - return static_cast(*this); - } -}; - +struct is_range : dash::detail::_is_range_type< + typename std::decay::type + > +{ }; /** - * Specialization of \c dash::view_traits for IteratorRange. + * \concept{DashRangeConcept} */ -template < - typename IteratorT, - typename SentinelT > -struct view_traits > { -private: - typedef IteratorRange RangeT; -public: - typedef RangeT origin_type; - typedef RangeT domain_type; - typedef RangeT image_type; - typedef RangeT global_type; - typedef typename RangeT::local_type local_type; - typedef typename RangeT::index_type index_type; - typedef typename RangeT::index_set_type index_set_type; - - /// Whether the view type is a projection (has less dimensions than the - /// view's domain type). - typedef std::integral_constant is_projection; - typedef std::integral_constant is_view; - /// Whether the view is the origin domain. - typedef std::integral_constant is_origin; - /// Whether the view / container type is a local view. - /// \note A container type is local if it is identical to its - /// \c local_type - typedef std::integral_constant::value > is_local; -}; +template +constexpr auto begin(RangeType && range) + -> decltype(std::forward(range).begin()) { + return std::forward(range).begin(); +} /** - * Adapter template for range concept, wraps `begin` and `end` iterators - * in range type. + * \concept{DashRangeConcept} */ -template < - typename Iterator, - typename Sentinel > -class IteratorRange -: public RangeBase< IteratorRange, - Iterator, - Sentinel > -{ - typedef IteratorRange self_t; - - Iterator & _begin; - Sentinel & _end; - -public: - typedef Iterator iterator; - typedef Sentinel sentinel; - typedef dash::default_index_t index_type; - typedef typename iterator::pattern_type pattern_type; - typedef dash::IndexSetIdentity index_set_type; - typedef typename iterator::value_type value_type; - - typedef typename - std::conditional< - std::is_pointer::value, - iterator, - typename iterator::local_type - >::type - local_iterator; - - typedef typename - std::conditional< - std::is_pointer::value, - iterator, - typename sentinel::local_type - >::type - local_sentinel; - - typedef IteratorRange local_type; - - -public: - template - constexpr explicit IteratorRange(Container && c) - : _begin(c.begin()) - , _end(c.end()) - { } - - constexpr IteratorRange(iterator & begin, sentinel & end) - : _begin(begin) - , _end(end) - { } - - constexpr iterator begin() const { return _begin; } - constexpr iterator end() const { return _end; } - - constexpr const local_type local() const { - return local_type( - _begin.local(), - _end.local() - ); - } - - constexpr const pattern_type & pattern() const { - return _begin.pattern(); - } - - constexpr index_set_type index_set() const { - return index_set_type(*this); - } -}; - +template +constexpr auto lbegin(RangeType && range) + -> decltype(std::forward(range).begin()) { + return std::forward(range).lbegin(); +} /** - * Specialization of adapter template for range concept, wraps `begin` - * and `end` pointers in range type. + * \concept{DashRangeConcept} */ -template < - typename LocalIterator, - typename LocalSentinel > -class IteratorRange -: public RangeBase< - IteratorRange, - LocalIterator *, - LocalSentinel * > -{ - typedef IteratorRange self_t; - - LocalIterator * _begin; - LocalSentinel * _end; - -public: - typedef LocalIterator * iterator; - typedef LocalSentinel * sentinel; - typedef dash::default_index_t index_type; - typedef dash::IndexSetIdentity index_set_type; - typedef LocalIterator value_type; - - typedef iterator local_iterator; - typedef sentinel local_sentinel; - - typedef IteratorRange local_type; - -public: - template - constexpr explicit IteratorRange(Container && c) - : _begin(c.begin()) - , _end(c.end()) - { } - - constexpr IteratorRange(iterator & begin, sentinel & end) - : _begin(begin) - , _end(end) - { } - - constexpr iterator begin() const { return _begin; } - constexpr iterator end() const { return _end; } +template +constexpr auto begin(const RangeType & range) + -> decltype(range.begin()) { + return range.begin(); +} - constexpr const local_type & local() const { - return *this; - } +/** + * \concept{DashRangeConcept} + */ +template +constexpr auto lend(RangeType && range) + -> decltype(std::forward(range).end()) { + return std::forward(range).lend(); +} - constexpr index_set_type index_set() const { - return index_set_type(*this); - } -}; +/** + * \concept{DashRangeConcept} + */ +template +constexpr auto end(RangeType && range) + -> decltype(std::forward(range).end()) { + return std::forward(range).end(); +} /** - * Adapter utility function. - * Wraps `begin` and `end` const iterators in range type. + * \concept{DashRangeConcept} */ -template -constexpr dash::IteratorRange -make_range( - const Iterator & begin, - const Sentinel & end) { - return dash::IteratorRange( - begin, - end); +template +constexpr auto end(const RangeType & range) + -> decltype(range.end()) { + return range.end(); } /** - * Adapter utility function. - * Wraps `begin` and `end` pointers in range type. + * \concept{DashRangeConcept} */ -template -constexpr dash::IteratorRange -make_range( - Iterator * begin, - Sentinel * end) { - return dash::IteratorRange( - begin, - end); +template +constexpr auto +size(RangeType && r) + -> decltype(std::forward(r).size()) { + return std::forward(r).size(); } /** - * Adapter utility function. - * Wraps `begin` and `end` iterators in range type. + * \concept{DashRangeConcept} */ -template -dash::IteratorRange -make_range( - Iterator & begin, - Sentinel & end) { - return dash::IteratorRange( - begin, - end); +template +constexpr auto +size(const RangeType & r) + -> decltype(r.size()) { + return r.size(); } } // namespace dash diff --git a/dash/include/dash/View.h b/dash/include/dash/View.h index e7b0a845c..50d84dac6 100644 --- a/dash/include/dash/View.h +++ b/dash/include/dash/View.h @@ -18,12 +18,13 @@ * \see DashDimensionalConcept * \see DashRangeConcept * \see DashIteratorConcept + * \see DashIndexSetConcept * \see \c dash::view_traits * * \par Terminology * - * A \b View is a mapping between two index sets, from a \b Domain space to - * an \b Image space in the view's codomain. + * A \b View is a mapping from a \b Domain space to an \b Image space in the + * view's codomain defined by their underlying index sets. * Views can be chained such that the image obtained from the application of * a view expression can again act as the domain of other views. * In effect, a view expression can be understood as a composite function on @@ -34,20 +35,37 @@ * * \par Expressions * - * View Specifier | Synopsis - * ------------------------- | -------------------------------------------------- - * dash::sub | Subrange of domain in a specified dimension - * dash::intersect | View from intersection of two domains - * dash::difference | View from difference of two domains - * dash::combine | Composite view of two possibply unconnected domains - * dash::local | Local subspace of domain - * dash::global | Maps subspace to elements in global domain - * dash::apply | Obtain image of domain view (inverse of \c domain) - * dash::domain | Obtain domain of view image (inverse of \c apply) - * dash::origin | Obtain the view origin (root domain) - * dash::blocks | Decompose domain into blocks - * dash::block | Subspace of decomposed domain in a specific block - * dash::index | Returns a view's index set + * View Specifier | Synopsis + * ---------------------------- | -------------------------------------------------- + * dash::sub | Subrange of domain in a specified dimension + * dash::intersect(v) | View from intersection of two domains, result \ + * remains regular rectangle for regular operands + * dash::difference | View from difference of two domains + * dash::expand(ob,oe) | Resize Cartesian view by specified begin-\ + * | and end offset + * + * dash::combine(v) | Composite possibly unconnected domain into \ + * view + * dash::group | Group domains in view, group members are not\ + * combined + * + * dash::local | Local subspace of domain + * dash::remote | Non-local subspace of domain + * dash::global | Maps subspace to elements in global domain + * + * dash::domain | Obtain domain of view image (inverse of \c apply) + * dash::origin | Obtain the view origin (local or global root\ + * domain) + * dash::global_origin | Obtain the view origin (global root domain) + * + * dash::blocks | Decompose domain into blocks in data distribution + * dash::block | Subspace of decomposed domain in a specific block + * dash::chunks | Decompose domain into single contiguous ranges + * dash::strides | Decompose domain into ranges with specified size + * + * dash::index | Returns a view's index set + * dash::owner | Maps elements in view to unit id of its memory \ + * space * * \par Examples * @@ -65,15 +83,16 @@ * for (auto elem : matrix_rect) { * // ... * } - * * \endcode * * \} */ -#include +#include + +#include #include -#include +#include #include #include #include @@ -81,9 +100,11 @@ #include #include #include +#include #include -#include +#include +#include #include #include @@ -96,89 +117,6 @@ #include #include - -#include - - -namespace dash { - -template < - class Iterator, - class Sentinel > -class IteratorViewOrigin; - -template < - class Iterator, - class Sentinel > -struct view_traits > { - typedef IteratorViewOrigin domain_type; - typedef IteratorViewOrigin origin_type; - typedef IteratorViewOrigin image_type; - - // Uses container::local_type directly, e.g. dash::LocalArrayRef: - // typedef typename dash::view_traits::local_type local_type; - // Uses ViewLocalMod wrapper on domain, e.g. ViewLocalMod: - typedef ViewLocalMod local_type; - typedef ViewGlobalMod global_type; - - typedef typename Iterator::index_type index_type; - typedef dash::IndexSetIdentity< - IteratorViewOrigin > index_set_type; - - typedef std::integral_constant is_projection; - typedef std::integral_constant is_view; - typedef std::integral_constant is_origin; - typedef std::integral_constant is_local; -}; - -template < - class Iterator, - class Sentinel -> -class IteratorViewOrigin -: public dash::IteratorRange -{ -public: - typedef typename Iterator::index_type index_type; -private: - typedef IteratorViewOrigin self_t; - typedef IteratorRange base_t; -public: - typedef self_t domain_type; - typedef self_t origin_type; - typedef self_t image_type; - // Alternative: IteratorLocalView - typedef typename view_traits::local_type local_type; - typedef typename view_traits::global_type global_type; - - typedef typename Iterator::pattern_type pattern_type; -public: - constexpr IteratorViewOrigin(Iterator begin, Iterator end) - : base_t(std::move(begin), std::move(end)) { - } - - constexpr const pattern_type & pattern() const { - return this->begin().pattern(); - } - - constexpr local_type local() const { - // for local_type: IteratorLocalView - // return local_type(this->begin(), this->end()); - return local_type(*this); - } - -}; - - -template -constexpr dash::IteratorViewOrigin -make_view(Iterator begin, Sentinel end) { - return dash::IteratorViewOrigin( - std::move(begin), - std::move(end)); -} - -} // namespace dash - +#include #endif // DASH__VIEW_H__INCLUDED diff --git a/dash/include/dash/algorithm/Copy.h b/dash/include/dash/algorithm/Copy.h index 8cd4484c1..fa4ca1bd4 100644 --- a/dash/include/dash/algorithm/Copy.h +++ b/dash/include/dash/algorithm/Copy.h @@ -4,6 +4,17 @@ #include #include +#include +#include + +#include + +#include +#include +#include +#include +#include + #include #include @@ -13,6 +24,7 @@ #include #include + namespace dash { #ifdef DOXYGEN @@ -22,7 +34,8 @@ namespace dash { * another range beginning at \c out_first. * * In terms of data distribution, source and destination ranges passed to - * \c dash::copy can be local (\c *ValueType) or global (\c GlobIter). + * \c dash::copy can be local (\c *ValueType) or global + * (\c GlobIter). * * For a non-blocking variant of \c dash::copy, see \c dash::copy_async. * @@ -47,9 +60,9 @@ template < class InputIt, class OutputIt > OutputIt copy( - InputIt in_first, - InputIt in_last, - OutputIt out_first); + const InputIt in_first, + const InputIt in_last, + OutputIt out_first); /** * Asynchronous variant of \c dash::copy. @@ -57,7 +70,8 @@ OutputIt copy( * another range beginning at \c out_first. * * In terms of data distribution, source and destination ranges passed to - * \c dash::copy can be local (\c *ValueType) or global (\c GlobIter). + * \c dash::copy can be local (\c *ValueType) or global + * (\c GlobIter). * * For a blocking variant of \c dash::copy_async, see \c dash::copy. * @@ -76,8 +90,8 @@ OutputIt copy( * \endcode * * \returns An instance of \c dash::Future providing the output range end - * iterator that is created on completion of the asynchronous copy - * operation. + * iterator that is created on completion of the asynchronous + * copy operation. * * \ingroup DashAlgorithms */ @@ -85,32 +99,31 @@ template < typename ValueType, class GlobInputIt > dash::Future copy_async( - InputIt in_first, - InputIt in_last, - OutputIt out_first); + const InputIt in_first, + const InputIt in_last, + OutputIt out_first); #else // DOXYGEN namespace internal { -// ========================================================================= +// ======================================================================= // Global to Local -// ========================================================================= +// ======================================================================= /** * Blocking implementation of \c dash::copy (global to local) without * optimization for local subrange. */ template < - typename ValueType, + class ValueType, class GlobInputIt > -ValueType * copy_impl( - GlobInputIt in_first, - GlobInputIt in_last, - ValueType * out_first, - std::vector & handles) +ValueType * copy_block( + GlobInputIt in_first, + GlobInputIt in_last, + ValueType * out_first) { - DASH_LOG_TRACE("dash::copy_impl()", + DASH_LOG_TRACE("dash::copy_block()", "in_first:", in_first.pos(), "in_last:", in_last.pos(), "out_first:", out_first); @@ -119,47 +132,66 @@ ValueType * copy_impl( typedef typename decltype(pattern)::size_type size_type; size_type num_elem_total = dash::distance(in_first, in_last); if (num_elem_total <= 0) { - DASH_LOG_TRACE("dash::copy_impl", "input range empty"); + DASH_LOG_TRACE("dash::copy_block", "input range empty"); return out_first; } - DASH_LOG_TRACE("dash::copy_impl", + DASH_LOG_TRACE("dash::copy_block", "total elements:", num_elem_total, "expected out_last:", out_first + num_elem_total); // Input iterators could be relative to a view. Map first input iterator // to global index range and use it to resolve last input iterator. - // Do not use in_last.global() as this would span over the relative input - // range. + // Do not use in_last.global() as this would span over the relative + // input range. auto g_in_first = in_first.global(); auto g_in_last = g_in_first + num_elem_total; - DASH_LOG_TRACE("dash::copy_impl", + DASH_LOG_TRACE("dash::copy_block", "g_in_first:", g_in_first.pos(), "g_in_last:", g_in_last.pos()); auto unit_first = pattern.unit_at(g_in_first.pos()); - DASH_LOG_TRACE_VAR("dash::copy_impl", unit_first); + DASH_LOG_TRACE_VAR("dash::copy_block", unit_first); auto unit_last = pattern.unit_at(g_in_last.pos() - 1); - DASH_LOG_TRACE_VAR("dash::copy_impl", unit_last); + DASH_LOG_TRACE_VAR("dash::copy_block", unit_last); + // MPI uses offset type int, do not copy more than INT_MAX bytes: + size_type max_copy_elem = (std::numeric_limits::max() / + sizeof(ValueType)); size_type num_elem_copied = 0; + DASH_LOG_TRACE_VAR("dash::copy_block", max_copy_elem); + if (num_elem_total > max_copy_elem) { + DASH_LOG_DEBUG("dash::copy_block", + "cannot copy", num_elem_total, "elements", + "in a single dart_get operation"); + } if (unit_first == unit_last) { // Input range is located at a single remote unit: - DASH_LOG_TRACE("dash::copy_impl", "input range at single unit"); - DASH_LOG_TRACE("dash::copy_impl", - "get elements:", num_elem_total); - auto cur_in_first = g_in_first; - auto cur_out_first = out_first; - dart_handle_t handle; - dash::internal::get_handle( - cur_in_first.dart_gptr(), - cur_out_first, - num_elem_total, - &handle); - if (handle != DART_HANDLE_NULL) { - handles.push_back(handle); + DASH_LOG_TRACE("dash::copy_block", "input range at single unit"); + while (num_elem_copied < num_elem_total) { + // Number of elements left to copy: + auto total_elem_left = num_elem_total - num_elem_copied; + auto num_copy_elem = (num_elem_total > max_copy_elem) + ? max_copy_elem + : num_elem_total; + if (num_copy_elem > total_elem_left) { + num_copy_elem = total_elem_left; + } + DASH_LOG_TRACE("dash::copy_block", + "copy max:", max_copy_elem, + "get elements:", num_copy_elem, + "total:", num_elem_total, + "copied:", num_elem_copied, + "left:", total_elem_left); + auto cur_in_first = g_in_first + num_elem_copied; + auto cur_out_first = out_first + num_elem_copied; + dash::internal::get_blocking( + cur_in_first.dart_gptr(), + cur_out_first, + num_copy_elem); + num_elem_copied += num_copy_elem; } - num_elem_copied = num_elem_total; } else { // Input range is spread over several remote units: - DASH_LOG_TRACE("dash::copy_impl", "input range spans multiple units"); + DASH_LOG_TRACE("dash::copy_block", + "input range spans multiple units"); // // Copy elements from every unit: // @@ -178,13 +210,15 @@ ValueType * copy_impl( // Number of elements left to copy: auto total_elem_left = num_elem_total - num_elem_copied; // Number of elements to copy in this iteration. - auto num_copy_elem = num_unit_elem; + auto num_copy_elem = (num_unit_elem < max_copy_elem) + ? num_unit_elem + : max_copy_elem; if (num_copy_elem > total_elem_left) { num_copy_elem = total_elem_left; } DASH_ASSERT_GT(num_copy_elem, 0, "Number of element to copy is 0"); - DASH_LOG_TRACE("dash::copy_impl", + DASH_LOG_TRACE("dash::copy_block", "start g_idx:", cur_in_first.pos(), "->", "unit:", local_pos.unit, @@ -192,105 +226,368 @@ ValueType * copy_impl( "->", "unit elements:", num_unit_elem, "max elem/unit:", max_elem_per_unit, + "copy max:", max_copy_elem, "get elements:", num_copy_elem, "total:", num_elem_total, "copied:", num_elem_copied, "left:", total_elem_left); auto dest_ptr = out_first + num_elem_copied; auto src_gptr = cur_in_first.dart_gptr(); - dart_handle_t handle; - dash::internal::get_handle(src_gptr, dest_ptr, num_copy_elem, &handle); - num_elem_copied += num_copy_elem; - if (handle != DART_HANDLE_NULL) { - handles.push_back(handle); + dash::dart_storage ds(num_copy_elem); + if (dart_get_blocking( + dest_ptr, + src_gptr, + ds.nelem, + ds.dtype, + ds.dtype) + != DART_OK) { + DASH_LOG_ERROR("dash::copy_block", "dart_get failed"); + DASH_THROW( + dash::exception::RuntimeError, "dart_get failed"); } + num_elem_copied += num_copy_elem; } } ValueType * out_last = out_first + num_elem_copied; - DASH_LOG_TRACE_VAR("dash::copy_impl >", out_last); + DASH_LOG_TRACE_VAR("dash::copy_block >", out_last); return out_last; } -// ========================================================================= +/** + * Asynchronous implementation of \c dash::copy (global to local) without + * optimization for local subrange. + */ +template < + class ValueType, + class GlobInputIt > +dash::Future copy_block_async( + GlobInputIt in_first, + GlobInputIt in_last, + ValueType * out_first) +{ + DASH_LOG_TRACE("dash::copy_block_async()", + "in_first:", in_first.pos(), + "in_last:", in_last.pos(), + "out_first:", out_first); + auto pattern = in_first.pattern(); + typedef typename decltype(pattern)::index_type index_type; + typedef typename decltype(pattern)::size_type size_type; + size_type num_elem_total = dash::distance(in_first, in_last); + if (num_elem_total <= 0) { + DASH_LOG_TRACE("dash::copy_block_async", "input range empty"); + return dash::Future([=]() { return out_first; }); + } + DASH_LOG_TRACE("dash::copy_block_async", + "total elements:", num_elem_total, + "expected out_last:", out_first + num_elem_total); + // Input iterators could be relative to a view. Map first input iterator + // to global index range and use it to resolve last input iterator. + // Do not use in_last.global() as this would span over the relative + // input range. + auto g_in_first = in_first.global(); + auto g_in_last = g_in_first + num_elem_total; + DASH_LOG_TRACE("dash::copy_block_async", + "g_in_first:", g_in_first.pos(), + "g_in_last:", g_in_last.pos()); + auto unit_first = pattern.unit_at(g_in_first.pos()); + DASH_LOG_TRACE_VAR("dash::copy_block_async", unit_first); + auto unit_last = pattern.unit_at(g_in_last.pos() - 1); + DASH_LOG_TRACE_VAR("dash::copy_block_async", unit_last); + + // Accessed global pointers to be flushed: + std::vector req_handles; + + // MPI uses offset type int, do not copy more than INT_MAX bytes: + size_type max_copy_elem = (std::numeric_limits::max() / + sizeof(ValueType)); + size_type num_elem_copied = 0; + DASH_LOG_TRACE_VAR("dash::copy_block_async", max_copy_elem); + if (num_elem_total > max_copy_elem) { + DASH_LOG_DEBUG("dash::copy_block_async", + "cannot copy", num_elem_total, "elements", + "in a single dart_get operation"); + } + if (unit_first == unit_last) { + // Input range is located at a single remote unit: + DASH_LOG_TRACE("dash::copy_block_async", + "input range at single unit"); + while (num_elem_copied < num_elem_total) { + // Number of elements left to copy: + auto total_elem_left = num_elem_total - num_elem_copied; + auto num_copy_elem = (num_elem_total > max_copy_elem) + ? max_copy_elem + : num_elem_total; + if (num_copy_elem > total_elem_left) { + num_copy_elem = total_elem_left; + } + DASH_LOG_TRACE("dash::copy_block_async", + "copy max:", max_copy_elem, + "get elements:", num_copy_elem, + "total:", num_elem_total, + "copied:", num_elem_copied, + "left:", total_elem_left); + auto cur_in_first = g_in_first + num_elem_copied; + auto cur_out_first = out_first + num_elem_copied; + dart_handle_t get_handle; + dash::internal::get_handle( + cur_in_first.dart_gptr(), + cur_out_first, + num_copy_elem, + &get_handle); + if (get_handle != DART_HANDLE_NULL) { + req_handles.push_back(get_handle); + } + num_elem_copied += num_copy_elem; + } + } else { + // Input range is spread over several remote units: + DASH_LOG_TRACE("dash::copy_block_async", + "input range spans multiple units"); + // + // Copy elements from every unit: + // + while (num_elem_copied < num_elem_total) { + // Global iterator pointing at begin of current unit's input range: + auto cur_in_first = g_in_first + num_elem_copied; + // unit and local index of first element in current range segment: + auto local_pos = pattern.local(static_cast( + cur_in_first.pos())); + // Number of elements located at current source unit: + size_type max_elem_per_unit = pattern.local_size(local_pos.unit); + // Local offset of first element in input range at current unit: + auto l_in_first_idx = local_pos.index; + // Maximum number of elements to copy from current unit: + auto num_unit_elem = max_elem_per_unit - l_in_first_idx; + // Number of elements left to copy: + auto total_elem_left = num_elem_total - num_elem_copied; + // Number of elements to copy in this iteration. + auto num_copy_elem = (num_unit_elem < max_copy_elem) + ? num_unit_elem + : max_copy_elem; + if (num_copy_elem > total_elem_left) { + num_copy_elem = total_elem_left; + } + DASH_ASSERT_GT(num_copy_elem, 0, + "Number of element to copy is 0"); + DASH_LOG_TRACE("dash::copy_block_async", + "start g_idx:", cur_in_first.pos(), + "->", + "unit:", local_pos.unit, + "l_idx:", l_in_first_idx, + "->", + "unit elements:", num_unit_elem, + "max elem/unit:", max_elem_per_unit, + "copy max:", max_copy_elem, + "get elements:", num_copy_elem, + "total:", num_elem_total, + "copied:", num_elem_copied, + "left:", total_elem_left); + auto src_gptr = cur_in_first.dart_gptr(); + auto dest_ptr = out_first + num_elem_copied; + dart_handle_t get_handle; + dash::internal::get_handle( + src_gptr, + dest_ptr, + num_copy_elem, + &get_handle); + if (get_handle != DART_HANDLE_NULL) { + req_handles.push_back(get_handle); + } + num_elem_copied += num_copy_elem; + } + } +#ifdef DASH_ENABLE_TRACE_LOGGING + for (auto gptr : req_handles) { + DASH_LOG_TRACE("dash::copy_block_async", " req_handle:", gptr); + } +#endif + dash::Future result([=]() mutable { + // Wait for all get requests to complete: + ValueType * _out = out_first + num_elem_copied; + DASH_LOG_TRACE("dash::copy_block_async [Future]()", + " wait for", req_handles.size(), "async get request"); + DASH_LOG_TRACE("dash::copy_block_async [Future]", " flush:", + req_handles); +#ifdef DASH_ENABLE_TRACE_LOGGING + for (auto gptr : req_handles) { + DASH_LOG_TRACE("dash::copy_block_async [Future]", " req_handle:", + gptr); + } +#endif + if (req_handles.size() > 0) { + if (dart_waitall_local(&req_handles[0], req_handles.size()) + != DART_OK) { + DASH_LOG_ERROR("dash::copy_block_async [Future]", + " dart_waitall_local failed"); + DASH_THROW( + dash::exception::RuntimeError, + "dash::copy_block_async [Future]: dart_waitall_local failed"); + } + } else { + DASH_LOG_TRACE("dash::copy_block_async [Future]", + " No pending handles"); + } + DASH_LOG_TRACE("dash::copy_block_async [Future] >", + " async requests completed, _out:", _out); + return _out; + }); + DASH_LOG_TRACE("dash::copy_block_async >", " returning future"); + return result; +} + +// ======================================================================= // Local to Global -// ========================================================================= +// ======================================================================= /** * Blocking implementation of \c dash::copy (local to global) without * optimization for local subrange. */ template < - typename ValueType, + class ValueType, class GlobOutputIt > -GlobOutputIt copy_impl( - ValueType * in_first, - ValueType * in_last, - GlobOutputIt out_first, - std::vector & handles) +GlobOutputIt copy_block( + ValueType * in_first, + ValueType * in_last, + GlobOutputIt out_first) { - DASH_LOG_TRACE("dash::copy_impl()", - "l_in_first:", in_first, - "l_in_last:", in_last, - "g_out_first:", out_first); + DASH_LOG_TRACE("dash::copy_block()", + "l_in_first:", in_first, + "l_in_last:", in_last, + "g_out_first.pos:", out_first.pos()); + DASH_LOG_TRACE("dash::copy_block", + "g_out_first:", out_first, out_first.dart_gptr()); auto num_elements = std::distance(in_first, in_last); - dart_handle_t handle; - dash::internal::put_handle( + dash::internal::put_blocking( out_first.dart_gptr(), in_first, - num_elements, - &handle); - if (handle != DART_HANDLE_NULL) { - handles.push_back(handle); - } + num_elements); auto out_last = out_first + num_elements; - DASH_LOG_TRACE("dash::copy_impl >", + DASH_LOG_TRACE("dash::copy_block >", "g_out_last:", out_last.dart_gptr()); return out_last; } +/** + * Asynchronous implementation of \c dash::copy (local to global) without + * optimization for local subrange. + */ +template < + class ValueType, + class GlobOutputIt > +dash::Future copy_block_async( + ValueType * in_first, + ValueType * in_last, + GlobOutputIt out_first) +{ + DASH_LOG_TRACE("dash::copy_block_async()", + "l_in_first:", in_first, + "l_in_last:", in_last, + "g_out_first:", out_first.dart_gptr()); + + // Accessed global pointers to be flushed: + std::vector req_handles; + + auto num_copy_elem = std::distance(in_first, in_last); + auto src_ptr = in_first; + auto dest_gptr = out_first.dart_gptr(); + dart_handle_t put_handle; + dash::dart_storage ds(num_copy_elem); + + DASH_ASSERT_RETURNS( + dart_put_handle( + dest_gptr, + src_ptr, + num_copy_elem + &put_handle), + DART_OK); + + if (put_handle != DART_HANDLE_NULL) { + req_handles.push_back(put_handle); + } + +#ifdef DASH_ENABLE_TRACE_LOGGING + for (auto gptr : req_handles) { + DASH_LOG_TRACE("dash::copy_block_async", " req_handle:", gptr); + } +#endif + dash::Future result([=]() mutable { + // Wait for all get requests to complete: + GlobOutputIt _out = out_first + num_copy_elem; + DASH_LOG_TRACE("dash::copy_block_async [Future]()", + " wait for", req_handles.size(), "async put request"); + DASH_LOG_TRACE("dash::copy_block_async [Future]", " flush:", + req_handles); + DASH_LOG_TRACE("dash::copy_block_async [Future]", " _out:", _out); +#ifdef DASH_ENABLE_TRACE_LOGGING + for (auto gptr : req_handles) { + DASH_LOG_TRACE("dash::copy_block_async [Future]", " req_handle:", + gptr); + } +#endif + if (req_handles.size() > 0) { + if (dart_waitall(&req_handles[0], req_handles.size()) + != DART_OK) { + DASH_LOG_ERROR("dash::copy_block_async [Future]", + " dart_waitall failed"); + DASH_THROW( + dash::exception::RuntimeError, + "dash::copy_block_async [Future]: dart_waitall failed"); + } + } else { + DASH_LOG_TRACE("dash::copy_block_async [Future]", + " No pending handles"); + } + DASH_LOG_TRACE("dash::copy_block_async [Future] >", + " async requests completed, _out:", _out); + return _out; + }); + DASH_LOG_TRACE("dash::copy_block_async >", " returning future"); + return result; +} + } // namespace internal -// ========================================================================= +// ======================================================================= // Global to Local, Distributed Range -// ========================================================================= +// ======================================================================= /** - * Variant of \c dash::copy as asynchronous global-to-local copy operation. + * Variant of \c dash::copy as asynchronous global-to-local copy + * operation. * * \ingroup DashAlgorithms */ template < - typename ValueType, - class GlobInputIt > + class ValueType, + class GlobInputIt > dash::Future copy_async( GlobInputIt in_first, GlobInputIt in_last, ValueType * out_first) { const auto & team = in_first.team(); - - DASH_LOG_TRACE("dash::copy_async()", "async, global to local"); - if (in_first == in_last) { - DASH_LOG_TRACE("dash::copy_async", "input range empty"); - return dash::Future(out_first); - } - dash::util::UnitLocality uloc(team, team.myid()); // Size of L2 data cache line: int l2_line_size = uloc.hwinfo().cache_line_sizes[1]; bool use_memcpy = ((in_last - in_first) * sizeof(ValueType)) <= l2_line_size; + DASH_LOG_TRACE("dash::copy_async()", "async, global to local"); + if (in_first == in_last) { + DASH_LOG_TRACE("dash::copy_async", "input range empty"); + return dash::Future([=]() { return out_first; }); + } ValueType * dest_first = out_first; - // Return value, initialize with begin of output range, indicating no values - // have been copied: + // Return value, initialize with begin of output range, indicating noi + // values have been copied: ValueType * out_last = out_first; // Check if part of the input range is local: DASH_LOG_TRACE_VAR("dash::copy_async", in_first.dart_gptr()); @@ -302,9 +599,9 @@ dash::Future copy_async( // Total number of elements to be copied: auto total_copy_elem = in_last - in_first; - // Instead of testing in_first.local() and in_last.local(), this test for a - // local-only range only requires one call to in_first.local() which increases - // throughput by ~10% for local ranges. + // Instead of testing in_first.local() and in_last.local(), this test + // for a local-only range only requires one call to in_first.local() + // which increases throughput by ~10% for local ranges. if (num_local_elem == total_copy_elem) { // Entire input range is local: DASH_LOG_TRACE("dash::copy_async", "entire input range is local"); @@ -327,19 +624,19 @@ dash::Future copy_async( } DASH_LOG_TRACE("dash::copy_async", "finished local copy of", (out_last - out_first), "elements"); - return dash::Future(out_last); + return dash::Future([=]() { return out_last; }); } - auto handles = std::make_shared>(); - DASH_LOG_TRACE("dash::copy_async", "local range:", li_range_in.begin, li_range_in.end, "in_first.is_local:", in_first.is_local()); + // Futures of asynchronous get requests: + auto futures = std::vector< dash::Future >(); // Check if global input range is partially local: if (num_local_elem > 0) { - // Part of the input range is local, copy local input subrange to local - // output range directly. + // Part of the input range is local, copy local input subrange to + // local output range directly. auto pattern = in_first.pattern(); // Map input iterators to global index domain: auto g_in_first = in_first.global(); @@ -350,21 +647,27 @@ dash::Future copy_async( // Global index of local range begin index: auto g_l_offset_begin = pattern.global(li_range_in.begin); // Global index of local range end index: - auto g_l_offset_end = pattern.global(li_range_in.end-1) - + 1; // pat.global(l_end) would be out of range + // + // NOTE: definition as pat.global(l_end-1)+1 as + // pat.global(l_end) would be out of range + auto g_l_offset_end = pattern.global(li_range_in.end-1) + 1; DASH_LOG_TRACE("dash::copy_async", "global index range of local subrange:", "begin:", g_l_offset_begin, "end:", g_l_offset_end); // Global position of input start iterator: auto g_offset_begin = g_in_first.pos(); // Convert local subrange to global iterators: - auto g_l_in_first = g_in_first + (g_l_offset_begin - g_offset_begin); - auto g_l_in_last = g_in_first + (g_l_offset_end - g_offset_begin); - DASH_LOG_TRACE("dash::copy_async", "global it. range of local subrange:", - "begin:", g_l_in_first.pos(), "end:", g_l_in_last.pos()); + auto g_l_in_first = g_in_first + + (g_l_offset_begin - g_offset_begin); + auto g_l_in_last = g_in_first + + (g_l_offset_end - g_offset_begin); + DASH_LOG_TRACE("dash::copy_async", + "global it. range of local subrange:", + "begin:", g_l_in_first.pos(), + "end:", g_l_in_last.pos()); DASH_LOG_TRACE_VAR("dash::copy_async", g_l_in_last.pos()); // - // ----------------------------------------------------------------------- + // ------------------------------------------------------------------- // Copy remote elements preceding the local subrange: // auto num_prelocal_elem = g_l_in_first.pos() - g_in_first.pos(); @@ -377,16 +680,16 @@ dash::Future copy_async( // ... [ --- copy --- | ... l ... | ........ ] // ^ ^ ^ ^ // in_first l_in_first l_in_last in_last - dash::internal::copy_impl(g_in_first, - g_l_in_first, - dest_first, - *handles); + auto fut_prelocal = dash::internal::copy_block_async(g_in_first, + g_l_in_first, + dest_first); + futures.push_back(fut_prelocal); // Advance output pointers: out_last += num_prelocal_elem; dest_first = out_last; } // - // ----------------------------------------------------------------------- + // ------------------------------------------------------------------- // Copy remote elements succeeding the local subrange: // auto num_postlocal_elem = in_last.pos() - g_l_offset_end; @@ -400,14 +703,14 @@ dash::Future copy_async( // ... [ ........ | ... l ... | --- copy --- ] // ^ ^ ^ ^ // in_first l_in_first l_in_last in_last - dash::internal::copy_impl(g_l_in_last, - g_in_last, - dest_first, - *handles); + auto fut_postlocal = dash::internal::copy_block_async(g_l_in_last, + g_in_last, + dest_first); + futures.push_back(fut_postlocal); out_last += num_postlocal_elem; } // - // ----------------------------------------------------------------------- + // ------------------------------------------------------------------- // Copy local subrange: // // Convert local subrange of global input to native pointers: @@ -449,112 +752,127 @@ dash::Future copy_async( } else { DASH_LOG_TRACE("dash::copy_async", "no local subrange"); // All elements in input range are remote - dash::internal::copy_impl(in_first, - in_last, - dest_first, - *handles); + auto fut_all = dash::internal::copy_block_async(in_first, + in_last, + dest_first); + futures.push_back(fut_all); out_last = out_first + total_copy_elem; } DASH_LOG_TRACE("dash::copy_async", "preparing future"); - if (handles->size() == 0) { - DASH_LOG_TRACE("dash::copy_async >", "finished (no pending handles), ", - "out_last:", out_last); - return dash::Future(out_last); - } - dash::Future fut_result( - // wait - [=]() mutable { - // Wait for all get requests to complete: - ValueType * _out = out_last; - DASH_LOG_TRACE("dash::copy_async_impl [Future]()", - " wait for", handles->size(), "async get request"); - DASH_LOG_TRACE("dash::copy_async_impl [Future]", " _out:", _out); - if (handles->size() > 0) { - if (dart_waitall_local(handles->data(), handles->size()) - != DART_OK) { - DASH_LOG_ERROR("dash::copy_async_impl [Future]", - " dart_waitall_local failed"); - DASH_THROW( - dash::exception::RuntimeError, - "dash::copy_async_impl [Future]: dart_waitall_local failed"); - } - } else { - DASH_LOG_TRACE("dash::copy_async_impl [Future]", " No pending handles"); - } - DASH_LOG_TRACE("dash::copy_async_impl [Future] >", - " async requests completed, _out:", _out); - return _out; - }, - // test - [=](ValueType ** out) mutable { - int32_t flag; - DASH_ASSERT_RETURNS( - DART_OK, - dart_testall_local(handles->data(), handles->size(), &flag)); - if (flag) { - handles->clear(); - *out = out_last; - } - return (flag != 0); - }, - // destroy - [=]() mutable { - for (auto& handle : *handles) { - DASH_ASSERT_RETURNS( - DART_OK, - dart_handle_free(&handle)); - } + dash::Future fut_result([=]() mutable { + ValueType * _out = out_last; + DASH_LOG_TRACE("dash::copy_async [Future]()", + "wait for", futures.size(), "async copy requests"); + DASH_LOG_TRACE("dash::copy_async [Future]", " futures:", futures); + DASH_LOG_TRACE("dash::copy_async [Future]", " _out:", _out); + for (auto f : futures) { + f.wait(); } - ); - + DASH_LOG_TRACE("dash::copy_async [Future] >", + "async requests completed", + "futures:", futures, "_out:", _out); + return _out; + }); DASH_LOG_TRACE("dash::copy_async >", "finished,", "expected out_last:", out_last); return fut_result; } /* - * Specialization of \c dash::copy as global-to-local blocking copy operation. + * Specialization of \c dash::copy as global-to-local blocking copy + * operation. * * \ingroup DashAlgorithms */ + template < - typename ValueType, - class GlobInputIt > -ValueType * copy( - GlobInputIt in_first, - GlobInputIt in_last, - ValueType * out_first) + class ValueType, + class GlobInputRange > +auto copy( + GlobInputRange in_range, + ValueType * out_first) + -> typename std::enable_if< + GlobInputRange::rank::value == 1, + ValueType * + >::type { - const auto & team = in_first.team(); - dash::util::UnitLocality uloc(team, team.myid()); - // Size of L2 data cache line: - int l2_line_size = uloc.hwinfo().cache_line_sizes[1]; - bool use_memcpy = ((in_last - in_first) * sizeof(ValueType)) - <= l2_line_size; + DASH_LOG_TRACE("dash::copy:range()", "ND = 1, blocking, global to local"); + if (in_range.size() == 0) { + DASH_LOG_TRACE("dash::copy:range", "input range empty"); + return out_first; + } + auto out_last = out_first; + auto in_blocks = dash::blocks(in_range); + DASH_LOG_TRACE("dash::copy:range", "number of blocks:", in_blocks.size()); + + for (auto block : in_blocks) { + DASH_LOG_TRACE("dash::copy:range", "block size:", block.size()); + auto in_copy_it = block.begin(); + auto in_copy_lp = in_copy_it.local(); + out_last = static_cast( + false && in_copy_lp != nullptr + ? std::copy( + in_copy_lp, + in_copy_lp + block.size(), + out_last) + : dash::internal::copy_block( + in_copy_it, + in_copy_it + block.size(), + out_last) ); + } + DASH_LOG_TRACE("dash::copy:range >", "finished,", "out_last:", out_last); + return out_last; +} - DASH_LOG_TRACE("dash::copy()", "blocking, global to local"); +template < + class ValueType, + class GlobInputRange > +auto copy( + GlobInputRange in_range, + ValueType * out_first) + -> typename std::enable_if< + (GlobInputRange::rank::value > 1), + ValueType * + >::type +{ + DASH_LOG_TRACE("dash::copy:range()", "ND > 1, blocking, global to local"); + + auto dest_first = out_first; + auto out_last = out_first; + auto in_first = in_range.begin(); + auto in_last = in_range.end(); + + DASH_LOG_TRACE("dash::copy:range", "source global in:", in_range); + DASH_LOG_TRACE("dash::copy:range", "source global in first:", in_first); + DASH_LOG_TRACE("dash::copy:range", "source global in last:", in_last); + + auto li_range_in = dash::index( + dash::local( + in_range)); + DASH_LOG_TRACE("dash::copy:range", "source local index range:", + li_range_in); + DASH_LOG_TRACE("dash::copy:range", "source g(local) index range:", + dash::global(li_range_in)); - ValueType * dest_first = out_first; - // Return value, initialize with begin of output range, indicating no - // values have been copied: - ValueType * out_last = out_first; - // Check if part of the input range is local: - DASH_LOG_TRACE_VAR("dash::copy", in_first.dart_gptr()); - DASH_LOG_TRACE_VAR("dash::copy", in_last.dart_gptr()); - DASH_LOG_TRACE_VAR("dash::copy", out_first); - auto li_range_in = local_index_range(in_first, in_last); // Number of elements in the local subrange: - auto num_local_elem = li_range_in.end - li_range_in.begin; +//auto num_local_elem = li_range_in.end - li_range_in.begin; + auto num_local_elem = li_range_in.size(); // Total number of elements to be copied: - auto total_copy_elem = in_last - in_first; + auto total_copy_elem = in_range.size(); + + const auto & team = in_first.team(); + dash::util::UnitLocality uloc(team, team.myid()); + // Size of L2 data cache line: + int l2_line_size = uloc.hwinfo().cache_line_sizes[1]; + bool use_memcpy = ((in_last - in_first) * sizeof(ValueType)) + <= l2_line_size; - // Instead of testing in_first.local() and in_last.local(), this test for - // a local-only range only requires one call to in_first.local() which - // increases throughput by ~10% for local ranges. + // Instead of testing in_first.local() and in_last.local(), this test + // for a local-only range only requires one call to in_first.local() + // which increases throughput by ~10% for local ranges. if (num_local_elem == total_copy_elem) { // Entire input range is local: - DASH_LOG_TRACE("dash::copy", "entire input range is local"); - ValueType * out_last = out_first + total_copy_elem; + DASH_LOG_TRACE("dash::copy:range", "entire input range is local"); // Use memcpy for data ranges below 64 KB if (use_memcpy) { std::memcpy(out_first, // destination @@ -568,72 +886,69 @@ ValueType * copy( l_in_last, out_first); } - DASH_LOG_TRACE("dash::copy", "finished local copy of", + DASH_LOG_TRACE("dash::copy:range", "finished local copy of", (out_last - out_first), "elements"); return out_last; } - - std::vector handles; - - DASH_LOG_TRACE("dash::copy", "local range:", - li_range_in.begin, - li_range_in.end, - "in_first.is_local:", in_first.is_local()); // Check if global input range is partially local: if (num_local_elem > 0) { - // Part of the input range is local, copy local input subrange to local - // output range directly. + // Part of the input range is local, copy local input subrange to + // local output range directly. auto pattern = in_first.pattern(); // Map input iterators to global index domain: auto g_in_first = in_first.global(); auto g_in_last = g_in_first + total_copy_elem; - DASH_LOG_TRACE("dash::copy", "resolving local subrange"); - DASH_LOG_TRACE_VAR("dash::copy", num_local_elem); + DASH_LOG_TRACE("dash::copy:range", "resolving local subrange"); + DASH_LOG_TRACE_VAR("dash::copy:range", num_local_elem); // Local index range to global input index range: // Global index of local range begin index: - auto g_l_offset_begin = pattern.global(li_range_in.begin); + auto g_l_offset_begin = pattern.global(li_range_in.first()); // Global index of local range end index: - auto g_l_offset_end = pattern.global(li_range_in.end-1) - + 1; // pat.global(l_end) would be out of range - DASH_LOG_TRACE("dash::copy", + // + // NOTE: definition as pat.global(l_end-1)+1 as + // pat.global(l_end) would be out of range + auto g_l_offset_end = pattern.global(li_range_in.last()) + 1; + DASH_LOG_TRACE("dash::copy:range", "global index range of local subrange:", "begin:", g_l_offset_begin, "end:", g_l_offset_end); // Global position of input start iterator: auto g_offset_begin = g_in_first.pos(); // Convert local subrange to global iterators: - auto g_l_in_first = g_in_first + (g_l_offset_begin - g_offset_begin); - auto g_l_in_last = g_in_first + (g_l_offset_end - g_offset_begin); - DASH_LOG_TRACE("dash::copy", "global it. range of local subrange:", - "begin:", g_l_in_first.pos(), "end:", g_l_in_last.pos()); - DASH_LOG_TRACE_VAR("dash::copy", g_l_in_last.pos()); + auto g_l_in_first = g_in_first + + (g_l_offset_begin - g_offset_begin); + auto g_l_in_last = g_in_first + + (g_l_offset_end - g_offset_begin); + DASH_LOG_TRACE("dash::copy:range", "global it. range of local subrange:", + "begin:", g_l_in_first.pos(), + "end:", g_l_in_last.pos()); + DASH_LOG_TRACE_VAR("dash::copy:range", g_l_in_last.pos()); auto num_prelocal_elem = g_l_in_first.pos() - g_in_first.pos(); auto num_postlocal_elem = in_last.pos() - g_l_offset_end; - DASH_LOG_TRACE_VAR("dash::copy", num_prelocal_elem); - DASH_LOG_TRACE_VAR("dash::copy", num_postlocal_elem); + DASH_LOG_TRACE_VAR("dash::copy:range", num_prelocal_elem); + DASH_LOG_TRACE_VAR("dash::copy:range", num_postlocal_elem); // - // ----------------------------------------------------------------------- + // ------------------------------------------------------------------- // Copy remote elements preceding the local subrange: // if (num_prelocal_elem > 0) { - DASH_LOG_TRACE("dash::copy", + DASH_LOG_TRACE("dash::copy:range", "copy global range preceding local subrange", "g_in_first:", g_in_first.pos(), "g_in_last:", g_l_in_first.pos()); // ... [ --- copy --- | ... l ... | ........ ] // ^ ^ ^ ^ // in_first l_in_first l_in_last in_last - out_last = dash::internal::copy_impl(g_in_first, + out_last = dash::internal::copy_block(g_in_first, g_l_in_first, - dest_first, - handles); + dest_first); // Advance output pointers: dest_first = out_last; } // - // ----------------------------------------------------------------------- + // ------------------------------------------------------------------- // Copy local subrange: // // Convert local subrange of global input to native pointers: @@ -644,14 +959,14 @@ ValueType * copy( // ValueType * l_in_first = g_l_in_first.local(); ValueType * l_in_last = l_in_first + num_local_elem; - DASH_LOG_TRACE_VAR("dash::copy", l_in_first); - DASH_LOG_TRACE_VAR("dash::copy", l_in_last); + DASH_LOG_TRACE_VAR("dash::copy:range", l_in_first); + DASH_LOG_TRACE_VAR("dash::copy:range", l_in_last); // Verify conversion of global input iterators to local pointers: DASH_ASSERT_MSG(l_in_first != nullptr, - "dash::copy: first index in global input (" << + "dash::copy:range: first index in global input (" << g_l_in_first.pos() << ") is not local"); - DASH_LOG_TRACE("dash::copy", "copy local subrange", + DASH_LOG_TRACE("dash::copy:range", "copy local subrange", "num_copy_elem:", l_in_last - l_in_first); // Use memcpy for data ranges below 64 KB if (use_memcpy) { @@ -666,132 +981,209 @@ ValueType * copy( } // Assert that all elements in local range have been copied: DASH_ASSERT_EQ(out_last, dest_first + num_local_elem, - "Expected to copy " << num_local_elem << " local elements " + "Expected to copy " << num_local_elem << + " local elements " "but copied " << (out_last - dest_first)); - DASH_LOG_TRACE("dash::copy", "finished local copy of", + DASH_LOG_TRACE("dash::copy:range", "finished local copy of", (out_last - dest_first), "elements"); // Advance output pointers: dest_first = out_last; // - // ----------------------------------------------------------------------- + // ------------------------------------------------------------------- // Copy remote elements succeeding the local subrange: // if (num_postlocal_elem > 0) { - DASH_LOG_TRACE("dash::copy", + DASH_LOG_TRACE("dash::copy:range", "copy global range succeeding local subrange", "in_first:", g_l_in_last.pos(), "in_last:", g_in_last.pos()); // ... [ ........ | ... l ... | --- copy --- ] // ^ ^ ^ ^ // in_first l_in_first l_in_last in_last - out_last = dash::internal::copy_impl(g_l_in_last, + out_last = dash::internal::copy_block(g_l_in_last, g_in_last, - dest_first, - handles); + dest_first); } } else { - DASH_LOG_TRACE("dash::copy", "no local subrange"); + DASH_LOG_TRACE("dash::copy:range", "no local subrange"); // All elements in input range are remote - out_last = dash::internal::copy_impl(in_first, - in_last, - dest_first, - handles); - } - - if (handles.size() > 0) { - DASH_LOG_TRACE("dash::copy", "Waiting for remote transfers to complete,", - "num_handles: ", handles.size()); - dart_waitall_local(handles.data(), handles.size()); + out_last = dash::internal::copy_block(in_first, + in_last, + dest_first); } - - DASH_LOG_TRACE("dash::copy >", "finished,", + DASH_LOG_TRACE("dash::copy:range >", "finished,", "out_last:", out_last); return out_last; } +/** + * Specialization of global to local copy for local iterators in global input + * range. + */ +template < + class ValueType, + class GlobInputIt, + typename std::enable_if< + std::is_pointer::value, + int >::type = 0 > +ValueType * copy( + GlobInputIt in_first, + GlobInputIt in_last, + ValueType * out_first) +{ + typedef typename GlobInputIt::pointer pointer_t; + + DASH_LOG_TRACE("dash::copy()", "blocking, local view iterator to local"); + DASH_LOG_TRACE_VAR("dash::copy", in_last - in_first); +// DASH_LOG_TRACE_VAR("dash::copy", in_first.viewspec().offsets()); +// DASH_LOG_TRACE_VAR("dash::copy", in_first.viewspec().extents()); +// DASH_LOG_TRACE_VAR("dash::copy", in_last.viewspec().offsets()); +// DASH_LOG_TRACE_VAR("dash::copy", in_last.viewspec().extents()); + auto out_last = std::copy(static_cast(in_first.local()), + static_cast(in_last.local()), + out_first); + DASH_LOG_TRACE_VAR("dash::copy", out_last - out_first); + DASH_LOG_TRACE_VAR("dash::copy >", out_last); + return out_last; +} + +template < + class ValueType, + class GlobInputIt, + typename std::enable_if< + !std::is_same::value, + int >::type = 0 > +ValueType * copy( + GlobInputIt in_first, + GlobInputIt in_last, + ValueType * out_first) +{ + DASH_LOG_TRACE("dash::copy()", "blocking, global to local"); + // Check if part of the input range is local: + DASH_LOG_TRACE_VAR("dash::copy", in_first.dart_gptr()); + DASH_LOG_TRACE_VAR("dash::copy", in_last.dart_gptr()); + DASH_LOG_TRACE_VAR("dash::copy", out_first); + + auto in_range = dash::make_range(in_first, in_last); + DASH_LOG_TRACE("dash::copy", "source value range type:", + dash::typestr(in_range)); + DASH_LOG_TRACE("dash::copy", "source value range:", in_range); + DASH_LOG_TRACE("dash::copy", "source index range:", dash::index(in_range)); + DASH_LOG_TRACE("dash::copy", "source range extents:", in_range.extents()); + DASH_LOG_TRACE("dash::copy", "source range offsets:", in_range.offsets()); + + return dash::copy(in_range, out_first); +} + -// ========================================================================= +// ====================================================================== // Local to Global, Distributed Range -// ========================================================================= +// ====================================================================== /** - * Variant of \c dash::copy as asynchronous local-to-global copy operation. + * Variant of \c dash::copy as asynchronous local-to-global copy + * operation. + * Output iterator type must specify dependent pattern type as + * \c GlobOutputIt::pattern_type. * * \ingroup DashAlgorithms */ template < - typename ValueType, + class ValueType, class GlobOutputIt > -dash::Future copy_async( - ValueType * in_first, - ValueType * in_last, - GlobOutputIt out_first) +auto copy_async( + ValueType * in_first, + ValueType * in_last, + GlobOutputIt out_first) + -> typename std::enable_if< + dash::has_type_pattern_type::value, + dash::Future + >::type { - auto handles = std::make_shared>(); - auto out_last = dash::internal::copy_impl(in_first, - in_last, - out_first, - *handles); - - if (handles->size() == 0) { - return dash::Future(out_last); + DASH_LOG_TRACE("dash::copy_async()", "blocking, local to global"); + // Return value, initialize with begin of output range, indicating no + // values have been copied: + GlobOutputIt out_last = out_first; + // Number of elements to copy in total: + auto num_elements = std::distance(in_first, in_last); + // Global iterator pointing at hypothetical end of output range: + GlobOutputIt out_h_last = out_first + num_elements; + + DASH_LOG_TRACE_VAR("dash::copy_async", num_elements); + // Futures of asynchronous get requests, one per block: + auto futures = std::vector< dash::Future >(); + auto out_range = dash::make_range(out_first, out_h_last); + auto out_blocks = dash::blocks(out_range); + auto in_copy_it = in_first; + + DASH_LOG_TRACE("dash::copy_async", + "number of blocks:", out_blocks.size()); + for (auto block : out_blocks) { + DASH_LOG_TRACE("dash::copy_async", "block size:", block.size()); + futures.push_back(static_cast>( + dash::internal::copy_block_async( + in_copy_it, + in_copy_it + block.size(), + block.begin())) ); + in_copy_it += block.size(); } - dash::Future fut_result( - // get - [=]() mutable { - // Wait for all get requests to complete: - GlobOutputIt _out = out_last; - DASH_LOG_TRACE("dash::copy_async [Future]()", - " wait for", handles->size(), "async put request"); - DASH_LOG_TRACE("dash::copy_async [Future]", " _out:", _out); - if (handles->size() > 0) { - if (dart_waitall(handles->data(), handles->size()) - != DART_OK) { - DASH_LOG_ERROR("dash::copy_async [Future]", - " dart_waitall failed"); - DASH_THROW( - dash::exception::RuntimeError, - "dash::copy_async [Future]: dart_waitall failed"); - } - } else { - DASH_LOG_TRACE("dash::copy_async [Future]", " No pending handles"); - } - handles->clear(); - DASH_LOG_TRACE("dash::copy_async [Future] >", - " async requests completed, _out:", _out); - return _out; - }, - // test - [=](GlobOutputIt *out) mutable { - int32_t flag; - DASH_ASSERT_RETURNS( - DART_OK, - dart_testall(handles->data(), handles->size(), &flag)); - if (flag) { - handles->clear(); - *out = out_last; - } - return (flag != 0); - }, - // destroy - [=]() mutable { - for (auto& handle : *handles) { - DASH_ASSERT_RETURNS( - DART_OK, - dart_handle_free(&handle)); - } + out_last += dash::distance(in_first, in_copy_it); + + dash::Future fut_result([=]() mutable { + auto _out = out_last; + DASH_LOG_TRACE("dash::copy_async [Future]()", + "wait for", futures.size(), "async copy requests"); + DASH_LOG_TRACE("dash::copy_async [Future]", " futures:", futures); + DASH_LOG_TRACE("dash::copy_async [Future]", " _out:", _out); + for (auto f : futures) { + f.wait(); } - ); + DASH_LOG_TRACE("dash::copy_async [Future] >", + "async requests completed", + "futures:", futures, "_out:", _out); + return _out; + }); + DASH_LOG_TRACE("dash::copy_async >", "finished,", + "expected out_last:", out_last); return fut_result; } /** - * Specialization of \c dash::copy as local-to-global blocking copy operation. + * Variant of \c dash::copy as asynchronous local-to-global copy + * operation. + * Output iterator type must specify dependent pattern type as + * \c GlobOutputIt::pattern_type. * * \ingroup DashAlgorithms */ template < - typename ValueType, + class ValueType, + class GlobOutputIt > +auto copy_async( + ValueType * in_first, + ValueType * in_last, + GlobOutputIt out_first) + -> typename std::enable_if< + !dash::has_type_pattern_type::value, + dash::Future + >::type +{ + DASH_LOG_TRACE("dash::copy_async()", + "blocking, local to global, restricted to single block"); + return dash::internal::copy_block_async( + in_first, + in_last, + out_first); +} + +/** + * Specialization of \c dash::copy as local-to-global blocking copy + * operation. + * + * \ingroup DashAlgorithms + */ +template < + class ValueType, class GlobOutputIt > GlobOutputIt copy( ValueType * in_first, @@ -799,112 +1191,231 @@ GlobOutputIt copy( GlobOutputIt out_first) { DASH_LOG_TRACE("dash::copy()", "blocking, local to global"); - // Return value, initialize with begin of output range, indicating no values - // have been copied: + // Return value, initialize with begin of output range, indicating no + // values have been copied: GlobOutputIt out_last = out_first; // Number of elements to copy in total: auto num_elements = std::distance(in_first, in_last); - DASH_LOG_TRACE_VAR("dash::copy", num_elements); // Global iterator pointing at hypothetical end of output range: GlobOutputIt out_h_last = out_first + num_elements; + + DASH_LOG_TRACE_VAR("dash::copy", num_elements); DASH_LOG_TRACE_VAR("dash::copy", out_first.pos()); DASH_LOG_TRACE_VAR("dash::copy", out_h_last.pos()); - // Test if a subrange of global output range is local: - auto li_range_out = local_index_range(out_first, out_h_last); - DASH_LOG_TRACE_VAR("dash::copy", li_range_out.begin); - DASH_LOG_TRACE_VAR("dash::copy", li_range_out.end); - // Number of elements in the local subrange: - auto num_local_elem = li_range_out.end - li_range_out.begin; - // handles to wait on at the end - std::vector handles; - // Check if part of the output range is local: - if (num_local_elem > 0) { - // Part of the output range is local - // Copy local input subrange to local output range directly: - auto pattern = out_first.pattern(); - DASH_LOG_TRACE("dash::copy", "resolving local subrange"); - DASH_LOG_TRACE_VAR("dash::copy", num_local_elem); - // Local index range to global output index range: - auto g_l_offset_begin = pattern.global(li_range_out.begin); - DASH_LOG_TRACE_VAR("dash::copy", g_l_offset_begin); - auto g_l_offset_end = pattern.global(li_range_out.end-1) - + 1; // pat.global(l_end) would be out of range - DASH_LOG_TRACE_VAR("dash::copy", g_l_offset_end); - // Offset of local subrange in output range - auto l_elem_offset = g_l_offset_begin - out_first.pos(); - DASH_LOG_TRACE_VAR("dash::copy",l_elem_offset); - // Convert local subrange of global output to native pointers: - ValueType * l_out_first = (out_first + l_elem_offset).local(); - DASH_LOG_TRACE_VAR("dash::copy", l_out_first); - ValueType * l_out_last = l_out_first + num_local_elem; - DASH_LOG_TRACE_VAR("dash::copy", l_out_last); - // ... [ ........ | ---- l ---- | ......... ] ... - // ^ ^ ^ ^ - // out_first l_out_first l_out_last out_last - out_last = out_first + num_local_elem; - // Assert that all elements in local range have been copied: - DASH_LOG_TRACE("dash::copy", "copying local subrange"); - DASH_LOG_TRACE_VAR("dash::copy", in_first); - DASH_ASSERT_RETURNS( - std::copy(in_first + l_elem_offset, - in_first + l_elem_offset + num_local_elem, - l_out_first), - l_out_last); - // Copy to remote elements preceding the local subrange: - if (g_l_offset_begin > out_first.pos()) { - DASH_LOG_TRACE("dash::copy", "copy to global preceding local subrange"); - out_last = dash::internal::copy_impl( - in_first, - in_first + l_elem_offset, - out_first, - handles); - } - // Copy to remote elements succeeding the local subrange: - if (g_l_offset_end < out_h_last.pos()) { - DASH_LOG_TRACE("dash::copy", "copy to global succeeding local subrange"); - out_last = dash::internal::copy_impl( - in_first + l_elem_offset + num_local_elem, - in_last, - out_first + num_local_elem, - handles); - } - } else { - // All elements in output range are remote - DASH_LOG_TRACE("dash::copy", "no local subrange"); - out_last = dash::internal::copy_impl( - in_first, - in_last, - out_first, - handles); + + auto out_range = dash::make_range(out_first, out_h_last); + + auto out_blocks = dash::blocks(out_range); + auto in_copy_it = in_first; + + DASH_LOG_TRACE("dash::copy", "number of blocks:", out_blocks.size()); + for (auto block : out_blocks) { + DASH_LOG_TRACE("dash::copy", "block size:", block.size()); + out_last = static_cast( + dash::internal::copy_block( + in_copy_it, + in_copy_it + block.size(), + block.begin())); + in_copy_it = in_first + dash::distance(out_first, out_last); } + return out_last; +} + +// ====================================================================== +// Global to Global, Distributed Range +// ====================================================================== + +/** + * Specialization of \c dash::copy as global-to-global blocking copy + * operation. + * + * \ingroup DashAlgorithms + */ + +template < + typename GlobInputRange, + typename GlobOutputRange, + typename std::enable_if< + ( dash::is_view::value && + dash::is_view::value ), + int >::type = 0 > +GlobOutputRange +// dash::IteratorRange< +// typename OutputRange::iterator, +// typename OutputRange::iterator > +copy(GlobInputRange && in_g_range, + GlobOutputRange out_g_range) +{ + DASH_LOG_TRACE("dash::copy()", "blocking, global to global"); + + DASH_LOG_TRACE("dash::copy()", "range(out_gi, out_ge):", + dash::typestr(out_g_range)); + DASH_LOG_TRACE_VAR("dash::copy()", out_g_range); + DASH_LOG_TRACE_VAR("dash::copy()", dash::index(out_g_range)); + + DASH_LOG_TRACE("dash::copy()", "range(in_gi, in_ge):", + dash::typestr(in_g_range)); + DASH_LOG_TRACE_VAR("dash::copy()", in_g_range); + DASH_LOG_TRACE_VAR("dash::copy()", dash::index(in_g_range)); + + auto in_blocks = dash::blocks(in_g_range); + DASH_LOG_TRACE_VAR("dash::copy()", in_blocks); - if (handles.size() > 0) { - DASH_LOG_TRACE("dash::copy", "Waiting for remote transfers to complete,", - "num_handles: ", handles.size()); - dart_waitall_local(handles.data(), handles.size()); + auto l_in_blocks = dash::local(in_blocks); + DASH_LOG_TRACE_VAR("dash::copy()", in_blocks); + + auto out_blocks = dash::blocks(out_g_range); + DASH_LOG_TRACE_VAR("dash::copy()", out_blocks); + + auto l_out_blocks = dash::local(out_blocks); + DASH_LOG_TRACE_VAR("dash::copy()", out_blocks); + + // Iterator to active output block: + auto out_block_it = out_blocks.begin(); + // Iterator local blocks in input range: + for (auto l_out_block : l_out_blocks) { + DASH_LOG_TRACE_VAR("dash::copy()", l_out_block); + DASH_LOG_TRACE_VAR("dash::copy()", + dash::global(dash::index(l_out_block))); } - return out_last; + // local view on in/out ranges: + auto out_l_range = dash::local(out_g_range); + DASH_LOG_TRACE("dash::copy()", "local(range(out_gi, out_ge)):", + dash::typestr(out_l_range)); + DASH_LOG_TRACE("dash::copy()", "local(range(out_gi, out_ge)):", + out_l_range); + DASH_LOG_TRACE("dash::copy()", "index(local(range(out_gi, out_ge))):", + dash::index(out_l_range)); + DASH_LOG_TRACE("dash::copy()", "global(index(local(range(o_gi,o_ge)))):", + dash::global(dash::index(out_l_range))); + + auto in_l_range = dash::local(in_g_range); + DASH_LOG_TRACE("dash::copy()", "local(range(in_gi, in_ge)):", + dash::typestr(in_l_range)); + DASH_LOG_TRACE("dash::copy()", "local(range(in_gi, in_ge)):", + in_l_range); + DASH_LOG_TRACE("dash::copy()", "index(local(range(in_gi, in_ge))):", + dash::index(in_l_range)); + + // Only sufficient if input- and output ranges have identical + // decomposition: + // + // auto out_l_end = std::copy(dash::begin(in_l_range), + // dash::end(in_l_range), + // dash::begin(out_l_range)); + + return out_g_range; +} + +/** + * Specialization of \c dash::copy as global-to-global blocking copy + * operation. + * + * \ingroup DashAlgorithms + */ +template < + class GlobInputIt, + class GlobOutputIt > +GlobOutputIt copy( + GlobInputIt in_first, + GlobInputIt in_last, + GlobOutputIt out_first) +{ + DASH_LOG_TRACE("dash::copy()", "blocking, global to global"); + + DASH_LOG_TRACE_VAR("dash::copy()", in_first); + DASH_LOG_TRACE_VAR("dash::copy()", in_last); + + auto num_elements = dash::distance(in_first, in_last); + DASH_LOG_TRACE_VAR("dash::copy()", num_elements); + DASH_LOG_TRACE_VAR("dash::copy()", out_first); + + auto out_h_last = out_first + num_elements; + DASH_LOG_TRACE_VAR("dash::copy()", out_h_last); + + // in/out ranges in global domain: + auto out_g_range = dash::make_range(out_first, out_h_last); + DASH_LOG_TRACE("dash::copy()", "range(out_gi, out_ge):", + dash::typestr(out_g_range)); + DASH_LOG_TRACE_VAR("dash::copy()", out_g_range); + DASH_LOG_TRACE_VAR("dash::copy()", dash::index(out_g_range)); + + auto in_g_range = dash::make_range(in_first, in_last); + DASH_LOG_TRACE("dash::copy()", "range(in_gi, in_ge):", + dash::typestr(in_g_range)); + DASH_LOG_TRACE_VAR("dash::copy()", in_g_range); + DASH_LOG_TRACE_VAR("dash::copy()", dash::index(in_g_range)); + + auto in_blocks = dash::blocks(in_g_range); + DASH_LOG_TRACE_VAR("dash::copy()", in_blocks); + + auto l_in_blocks = dash::local(in_blocks); + DASH_LOG_TRACE_VAR("dash::copy()", in_blocks); + + auto out_blocks = dash::blocks(out_g_range); + DASH_LOG_TRACE_VAR("dash::copy()", out_blocks); + + auto l_out_blocks = dash::local(out_blocks); + DASH_LOG_TRACE_VAR("dash::copy()", out_blocks); + + // Iterator to active output block: + auto out_block_it = out_blocks.begin(); + // Iterator local blocks in input range: + for (auto l_out_block : l_out_blocks) { + DASH_LOG_TRACE_VAR("dash::copy()", l_out_block); + DASH_LOG_TRACE_VAR("dash::copy()", dash::global(dash::index(l_out_block))); + } + + // local view on in/out ranges: + auto out_l_range = dash::local(out_g_range); + DASH_LOG_TRACE("dash::copy()", "local(range(out_gi, out_ge)):", + dash::typestr(out_l_range)); + DASH_LOG_TRACE("dash::copy()", "local(range(out_gi, out_ge)):", + out_l_range); + DASH_LOG_TRACE("dash::copy()", "index(local(range(out_gi, out_ge))):", + dash::index(out_l_range)); + DASH_LOG_TRACE("dash::copy()", "global(index(local(range(o_gi,o_ge)))):", + dash::global(dash::index(out_l_range))); + + auto in_l_range = dash::local(in_g_range); + DASH_LOG_TRACE("dash::copy()", "local(range(in_gi, in_ge)):", + dash::typestr(in_l_range)); + DASH_LOG_TRACE("dash::copy()", "local(range(in_gi, in_ge)):", + in_l_range); + DASH_LOG_TRACE("dash::copy()", "index(local(range(in_gi, in_ge))):", + dash::index(in_l_range)); + + // Only sufficient if input- and output ranges have identical + // decomposition: + // + // auto out_l_end = std::copy(dash::begin(in_l_range), + // dash::end(in_l_range), + // dash::begin(out_l_range)); + + return out_first + num_elements; } -// ========================================================================= +// ====================================================================== // Other Specializations -// ========================================================================= +// ====================================================================== #ifdef DASH_EXPERIMENTAL /* - * Specialization of \c dash::copy as global-to-local blocking copy operation - * returning an allocated range. + * Specialization of \c dash::copy as global-to-local blocking copy + * operation returning an allocated range. * Allows for zero-copy operations if the copied range is local. * * Returns a future of a local range { begin, end }. * If the requested data range is in shared memory, the range returned * references the native pointers of the target range. - * If the requested data range needed to be copied from remote memory, the - * range returned is the copied destination range such that begin = out_first - * and end = out_first + num_elem_copied. + * If the requested data range needed to be copied from remote memory, + * the range returned is the copied destination range such that + * \c (begin = out_first). + * and + * \c (end = out_first + num_elem_copied.) */ template < typename ValueType, @@ -937,30 +1448,6 @@ copy_async( } #endif -/** - * Specialization of \c dash::copy as global-to-global blocking copy - * operation. - * - * \ingroup DashAlgorithms - */ -template < - typename ValueType, - class GlobInputIt, - class GlobOutputIt > -GlobOutputIt copy( - GlobInputIt in_first, - GlobInputIt in_last, - GlobOutputIt out_first) -{ - DASH_LOG_TRACE("dash::copy()", "blocking, global to global"); - - // TODO: - // - Implement adapter for local-to-global dash::copy here - // - Return if global input range has no local sub-range - - return GlobOutputIt(); -} - #endif // DOXYGEN } // namespace dash diff --git a/dash/include/dash/algorithm/LocalRange.h b/dash/include/dash/algorithm/LocalRange.h index a6f045f8e..7eba6b532 100644 --- a/dash/include/dash/algorithm/LocalRange.h +++ b/dash/include/dash/algorithm/LocalRange.h @@ -72,6 +72,8 @@ local_index_range( /** * Resolves the local index range between global iterators. * + * Precondition: \c GlobInputIter is a view iterator. + * * \b Example: * * Total range | 0 1 2 3 4 5 6 7 8 9 @@ -94,10 +96,14 @@ local_index_range( * \ingroup DashAlgorithms */ template +#ifndef DOXYGEN typename std::enable_if< !GlobInputIter::has_view::value, LocalIndexRange >::type +#else + LocalIndexRange +#endif local_index_range( /// Iterator to the initial position in the global sequence const GlobInputIter & first, diff --git a/dash/include/dash/atomic/GlobAtomicRef.h b/dash/include/dash/atomic/GlobAtomicRef.h index e29cab720..1312d69d3 100644 --- a/dash/include/dash/atomic/GlobAtomicRef.h +++ b/dash/include/dash/atomic/GlobAtomicRef.h @@ -12,129 +12,105 @@ namespace dash { template class Atomic; +template +class Shared; + /** -* Specialization for atomic values. All atomic operations are -* \c const as the \c GlobRef does not own the atomic values. -*/ + * Specialization for atomic values. All atomic operations are + * \c const as the \c GlobRef does not own the atomic values. + */ template class GlobRef> { -/* Notes on type compatibility: -* -* - The general support of atomic operations on values of type T is -* checked in `dash::Atomic` and is not verified here. -* - Whether arithmetic operations (like `fetch_add`) are supported -* for values of type T is implicitly tested in the DASH operation -* types (like `dash::plus`) and is not verified here. -* -*/ - -template -friend std::ostream & operator<<( -std::ostream & os, -const GlobRef & gref); - -public: -using value_type = T; -using const_value_type = typename std::add_const::type; -using nonconst_value_type = typename std::remove_const::type; -using atomic_t = dash::Atomic; -using const_atomic_t = typename dash::Atomic; -using nonconst_atomic_t = typename dash::Atomic; -using self_t = GlobRef; -using const_type = GlobRef; -using nonconst_type = GlobRef>; + /* Notes on type compatibility: + * + * - The general support of atomic operations on values of type T is + * checked in `dash::Atomic` and is not verified here. + * - Whether arithmetic operations (like `fetch_add`) are supported + * for values of type T is implicitly tested in the DASH operation + * types (like `dash::plus`) and is not verified here. + * + */ -private: -dart_gptr_t _gptr; + template + friend std::ostream & operator<<( + std::ostream & os, + const GlobRef & gref); public: -/** -* Reference semantics forbid declaration without definition. -*/ -GlobRef() = delete; - -/** -* Constructor, creates an GlobRef object referencing an element in global -* memory. -*/ -template -explicit GlobRef( -/// Pointer to referenced object in global memory -GlobPtr & gptr) -: GlobRef(gptr.dart_gptr()) -{ } + typedef T + value_type; + typedef GlobRef> + const_type; -/** -* Constructor, creates an GlobRef object referencing an element in global -* memory. -*/ -template -GlobRef( -/// Pointer to referenced object in global memory -const GlobPtr & gptr) -: GlobRef(gptr.dart_gptr()) -{ -static_assert(std::is_same::value, - "Cannot create GlobRef> from GlobPtr>!"); -} - -template -GlobRef( -/// Pointer to referenced object in global memory -const GlobPtr & gptr) -: GlobRef(gptr.dart_gptr()) -{ } - - -/** -* Constructor, creates an GlobRef object referencing an element in global -* memory. -*/ -explicit GlobRef(dart_gptr_t dart_gptr) -: _gptr(dart_gptr) -{ -DASH_LOG_TRACE_VAR("GlobRef(dart_gptr_t)", dart_gptr); -} +private: + typedef dash::Atomic atomic_t; + typedef GlobRef self_t; -/** -* Like native references, global reference types cannot be copied. -* -* Default definition of copy constructor would conflict with semantics -* of \c operator=(const self_t &). -*/ -GlobRef(const self_t & other) = delete; +private: + dart_gptr_t _gptr; -/** -* Unlike native reference types, global reference types are moveable. -*/ -GlobRef(self_t && other) = default; +public: + /** + * Default constructor, creates an GlobRef object referencing an element in + * global memory. + */ + GlobRef() + : _gptr(DART_GPTR_NULL) { + } -self_t & operator=(const self_t & other) = delete; + /** + * Constructor, creates an GlobRef object referencing an element in global + * memory. + */ + template + explicit GlobRef( + /// Pointer to referenced object in global memory + GlobPtr & gptr) + : GlobRef(gptr.dart_gptr()) + { } -operator T() const { -return load(); -} + /** + * Constructor, creates an GlobRef object referencing an element in global + * memory. + */ + template + GlobRef( + /// Pointer to referenced object in global memory + const GlobPtr & gptr) + : GlobRef(gptr.dart_gptr()) + { } /** - * Implicit conversion to const type. + * Constructor, creates an GlobRef object referencing an element in global + * memory. */ - template::value,void>> - operator const_type() const { - return const_type(_gptr); + explicit GlobRef(dart_gptr_t dart_gptr) + : _gptr(dart_gptr) + { + DASH_LOG_TRACE_VAR("GlobRef(dart_gptr_t)", dart_gptr); } /** - * Explicit conversion to non-const type. + * Copy constructor. */ - template::value,void>> - explicit - operator nonconst_type() const { - return nonconst_type(_gptr); + GlobRef( + /// GlobRef instance to copy. + const GlobRef & other) + : _gptr(other._gptr) + { } + + self_t & operator=(const self_t & other) = delete; + + operator T() const { + return load(); } + operator GlobPtr() const { + DASH_LOG_TRACE("GlobRef.GlobPtr()", "conversion operator"); + DASH_LOG_TRACE_VAR("GlobRef.T()", _gptr); + return GlobPtr(_gptr); + } dart_gptr_t dart_gptr() const { return _gptr; @@ -145,22 +121,13 @@ return load(); * the calling unit's local memory. */ bool is_local() const { - return dash::internal::is_local(_gptr); + return GlobPtr(_gptr).is_local(); } - /** - * atomically assigns value - * - * \return The assigned value. - * - * \note This operator does not return a reference but a copy of the value - * in order to ensure atomicity. This is consistent with the C++ std::atomic - * \c operator=, see - * http://en.cppreference.com/w/cpp/atomic/atomic/operator%3D. - */ - T operator=(const T & value) const { + /// atomically assigns value + GlobRef operator=(const T & value) const { store(value); - return value; + return *this; } /** @@ -168,11 +135,6 @@ return load(); */ void set(const T & value) const { - static_assert(dash::dart_punned_datatype::value != DART_TYPE_UNDEFINED, - "Basic type or type smaller than 64bit required for " - "atomic set!"); - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef>!"); DASH_LOG_DEBUG_VAR("GlobRef.store()", value); DASH_LOG_TRACE_VAR("GlobRef.store", _gptr); dart_ret_t ret = dart_accumulate( @@ -190,19 +152,16 @@ return load(); * Set the value of the shared atomic variable. */ inline void store(const T & value) const { - set(value); + exchange(value); } /// atomically fetches value T get() const { - static_assert(dash::dart_punned_datatype::value != DART_TYPE_UNDEFINED, - "Basic type or type smaller than 64bit required for " - "atomic get!"); DASH_LOG_DEBUG("GlobRef.load()"); DASH_LOG_TRACE_VAR("GlobRef.load", _gptr); - nonconst_value_type nothing; - nonconst_value_type result; + value_type nothing; + value_type result; dart_ret_t ret = dart_fetch_and_op( _gptr, reinterpret_cast(¬hing), @@ -216,7 +175,7 @@ return load(); } /** - * Get the value of the shared atomic variable. + * Set the value of the shared atomic variable. */ inline T load() const { return get(); @@ -227,22 +186,13 @@ return load(); */ template void op( - /// Binary operation to be performed on global atomic variable BinaryOp binary_op, - /// Value to be used in binary op on global atomic variable. + /// Value to be added to global atomic variable. const T & value) const { - static_assert(dash::dart_punned_datatype::value != DART_TYPE_UNDEFINED, - "Basic type or type smaller than 64bit required for " - "atomic operation!"); - static_assert(dash::dart_datatype::value != DART_TYPE_UNDEFINED || - binary_op.op_kind() != dash::internal::OpKind::ARITHMETIC, - "Atomic arithmetic operations only valid on basic types"); - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef>!"); DASH_LOG_DEBUG_VAR("GlobRef.op()", value); DASH_LOG_TRACE_VAR("GlobRef.op", _gptr); - nonconst_value_type acc = value; + value_type acc = value; DASH_LOG_TRACE("GlobRef.op", "dart_accumulate"); dart_ret_t ret = dart_accumulate( _gptr, @@ -267,18 +217,10 @@ return load(); /// Value to be added to global atomic variable. const T & value) const { - static_assert(dash::dart_punned_datatype::value != DART_TYPE_UNDEFINED, - "Basic type or type smaller than 64bit required for " - "atomic fetch_op!"); - static_assert(dash::dart_datatype::value != DART_TYPE_UNDEFINED || - binary_op.op_kind() != dash::internal::OpKind::ARITHMETIC, - "Atomic arithmetic operations only valid on basic types!"); - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef>!"); DASH_LOG_DEBUG_VAR("GlobRef.fetch_op()", value); DASH_LOG_TRACE_VAR("GlobRef.fetch_op", _gptr); DASH_LOG_TRACE_VAR("GlobRef.fetch_op", typeid(value).name()); - nonconst_value_type res; + value_type res; dart_ret_t ret = dart_fetch_and_op( _gptr, reinterpret_cast(&value), @@ -307,19 +249,12 @@ return load(); * \see \c dash::atomic::compare_exchange */ bool compare_exchange(const T & expected, const T & desired) const { - static_assert(dash::dart_punned_datatype::value != DART_TYPE_UNDEFINED, - "Integral type or type smaller than 64bit required for " - "compare_exchange!"); - static_assert(!std::is_floating_point::value, - "compare_exchange not available for floating point!"); - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); DASH_LOG_DEBUG_VAR("GlobRef.compare_exchange()", desired); DASH_LOG_TRACE_VAR("GlobRef.compare_exchange", _gptr); DASH_LOG_TRACE_VAR("GlobRef.compare_exchange", expected); DASH_LOG_TRACE_VAR( "GlobRef.compare_exchange", typeid(desired).name()); - nonconst_value_type result; + value_type result; dart_ret_t ret = dart_compare_and_swap( _gptr, reinterpret_cast(&desired), @@ -339,8 +274,6 @@ return load(); */ void add(const T & value) const { - static_assert(std::is_same::value, - "Cannot modify value referenced by GlobRef!"); op(dash::plus(), value); } @@ -350,7 +283,7 @@ return load(); * \return The value of the referenced shared variable before the * operation. */ - T fetch_add ( + T fetch_add( /// Value to be added to global atomic variable. const T & value) const { @@ -379,104 +312,32 @@ return load(); return fetch_op(dash::plus(), -value); } - /** - * DASH specific variant which is faster than \c fetch_multiply - * but does not return value - */ - void multiply(const T & value) const - { - op(dash::multiply(), value); - } - - /** - * Atomic fetch-and-multiply operation on the referenced shared value. - * - * \return The value of the referenced shared variable before the - * operation. - */ - T fetch_multiply( - /// Value to be added to global atomic variable. - const T & value) const - { - return fetch_op(dash::multiply(), value); - } - - /** - * prefix atomically increment value by one - * - * \return The value of the referenced shared variable after the - * operation. - * - * \note This operator does not return a reference but a copy of the value - * in order to ensure atomicity. This is consistent with the C++ std::atomic - * \c operator++, see - * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith. - */ + /// prefix atomically increment value by one T operator++ () const { return fetch_add(1) + 1; } - /** - * postfix atomically increment value by one - * - * \return The value of the referenced shared variable before the - * operation. - */ + /// postfix atomically increment value by one T operator++ (int) const { return fetch_add(1); } - /** - * prefix atomically decrement value by one - * - * \return The value of the referenced shared variable after the - * operation. - * - * \note This operator does not return a reference but a copy of the value - * in order to ensure atomicity. This is consistent with the C++ std::atomic - * \c operator--, see - * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith. - */ + /// prefix atomically decrement value by one T operator-- () const { return fetch_sub(1) - 1; } - /** - * postfix atomically decrement value by one - * - * \return The value of the referenced shared variable before the - * operation. - */ + /// postfix atomically decrement value by one T operator-- (int) const { return fetch_sub(1); } - /** - * atomically increment value by ref - * - * \return The value of the referenced shared variable after the - * operation. - * - * \note This operator does not return a reference but a copy of the value - * in order to ensure atomicity. This is consistent with the C++ std::atomic - * \c operator+=, see - * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith2. - */ + /// atomically increment value by ref T operator+=(const T & value) const { return fetch_add(value) + value; } - /** - * atomically decrement value by ref - * - * \return The value of the referenced shared variable after the - * operation. - * - * Note that this operator does not return a reference but a copy of the value - * in order to ensure atomicity. This is consistent with the C++ std::atomic - * \c operator-=, see - * http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith2. - */ + /// atomically decrement value by ref T operator-=(const T & value) const { return fetch_sub(value) - value; } diff --git a/dash/include/dash/internal/StreamConversion.h b/dash/include/dash/internal/StreamConversion.h index e65bcd621..a23034ae2 100644 --- a/dash/include/dash/internal/StreamConversion.h +++ b/dash/include/dash/internal/StreamConversion.h @@ -4,11 +4,10 @@ #include #include +#include #include -#include - #include #include #include @@ -17,7 +16,9 @@ #include #include #include +#include #include +#include namespace dash { @@ -31,6 +32,30 @@ std::ostream & operator<<( dart_team_unit_t uid); +/** + * Write \c std::shared_ptr to output stream. + */ +template +std::ostream & operator<<( + std::ostream & os, + const std::shared_ptr & p) { + os << dash::typestr(p) + << "(" << p.get() << ")"; + return os; +} + +/** + * Write \c std::unique_ptr to output stream. + */ +template +std::ostream & operator<<( + std::ostream & os, + const std::unique_ptr & p) { + os << dash::typestr(p) + << "(" << p.get() << ")"; + return os; +} + /** * Write \c std::pair to output stream. */ @@ -137,8 +162,7 @@ auto operator<<( */ template < class Range, - class RangeDType = typename std::decay::type -> + class RangeDType = typename std::decay::type > auto operator<<( std::ostream & o, Range && range) @@ -162,7 +186,9 @@ auto operator<<( std::ostream & >::type { - typedef typename std::iterator_traits::value_type + typedef typename std::iterator_traits< + decltype(range.begin()) + >::value_type value_t; auto && rng = std::forward(range); @@ -177,6 +203,7 @@ auto operator<<( return operator<<(o, ss.str()); } + } // namespace dash #endif // DASH__INTERNAL__STREAM_CONVERSION_H_ diff --git a/dash/include/dash/iterator/GlobIter.h b/dash/include/dash/iterator/GlobIter.h index ec0f38094..ac2b73c91 100644 --- a/dash/include/dash/iterator/GlobIter.h +++ b/dash/include/dash/iterator/GlobIter.h @@ -53,12 +53,12 @@ template< class PointerType = typename GlobMemType::pointer, class ReferenceType = GlobRef > class GlobIter -: public std::iterator< - std::random_access_iterator_tag, - ElementType, - typename PatternType::index_type, - PointerType, - ReferenceType > +// : public std::iterator< +// std::random_access_iterator_tag, +// ElementType, +// typename PatternType::index_type, +// PointerType, +// ReferenceType > { private: typedef GlobIter< @@ -72,19 +72,25 @@ class GlobIter typedef typename std::remove_const::type nonconst_value_type; public: - typedef ElementType value_type; + typedef typename std::random_access_iterator_tag iterator_category; - typedef ReferenceType reference; - typedef typename ReferenceType::const_type const_reference; + typedef typename PatternType::index_type difference_type; - typedef PointerType pointer; - typedef typename PointerType::const_type const_pointer; + typedef ElementType value_type; - typedef typename GlobMemType::local_pointer local_pointer; - typedef typename GlobMemType::local_pointer local_type; + typedef ReferenceType reference; + typedef typename dash::const_value_cast::type + const_reference; - typedef PatternType pattern_type; - typedef typename PatternType::index_type index_type; + typedef PointerType pointer; + typedef typename dash::const_value_cast::type + const_pointer; + + typedef typename GlobMemType::local_pointer local_pointer; + typedef typename GlobMemType::local_pointer local_type; + + typedef PatternType pattern_type; + typedef typename PatternType::index_type index_type; private: typedef GlobIter< @@ -96,7 +102,7 @@ class GlobIter self_const_t; public: - typedef std::integral_constant has_view; + typedef std::integral_constant has_view; public: // For ostream output @@ -141,12 +147,23 @@ class GlobIter index_type _idx = 0; /// Maximum position allowed for this iterator. index_type _max_idx = 0; + /// Unit id of the active unit + team_unit_t _myid = DART_UNDEFINED_TEAM_UNIT_ID; /// Pointer to first element in local memory local_pointer _lbegin = nullptr; public: - - constexpr GlobIter() = default; + /** + * Default constructor. + */ + constexpr GlobIter() + : _globmem(nullptr), + _pattern(nullptr), + _idx(0), + _max_idx(0), + _myid(dash::Team::All().myid()), + _lbegin(nullptr) + { } /** * Constructor, creates a global iterator on global memory following @@ -154,59 +171,86 @@ class GlobIter */ constexpr GlobIter( GlobMemType * gmem, - const PatternType & pat, - index_type position = 0) + const PatternType & pat, + index_type position = 0) : _globmem(gmem), _pattern(&pat), _idx(position), _max_idx(pat.size() - 1), + _myid(pat.team().myid()), _lbegin(_globmem->lbegin()) { } /** * Copy constructor. */ + constexpr GlobIter(const self_t & other) = default; + + /** + * Templated copy constructor. + */ template < + class T_, + class P_, + class GM_, class Ptr_, class Ref_ > constexpr GlobIter( - const GlobIter & other) + const GlobIter & other) : _globmem(other._globmem) , _pattern(other._pattern) , _idx (other._idx) , _max_idx(other._max_idx) + , _myid (other._myid) , _lbegin (other._lbegin) { } /** * Move constructor. */ + constexpr GlobIter(self_t && other) = default; + + /** + * Templated move constructor. + */ template < + class T_, + class P_, + class GM_, class Ptr_, class Ref_ > constexpr GlobIter( - GlobIter && other) + GlobIter && other) : _globmem(other._globmem) , _pattern(other._pattern) , _idx (other._idx) , _max_idx(other._max_idx) + , _myid (other._myid) , _lbegin (other._lbegin) { } /** * Assignment operator. */ + self_t & operator=(const self_t & other) = default; + + /** + * Templated assignment operator. + */ template < typename T_, + class P_, + class GM_, class Ptr_, class Ref_ > self_t & operator=( - const GlobIter & other) + const GlobIter & other) { _globmem = other._globmem; _pattern = other._pattern; _idx = other._idx; _max_idx = other._max_idx; + _myid = other._myid; _lbegin = other._lbegin; return *this; } @@ -214,17 +258,25 @@ class GlobIter /** * Move-assignment operator. */ + self_t & operator=(self_t && other) = default; + + /** + * Templated move-assignment operator. + */ template < typename T_, + class P_, + class GM_, class Ptr_, class Ref_ > self_t & operator=( - GlobIter && other) + GlobIter && other) { _globmem = other._globmem; _pattern = other._pattern; _idx = other._idx; _max_idx = other._max_idx; + _myid = other._myid; _lbegin = other._lbegin; // no ownership to transfer return *this; @@ -329,7 +381,15 @@ class GlobIter "unit:", local_pos.unit, "local index:", local_pos.index); // Global pointer to element at given position: +#if 0 const_pointer gptr( +#else + // TODO: Intermediate, should be `const_pointer`. + // Actual issue is `const_pointer` defined as local pointer + // type, should be global pointer for global iterator like + // `GlobIter`: + dash::GlobPtr gptr( +#endif _globmem->at( team_unit_t(local_pos.unit), local_pos.index) @@ -406,7 +466,7 @@ class GlobIter */ constexpr bool is_local() const { - return (_globmem->team().myid() == lpos().unit); + return (_myid == lpos().unit); } /** @@ -442,7 +502,7 @@ class GlobIter local_pos_t local_pos = _pattern->local(idx); DASH_LOG_TRACE_VAR("GlobIter.local= >", local_pos.unit); DASH_LOG_TRACE_VAR("GlobIter.local= >", local_pos.index); - if (_globmem->team().myid() != local_pos.unit) { + if (_myid != local_pos.unit) { // Iterator position does not point to local element return nullptr; } @@ -688,7 +748,7 @@ std::ostream & operator<<( { std::ostringstream ss; dash::GlobPtr ptr(*it._globmem, - it.dart_gptr()); + it.dart_gptr()); ss << "dash::GlobIter<" << typeid(ElementType).name() << ">(" << "idx:" << it._idx << ", " << "gptr:" << ptr << ")"; diff --git a/dash/include/dash/iterator/GlobViewIter.h b/dash/include/dash/iterator/GlobViewIter.h index e697bba0a..243ffe94e 100644 --- a/dash/include/dash/iterator/GlobViewIter.h +++ b/dash/include/dash/iterator/GlobViewIter.h @@ -84,10 +84,12 @@ class GlobViewIter typedef ElementType value_type; typedef ReferenceType reference; - typedef typename ReferenceType::const_type const_reference; + typedef typename dash::const_value_cast::type + const_reference; typedef PointerType pointer; - typedef typename PointerType::const_type const_pointer; + typedef typename dash::const_value_cast::type + const_pointer; typedef typename GlobMemType::local_pointer local_pointer; typedef typename GlobMemType::local_pointer local_type; @@ -474,7 +476,7 @@ class GlobViewIter */ inline reference operator*() { - return this->operator[](_idx); + return this->operator[](0); } /** @@ -484,7 +486,7 @@ class GlobViewIter */ inline const_reference operator*() const { - return this->operator[](_idx); + return this->operator[](0); } /** @@ -493,22 +495,31 @@ class GlobViewIter */ reference operator[]( /// The global position of the element - index_type g_index) + index_type idx) { typedef typename pattern_type::local_index_t local_pos_t; // Global index to local index and unit: local_pos_t local_pos; + idx += _idx; + IndexType offset = 0; + // Convert iterator position (_idx) to local index and unit. + if (_idx > _max_idx) { + // Global iterator pointing past the range indexed by the pattern + // which is the case for .end() iterators. + idx = _max_idx; + offset += _idx - _max_idx; + } if (_viewspec == nullptr) { // No viewspec mapping required: - local_pos = _pattern->local(g_index); + local_pos = _pattern->local(idx); } else { // Viewspec projection required: - auto glob_coords = coords(g_index); + auto glob_coords = coords(idx); local_pos = _pattern->local_index(glob_coords); } DASH_LOG_TRACE("GlobViewIter.[]", - "(index:", g_index, " voffset:", _view_idx_offset, ") ->", + "(index:", idx, " voffset:", _view_idx_offset, ") ->", "(unit:", local_pos.unit, " index:", local_pos.index, ")"); // Global reference to element at given position: return reference( @@ -522,22 +533,31 @@ class GlobViewIter */ const_reference operator[]( /// The global position of the element - index_type g_index) const + index_type idx) const { typedef typename pattern_type::local_index_t local_pos_t; + idx += _idx; + IndexType offset = 0; + // Convert iterator position (_idx) to local index and unit. + if (_idx > _max_idx) { + // Global iterator pointing past the range indexed by the pattern + // which is the case for .end() iterators. + idx = _max_idx; + offset += _idx - _max_idx; + } // Global index to local index and unit: local_pos_t local_pos; if (_viewspec == nullptr) { // No viewspec mapping required: - local_pos = _pattern->local(g_index); + local_pos = _pattern->local(idx); } else { // Viewspec projection required: - auto glob_coords = coords(g_index); + auto glob_coords = coords(idx); local_pos = _pattern->local_index(glob_coords); } DASH_LOG_TRACE("GlobViewIter.[]", - "(index:", g_index, " voffset:", _view_idx_offset, ") ->", + "(index:", idx, " voffset:", _view_idx_offset, ") ->", "(unit:", local_pos.unit, " index:", local_pos.index, ")"); // Global reference to element at given position: return const_reference( @@ -675,7 +695,7 @@ class GlobViewIter /** * Unit and local offset at the iterator's position. - * Projects iterator position from its view spec to global index domain. + * Projects iterator position from its view spec to local index domain. */ inline typename pattern_type::local_index_t lpos() const { @@ -1074,10 +1094,12 @@ std::ostream & operator<<( ElementType, Pattern, GlobStaticMem, Pointer, Reference> & it) { std::ostringstream ss; - Pointer ptr(it.globmem(), it.dart_gptr()); - ss << "dash::GlobViewIter<" << typeid(ElementType).name() << ">(" + ss << "dash::GlobViewIter<" + << typeid(ElementType).name() << ", " + << typeid(Pointer).name() + << ">(" << "idx:" << it._idx << ", " - << "gptr:" << ptr << ")"; + << "gptr:" << it.global().dart_gptr() << ")"; return operator<<(os, ss.str()); } diff --git a/dash/include/dash/iterator/IteratorTraits.h b/dash/include/dash/iterator/IteratorTraits.h index d071e6f95..dc6471425 100644 --- a/dash/include/dash/iterator/IteratorTraits.h +++ b/dash/include/dash/iterator/IteratorTraits.h @@ -9,64 +9,104 @@ #include #include + namespace dash { namespace detail { -template -struct is_global_iterator : std::false_type { -}; + /** + * Definition of type trait \c dash::detail::has_type_domain_iterator + * with static member \c value indicating whether type \c T provides + * dependent type \c domain_iterator. + */ + DASH__META__DEFINE_TRAIT__HAS_TYPE(domain_iterator); -template < - typename ElementType, - class PatternType, - class GlobMemType, - class PointerType, - class ReferenceType> -struct is_global_iterator> : std::true_type { -}; -template < - typename ElementType, - class PatternType, - class GlobMemType, - class PointerType, - class ReferenceType> -struct is_global_iterator> : std::true_type { -}; + template + struct is_global_iterator : std::false_type { + }; -/// iterator traits index_type + template < + typename ElementType, + class PatternType, + class GlobMemType, + class PointerType, + class ReferenceType> + struct is_global_iterator> : std::true_type { + }; -DASH__META__DEFINE_TRAIT__HAS_TYPE(index_type) + template < + typename ElementType, + class PatternType, + class GlobMemType, + class PointerType, + class ReferenceType> + struct is_global_iterator> : std::true_type { + }; -template ::value> -struct iterator_traits_index_type { - typedef typename _Iter::index_type type; -}; + /// iterator traits index_type -template -struct iterator_traits_index_type<_Iter, false> { - typedef dash::default_index_t type; -}; + DASH__META__DEFINE_TRAIT__HAS_TYPE(index_type) + + template ::value> + struct iterator_traits_index_type { + typedef typename _Iter::index_type type; + }; + + template + struct iterator_traits_index_type<_Iter, false> { + typedef dash::default_index_t type; + }; } // namespace detail -template -struct iterator_traits : std::iterator_traits { - using is_global_iterator = typename detail::is_global_iterator; - using index_type = - typename detail::iterator_traits_index_type::type; + +template +struct iterator_traits +: public std::iterator_traits { + + using is_global_iterator + = typename detail::is_global_iterator; + + using is_view_iterator + = typename dash::detail::has_type_domain_iterator; + + using index_type + = typename detail::iterator_traits_index_type::type; + + using is_local + = typename std::integral_constant::value + >; +}; + +template +struct iterator_traits +: public std::iterator_traits { + + using is_global_iterator + = typename detail::is_global_iterator; + + using is_view_iterator + = std::integral_constant; + + using index_type + = typename detail::iterator_traits_index_type::type; + + using is_local + = typename std::integral_constant; }; } // namespace dash + #endif diff --git a/dash/include/dash/iterator/LocalViewIter.h b/dash/include/dash/iterator/LocalViewIter.h new file mode 100644 index 000000000..59216923b --- /dev/null +++ b/dash/include/dash/iterator/LocalViewIter.h @@ -0,0 +1,1007 @@ +#ifndef DASH__LOCAL_VIEW_ITER_H__INCLUDED +#define DASH__LOCAL_VIEW_ITER_H__INCLUDED + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace dash { + +#ifndef DOXYGEN +// Forward-declaration +template< + typename ElementType, + class PatternType, + class GlobMemType, + class PointerType, + class ReferenceType > +class GlobIter; +// Forward-declaration +template< + typename ElementType, + class PatternType, + class GlobMemType, + class PointerType, + class ReferenceType > +class GlobStencilIter; +#endif + +/** + * Global iterator on an index set specified by a view modifier. + * + * \concept{DashGlobalIteratorConcept} + */ +template< + typename ElementType, + class PatternType, + class GlobMemType = GlobStaticMem< + typename std::decay::type + >, + class PointerType = ElementType *, + class ReferenceType = ElementType & > +class LocalViewIter +: public std::iterator< + std::random_access_iterator_tag, + ElementType, + typename PatternType::index_type, + PointerType, + ReferenceType > { +private: + typedef LocalViewIter< + ElementType, + PatternType, + GlobMemType, + PointerType, + ReferenceType> + self_t; + + typedef GlobIter< + ElementType, + PatternType, + GlobMemType, + PointerType, + ReferenceType> + global_type; + + typedef GlobIter< + const ElementType, + PatternType, + GlobMemType, + PointerType, + ReferenceType> + const_global_type; + + typedef typename std::remove_const::type + nonconst_value_type; + + typedef typename PatternType::viewspec_type + ViewSpecType; + typedef typename PatternType::index_type + IndexType; + +public: + typedef ElementType value_type; + + typedef ReferenceType reference; + typedef typename dash::const_value_cast::type + const_reference; + + typedef PointerType pointer; + typedef typename dash::const_value_cast::type + const_pointer; + + typedef typename GlobMemType::local_pointer local_pointer; + typedef typename GlobMemType::local_pointer local_type; + + typedef PatternType pattern_type; + typedef typename PatternType::index_type index_type; + +private: + typedef LocalViewIter< + const ElementType, + PatternType, + GlobMemType, + const_pointer, + const_reference > + self_const_t; + +public: + typedef std::integral_constant has_view; + +public: + // For ostream output + template < + typename T_, + class P_, + class GM_, + class Ptr_, + class Ref_ > + friend std::ostream & operator<<( + std::ostream & os, + const LocalViewIter & it); + + // For conversion to GlobStencilIter + template< + typename T_, + class P_, + class Ptr_, + class GM_, + class Ref_ > + friend class GlobStencilIter; + + template< + typename T_, + class P_, + class GM_, + class Ptr_, + class Ref_ > + friend class LocalViewIter; + + template< + typename T_, + class P_, + class GM_, + class Ptr_, + class Ref_ > + friend class GlobIter; + +private: + static const dim_t NumDimensions = PatternType::ndim(); + static const MemArrange Arrangement = PatternType::memory_order(); + +protected: + /// Global memory used to dereference iterated values. + GlobMemType * _globmem; + /// Pattern that specifies the iteration order (access pattern). + const PatternType * _pattern; + /// View that specifies the iterator's index range relative to the global + /// index range of the iterator's pattern. + const ViewSpecType * _viewspec; + /// Current position of the iterator relative to the iterator's view. + IndexType _idx = 0; + /// The iterator's view index start offset. + IndexType _view_idx_offset = 0; + /// Maximum position relative to the viewspec allowed for this iterator. + IndexType _max_idx = 0; + /// Unit id of the active unit + team_unit_t _myid; + /// Pointer to first element in local memory + local_pointer _lbegin = nullptr; + +public: + /** + * Default constructor. + */ + constexpr LocalViewIter() + : _globmem(nullptr) + , _pattern(nullptr) + , _viewspec(nullptr) + , _idx(0) + , _view_idx_offset(0) + , _max_idx(0) + , _myid(dash::Team::All().myid()) + , _lbegin(nullptr) + { } + + /** + * Constructor, creates a global iterator on global memory following + * the element order specified by the given pattern and view spec. + */ + template + constexpr LocalViewIter( + GlobStaticMemT_ * gmem, + const PatternType & pat, + const ViewSpecType & viewspec, + IndexType position = 0, + IndexType view_index_offset = 0) + : _globmem(reinterpret_cast(gmem)) + , _pattern(&pat) + , _viewspec(&viewspec) + , _idx(position) + , _view_idx_offset(view_index_offset) + , _max_idx(viewspec.size() - 1) + , _myid(pat.team().myid()) + , _lbegin(_globmem->lbegin()) + { } + + /** + * Constructor, creates a global iterator on global memory following + * the element order specified by the given pattern and view spec. + */ + template + constexpr LocalViewIter( + GlobStaticMemT_ * gmem, + const PatternType & pat, + IndexType position = 0, + IndexType view_index_offset = 0) + : _globmem(reinterpret_cast(gmem)) + , _pattern(&pat) + , _viewspec(nullptr) + , _idx(position) + , _view_idx_offset(view_index_offset) + , _max_idx(pat.size() - 1) + , _myid(dash::Team::GlobalUnitID()) + , _lbegin(_globmem->lbegin()) + { } + + /** + * Constructor, creates a global view iterator from a global iterator. + */ + template < + class P_, + class GM_, + class Ptr_, + class Ref_ > + constexpr LocalViewIter( + const GlobIter & other, + const ViewSpecType & viewspec, + IndexType view_offs = 0) + : _globmem(other._globmem) + , _pattern(other._pattern) + , _viewspec(&viewspec) + , _idx(other._idx) + , _view_idx_offset(view_offs) + , _max_idx(other._max_idx) + , _myid(other._myid) + , _lbegin(other._lbegin) + { } + + /** + * Copy constructor. + */ + template < + typename T_, + class P_, + class GM_, + class Ptr_, + class Ref_ > + constexpr LocalViewIter( +// const LocalViewIter & other) + const LocalViewIter & other) + : _globmem (other._globmem) + , _pattern (other._pattern) + , _viewspec (other._viewspec) + , _idx (other._idx) + , _view_idx_offset(other._view_idx_offset) + , _max_idx (other._max_idx) + , _myid (other._myid) + , _lbegin (other._lbegin) + { } + + /** + * Move constructor. + */ + template < + typename T_, + class P_, + class GM_, + class Ptr_, + class Ref_ > + constexpr LocalViewIter( +// LocalViewIter && other) + LocalViewIter && other) + : _globmem (other._globmem) + , _pattern (other._pattern) + , _viewspec (other._viewspec) + , _idx (other._idx) + , _view_idx_offset(other._view_idx_offset) + , _max_idx (other._max_idx) + , _myid (other._myid) + , _lbegin (other._lbegin) + { } + + /** + * Assignment operator. + */ + template < + typename T_, + class P_, + class GM_, + class Ptr_, + class Ref_ > + self_t & operator=( + const LocalViewIter & other) + { + _globmem = other._globmem; + _pattern = other._pattern; + _viewspec = other._viewspec; + _idx = other._idx; + _view_idx_offset = other._view_idx_offset; + _max_idx = other._max_idx; + _myid = other._myid; + _lbegin = other._lbegin; + } + + /** + * Move-assignment operator. + */ + template < + typename T_, + class P_, + class GM_, + class Ptr_, + class Ref_ > + self_t & operator=( + LocalViewIter && other) + { + _globmem = other._globmem; + _pattern = other._pattern; + _viewspec = other._viewspec; + _idx = other._idx; + _view_idx_offset = other._view_idx_offset; + _max_idx = other._max_idx; + _myid = other._myid; + _lbegin = other._lbegin; + // no ownership to transfer + return *this; + } + + /** + * The number of dimensions of the iterator's underlying pattern. + */ + static dim_t ndim() + { + return NumDimensions; + } + + /** + * Type conversion operator to \c GlobPtr. + * + * \return A global reference to the element at the iterator's position + */ + explicit operator const_pointer() const + { + return local(); + } + + /** + * Type conversion operator to native pointer. + * + * \return A global reference to the element at the iterator's position + */ + explicit operator pointer() + { + return local(); + } + + /** + * Explicit conversion to \c dart_gptr_t. + * + * \return A DART global pointer to the element at the iterator's + * position + */ + dart_gptr_t dart_gptr() const + { + DASH_LOG_TRACE_VAR("LocalViewIter.dart_gptr()", _idx); + typedef typename pattern_type::local_index_t + local_pos_t; + IndexType idx = _idx; + IndexType offset = 0; + // Convert iterator position (_idx) to local index and unit. + if (_idx > _max_idx) { + // Global iterator pointing past the range indexed by the pattern + // which is the case for .end() iterators. + idx = _max_idx; + offset += _idx - _max_idx; + } + // Global index to local index and unit: + local_pos_t local_pos = lpos(); + DASH_LOG_TRACE("LocalViewIter.dart_gptr", + "unit:", local_pos.unit, + "local index:", local_pos.index); + // Global pointer to element at given position: + dash::GlobPtr gptr( + _globmem->at( + local_pos.unit, + local_pos.index) + ); + DASH_LOG_TRACE_VAR("GlobIter.dart_gptr >", gptr); + return (gptr + offset).dart_gptr(); + } + + /** + * Dereference operator. + * + * \return A global reference to the element at the iterator's position. + */ + inline reference operator*() + { + return this->operator[](0); + } + + /** + * Dereference operator. + * + * \return A global reference to the element at the iterator's position. + */ + inline const_reference operator*() const + { + return this->operator[](0); + } + + /** + * Subscript operator, returns global reference to element at given + * global index. + */ + reference operator[]( + /// The global position of the element + index_type idx) + { + DASH_LOG_TRACE_VAR("LocalViewIter.[]=()", idx); + idx += _idx; + IndexType offset = 0; + if (_idx > _max_idx) { + // Global iterator pointing past the range indexed by the pattern + // which is the case for .end() iterators. + idx = _max_idx; + offset += _idx - _max_idx; + } + // Local coords at index, applies viewspec: + auto l_coords = coords(idx); + // Local index with respect to local block layout: + idx = _pattern->local_at(l_coords); + DASH_LOG_TRACE("LocalViewIter.[]= >", + "globmem.lbegin:", _globmem->lbegin(), + "+", idx); + // Global reference to element at given position: + return *(_globmem->lbegin() + idx + offset); + } + + /** + * Subscript operator, returns global reference to element at given + * global index. + */ + const_reference operator[]( + /// The global position of the element + index_type idx) const + { + DASH_LOG_TRACE_VAR("LocalViewIter.[]()", idx); + idx += _idx; + IndexType offset = 0; + if (_idx > _max_idx) { + // Global iterator pointing past the range indexed by the pattern + // which is the case for .end() iterators. + idx = _max_idx; + offset += _idx - _max_idx; + } + // Local coords at index, applies viewspec: + auto l_coords = coords(idx); + // Local index with respect to local block layout: + idx = _pattern->local_at(l_coords); + DASH_LOG_TRACE("LocalViewIter.[] >", + "globmem.lbegin:", _globmem->lbegin(), + "+ index", idx, + "+ tail", offset); + // Global reference to element at given position: + return *(_globmem->lbegin() + idx + offset); + } + + /** + * Checks whether the element referenced by this global iterator is in + * the calling unit's local memory. + */ + constexpr bool is_local() const + { + return true; + } + + /** + * Convert global iterator to native pointer. + */ + local_pointer local() const + { + DASH_LOG_TRACE_VAR("LocalViewIter.local=()", _idx); + typedef typename pattern_type::local_index_t + local_pos_t; + IndexType idx = _idx; + IndexType offset = 0; + DASH_LOG_TRACE_VAR("LocalViewIter.local=", _max_idx); + // Convert iterator position (_idx) to local index and unit. + if (_idx > _max_idx) { + // Global iterator pointing past the range indexed by the pattern + // which is the case for .end() iterators. + idx = _max_idx; + offset += _idx - _max_idx; + } + // Local coords at index, applies viewspec: + auto l_coords = coords(idx); + // Local index with respect to local block layout: + idx = _pattern->local_at(l_coords); + DASH_LOG_TRACE_VAR("LocalViewIter.local=", idx); + DASH_LOG_TRACE_VAR("LocalViewIter.local=", offset); + + if (_viewspec != nullptr) { + // Viewspec projection required: + idx = _pattern->local_memory_layout().at(coords(idx)); + } + DASH_LOG_TRACE_VAR("LocalViewIter.local= >", idx); + DASH_LOG_TRACE_VAR("LocalViewIter.local= >", offset); + return (_lbegin + idx + offset); + } + + /** + * Map iterator to global index domain by projecting the iterator's view. + */ + inline const_global_type global() const + { + auto g_idx = gpos(); + return const_global_type( + _globmem, + *_pattern, + g_idx + ); + } + + /** + * Map iterator to global index domain by projecting the iterator's view. + */ + inline global_type global() + { + return global_type( + _globmem, + *_pattern, + gpos() + ); + } + + /** + * Position of the iterator in its view's iteration space and the view's + * offset in global index space. + */ + constexpr index_type pos() const noexcept + { + return _idx + _view_idx_offset; + } + + /** + * Position of the iterator in its view's iteration space, disregarding + * the view's offset in global index space. + */ + inline index_type rpos() const noexcept + { + return _idx; + } + + /** + * Position of the iterator in global index range. + * Projects iterator position from its view spec to global index domain. + */ + inline index_type gpos() const + { + DASH_LOG_TRACE_VAR("LocalViewIter.gpos()", _idx); + + IndexType idx = _idx; + IndexType offset = 0; + DASH_LOG_TRACE_VAR("LocalViewIter.gpos", _max_idx); + // Convert iterator position (_idx) to local index and unit. + if (_idx > _max_idx) { + // Global iterator pointing past the range indexed by the pattern + // which is the case for .end() iterators. + idx = _max_idx; + offset += _idx - _max_idx; + } + // Local coords at index, applies viewspec: + auto l_coords = coords(idx); + // Global index with respect to local block layout: + IndexType g_idx = _pattern->global_index(_myid, l_coords); + DASH_LOG_TRACE_VAR("LocalViewIter.gpos", g_idx); + g_idx += offset; + DASH_LOG_TRACE_VAR("LocalViewIter.gpos >", g_idx); + return g_idx; + } + + /** + * Unit and local offset at the iterator's position. + * Projects iterator position from its view spec to global index domain. + */ + inline typename pattern_type::local_index_t lpos() const + { + DASH_LOG_TRACE_VAR("LocalViewIter.lpos()", _idx); + + typedef typename pattern_type::local_index_t + local_pos_t; + IndexType idx = _idx; + IndexType offset = 0; + // Convert iterator position (_idx) to local index and unit. + if (_idx > _max_idx) { + // Global iterator pointing past the range indexed by the pattern + // which is the case for .end() iterators. + idx = _max_idx; + offset = _idx - _max_idx; + } + // Local coords at index, applies viewspec: + auto l_coords = coords(idx); + // Local index with respect to local block layout: + idx = _pattern->local_at(l_coords); + + local_pos_t local_pos; + local_pos.unit = _myid; + local_pos.index = idx + offset; + DASH_LOG_TRACE("LocalViewIter.lpos >", + "unit:", local_pos.unit, + "local index:", local_pos.index); + return local_pos; + } + + /** + * Whether the iterator's position is relative to a view. + */ + inline bool is_relative() const noexcept + { + return _viewspec != nullptr; + } + + /** + * The view that specifies this iterator's index range. + */ + inline ViewSpecType viewspec() const + { + if (_viewspec != nullptr) { + return *_viewspec; + } + return ViewSpecType(_pattern->memory_layout().extents()); + } + + /** + * The instance of \c GlobStaticMem used by this iterator to resolve addresses + * in global memory. + */ + constexpr const GlobMemType & globmem() const noexcept + { + return *_globmem; + } + + /** + * The instance of \c GlobStaticMem used by this iterator to resolve addresses + * in global memory. + */ + inline GlobMemType & globmem() noexcept + { + return *_globmem; + } + + /** + * Prefix increment operator. + */ + self_t & operator++() noexcept + { + ++_idx; + return *this; + } + + /** + * Postfix increment operator. + */ + self_t operator++(int) noexcept + { + self_t result = *this; + ++_idx; + return result; + } + + /** + * Prefix decrement operator. + */ + self_t & operator--() noexcept + { + --_idx; + return *this; + } + + /** + * Postfix decrement operator. + */ + self_t operator--(int) noexcept + { + self_t result = *this; + --_idx; + return result; + } + + self_t & operator+=(index_type n) noexcept + { + _idx += n; + return *this; + } + + self_t & operator-=(index_type n) noexcept + { + _idx -= n; + return *this; + } + + self_t operator+(index_type n) const noexcept + { + if (_viewspec == nullptr) { + self_t res( + _globmem, + *_pattern, + _idx + static_cast(n), + _view_idx_offset); + return res; + } + self_t res( + _globmem, + *_pattern, + *_viewspec, + _idx + static_cast(n), + _view_idx_offset); + return res; + } + + self_t operator-(index_type n) const noexcept + { + if (_viewspec == nullptr) { + self_t res( + _globmem, + *_pattern, + _idx - static_cast(n), + _view_idx_offset); + return res; + } + self_t res( + _globmem, + *_pattern, + *_viewspec, + _idx - static_cast(n), + _view_idx_offset); + return res; + } + + index_type operator+( + const self_t & other) const noexcept + { + return _idx + other._idx; + } + + index_type operator-( + const self_t & other) const + { + return _idx - other._idx; + } + + inline bool operator<(const self_t & other) const noexcept + { + // NOTE: + // This function call is significantly slower than the explicit + // implementation in operator== and operator!=. + return compare(other, + std::less(), + std::less()); + } + + inline bool operator<=(const self_t & other) const noexcept + { + // NOTE: + // This function call is significantly slower than the explicit + // implementation in operator== and operator!=. + return compare(other, + std::less_equal(), + std::less_equal()); + } + + inline bool operator>(const self_t & other) const noexcept + { + // NOTE: + // This function call is significantly slower than the explicit + // implementation in operator== and operator!=. + return compare(other, + std::greater(), + std::greater()); + } + + inline bool operator>=(const self_t & other) const noexcept + { + // NOTE: + // This function call is significantly slower than the explicit + // implementation in operator== and operator!=. + return compare(other, + std::greater_equal(), + std::greater_equal()); + } + + inline bool operator==(const self_t & other) const noexcept + { + // NOTE: See comments in method compare(). + if (_viewspec == other._viewspec) { + // Same viewspec pointer + return _idx == other._idx; + } + if ((_viewspec != nullptr && other._viewspec != nullptr) && + (*_viewspec) == *(other._viewspec)) { + // Viewspec instances are equal + return _idx == other._idx; + } + auto lhs_local = lpos(); + auto rhs_local = other.lpos(); + return (lhs_local.unit == rhs_local.unit && + lhs_local.index == rhs_local.index); + } + + inline bool operator!=(const self_t & other) const noexcept + { + // NOTE: See comments in method compare(). + if (_viewspec == other._viewspec) { + // Same viewspec pointer + return _idx != other._idx; + } + if ((_viewspec != nullptr && other._viewspec != nullptr) && + (*_viewspec) == *(other._viewspec)) { + // Viewspec instances are equal + return _idx != other._idx; + } + auto lhs_local = lpos(); + auto rhs_local = other.lpos(); + return (lhs_local.unit != rhs_local.unit || + lhs_local.index != rhs_local.index); + } + + constexpr const PatternType & pattern() const noexcept + { + return *_pattern; + } + + constexpr dash::Team & team() const noexcept + { + return _pattern->team(); + } + +private: + /** + * Compare position of this global iterator to the position of another + * global iterator with respect to viewspec projection. + */ + template< + class LocalIndexCmpFun, + class LocalPtrCmpFun > + bool compare( + const self_t & other, + const LocalIndexCmpFun & lidx_cmp, + const LocalPtrCmpFun & lptr_cmp) const noexcept + { +#if __REMARK__ + // Usually this is a best practice check, but it's an infrequent case + // so we rather avoid this comparison: + if (this == &other) { + return true; + } +#endif + // NOTE: + // Do not check _idx first, as it would never match for comparison with + // an end iterator. + if (_viewspec == other._viewspec) { + // Same viewspec pointer + return lidx_cmp(_idx, other._idx); + } + if ((_viewspec != nullptr && other._viewspec != nullptr) && + (*_viewspec) == *(other._viewspec)) { + // Viewspec instances are equal + return lidx_cmp(_idx, other._idx); + } + // View projection at lhs and/or rhs set. + // Convert both to GlobPtr (i.e. apply view projection) and compare. + // + // NOTE: + // This conversion is quite expensive but will never be necessary + // if both iterators have been created from the same range. + // Example: + // a.block(1).begin() == a.block(1).end(). + // does not require viewspace projection while + // a.block(1).begin() == a.end() + // does. The latter case should be avoided for this reason. + const pointer lhs_ptr(dart_gptr()); + const pointer rhs_ptr(other.dart_gptr()); + return lptr_cmp(lhs_ptr, rhs_ptr); + } + + /** + * Convert a local offset within the local iterator's range to + * corresponding local coordinates with respect to viewspec projection. + * + * This method is bounds-checked and might throw. + * + * \note + * This method could be specialized for NumDimensions = 1 for performance + * tuning. + */ + std::array coords( + IndexType l_index) const + { + DASH_LOG_TRACE_VAR("LocalViewIter.coords()", l_index); + // Global cartesian coords of current iterator position: + std::array l_coords; + if (_viewspec != nullptr) { + DASH_LOG_TRACE_VAR("LocalViewIter.coords", *_viewspec); + // Create cartesian index space from extents of view projection: + CartesianIndexSpace index_space( + _viewspec->extents()); + // Initialize global coords with view coords (coords of iterator + // position in view index space): + l_coords = index_space.coords(l_index); + // Apply offset of view projection to view coords: + for (dim_t d = 0; d < NumDimensions; ++d) { + l_coords[d] += _viewspec->offset(d); + } + } else { + l_coords = _pattern->local_memory_layout().coords(l_index); + } + DASH_LOG_TRACE_VAR("LocalViewIter.coords >", l_coords); + return l_coords; + } + +}; // class LocalViewIter + +/** + * Resolve the number of elements between two global iterators. + * + * The difference of global pointers is not well-defined if their range + * spans over more than one block. + * The corresponding invariant is: + * g_last == g_first + (l_last - l_first) + * Example: + * + * \code + * unit: 0 1 0 + * local offset: | 0 1 2 | 0 1 2 | 3 4 5 | ... + * global offset: | 0 1 2 3 4 5 6 7 8 ... + * range: [- - - - -] + * \endcode + * + * When iterating in local memory range [0,5[ of unit 0, the position of the + * global iterator to return is 8 != 5 + * + * \tparam ElementType Type of the elements in the range + * \complexity O(1) + * + * \ingroup Algorithms + */ +template< + typename ElementT, + class Pattern, + class GlobStaticMem, + class Pointer, + class Reference > +auto distance( + const LocalViewIter & + first, + /// Global iterator to the final position in the global sequence + const LocalViewIter & + last) +-> typename Pattern::index_type +{ + return last - first; +} + +template < + typename ElementT, + class Pattern, + class GlobStaticMem, + class Pointer, + class Reference > +std::ostream & operator<<( + std::ostream & os, + const dash::LocalViewIter< + ElementT, Pattern, GlobStaticMem, Pointer, Reference> & it) +{ + std::ostringstream ss; + ss << "dash::LocalViewIter<" + << typeid(ElementT).name() << ", " + << typeid(Pointer).name() + << ">(" + << "idx:" << it._idx << ", " + << "gptr:" << it.global().dart_gptr() << ")"; + return operator<<(os, ss.str()); +} + +} // namespace dash + +#endif // DASH__LOCAL_VIEW_ITER_H__INCLUDED diff --git a/dash/include/dash/iterator/internal/IteratorBase.h b/dash/include/dash/iterator/internal/IteratorBase.h index 1abe61b36..8908250d7 100644 --- a/dash/include/dash/iterator/internal/IteratorBase.h +++ b/dash/include/dash/iterator/internal/IteratorBase.h @@ -85,12 +85,12 @@ class IndexIteratorBase } derived_t & operator++() { - _pos++; + ++_pos; return derived(); } derived_t & operator--() { - _pos--; + --_pos; return derived(); } diff --git a/dash/include/dash/matrix/LocalMatrixRef.h b/dash/include/dash/matrix/LocalMatrixRef.h index 11dab1a19..bfe75178c 100644 --- a/dash/include/dash/matrix/LocalMatrixRef.h +++ b/dash/include/dash/matrix/LocalMatrixRef.h @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -90,18 +91,26 @@ class LocalMatrixRef typedef typename PatternT::size_type size_type; typedef typename PatternT::index_type difference_type; +#if 1 + typedef LocalViewIter< value_type, PatternT> iterator; + typedef LocalViewIter const_iterator; + + typedef LocalViewIter< value_type, PatternT> pointer; + typedef LocalViewIter const_pointer; +#else typedef GlobViewIter< value_type, PatternT> iterator; typedef GlobViewIter const_iterator; + typedef GlobViewIter< value_type, PatternT> pointer; + typedef GlobViewIter const_pointer; +#endif + typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; typedef GlobRef< value_type> reference; typedef GlobRef const_reference; - typedef GlobViewIter< value_type, PatternT> pointer; - typedef GlobViewIter const_pointer; - typedef T * local_pointer; typedef const T * const_local_pointer; @@ -205,7 +214,7 @@ class LocalMatrixRef * not have a pattern. The pattern of the referenced matrix * refers to the global data domain. */ - constexpr const PatternT & pattern() const; + constexpr const PatternT & pattern() const noexcept; inline iterator begin() noexcept; constexpr const_iterator begin() const noexcept; diff --git a/dash/include/dash/matrix/internal/LocalMatrixRef-inl.h b/dash/include/dash/matrix/internal/LocalMatrixRef-inl.h index e48d6f060..9a01a10cc 100644 --- a/dash/include/dash/matrix/internal/LocalMatrixRef-inl.h +++ b/dash/include/dash/matrix/internal/LocalMatrixRef-inl.h @@ -32,11 +32,10 @@ ::LocalMatrixRef( { auto local_extents = mat->_pattern.local_extents(); DASH_LOG_TRACE_VAR("LocalMatrixRef(mat)", local_extents); - // Global offset to first local element is missing: - // _refview._viewspec.resize(local_extents); - std::array local_begin_coords = {{ }}; - auto local_offsets = mat->_pattern.global(local_begin_coords); - _refview._viewspec = ViewSpec_t(local_offsets, local_extents); +//std::array local_begin_coords = {{ }}; +//auto local_offsets = mat->_pattern.global(local_begin_coords); + _refview._viewspec = ViewSpec_t(local_extents); + _refview._l_viewspec = ViewSpec_t(local_extents); DASH_LOG_TRACE_VAR("LocalMatrixRef(mat) >", _refview._viewspec); } @@ -159,7 +158,7 @@ ::extent( (NumDim - 1), "got ", dim); assert(false); } - return _refview._viewspec.extent(dim); + return _refview._l_viewspec.extent(dim); } template @@ -167,7 +166,7 @@ constexpr std::array LocalMatrixRef ::extents() const noexcept { - return _refview._viewspec.extents(); + return _refview._l_viewspec.extents(); } template @@ -182,7 +181,7 @@ ::offset( (NumDim - 1), "got ", dim); assert(false); } - return _refview._viewspec.offset(dim); + return _refview._l_viewspec.offset(dim); } template @@ -190,7 +189,7 @@ constexpr std::array LocalMatrixRef ::offsets() const noexcept { - return _refview._viewspec.offsets(); + return _refview._l_viewspec.offsets(); } template @@ -202,8 +201,18 @@ ::empty() const noexcept } template -inline typename LocalMatrixRef::iterator +constexpr const +typename LocalMatrixRef::pattern_type & LocalMatrixRef +::pattern() const noexcept +{ + return _refview._mat->_pattern; +} + +#if 0 +template +inline typename LocalMatrixRef::iterator +LocalMatrixRef ::begin() noexcept { return iterator( @@ -218,6 +227,25 @@ ::begin() noexcept _refview._l_viewspec) ); } +#endif + +template +inline typename LocalMatrixRef::iterator +LocalMatrixRef +::begin() noexcept +{ + return iterator( + _refview._mat->_glob_mem, + _refview._mat->_pattern, + _refview._l_viewspec, + // iterator position in view index space + 0, + // view index start offset + _refview._mat->_pattern.local_at( + _refview._coord, + _refview._l_viewspec) + ); +} template constexpr typename LocalMatrixRef::const_iterator @@ -227,7 +255,7 @@ ::begin() const noexcept return const_iterator( _refview._mat->_glob_mem, _refview._mat->_pattern, - _refview._viewspec, + _refview._l_viewspec, // iterator position in view index space 0, // view index start offset @@ -290,7 +318,7 @@ typename LocalMatrixRef::size_type constexpr LocalMatrixRef ::size() const noexcept { - return _refview._viewspec.size(); + return _refview._l_viewspec.size(); } template diff --git a/dash/include/dash/meta/TypeInfo.h b/dash/include/dash/meta/TypeInfo.h index b0e2bb5e8..87a9d4d27 100644 --- a/dash/include/dash/meta/TypeInfo.h +++ b/dash/include/dash/meta/TypeInfo.h @@ -11,29 +11,35 @@ namespace internal { } /** - * Returns string containing the type name of the given object. + * Returns string containing the name of the specified type. * * Similar to the `typeid` operator but ensures human-readable, demangled * format. */ template -std::string typestr(const T & obj) { - return dash::internal::demangle( - typeid(obj).name() - ); +std::string typestr() { + typedef typename std::remove_reference::type TR; + std::string r = dash::internal::demangle(typeid(TR).name()); + if (std::is_const::value) + r = "const " + r; + if (std::is_volatile::value) + r = "volatile " + r; + if (std::is_lvalue_reference::value) + r += "&"; + else if (std::is_rvalue_reference::value) + r += "&&"; + return r; } /** - * Returns string containing the name of the specified type. + * Returns string containing the type name of the given object. * * Similar to the `typeid` operator but ensures human-readable, demangled * format. */ template -std::string typestr() { - return dash::internal::demangle( - typeid(T).name() - ); +std::string typestr(T && val) { + return typestr(val))>(); } } // namespace dash diff --git a/dash/include/dash/pattern/BlockPattern1D.h b/dash/include/dash/pattern/BlockPattern1D.h index a49818f93..f26e49cc9 100644 --- a/dash/include/dash/pattern/BlockPattern1D.h +++ b/dash/include/dash/pattern/BlockPattern1D.h @@ -1201,7 +1201,7 @@ class BlockPattern<1, Arrangement, IndexType> constexpr std::array initialize_local_range(SizeType l_size) const { return (l_size == 0) - ? std::array {{ 0, 0 }} + ? std::array {{ }} : std::array {{ global(0), global(l_size - 1) + 1 diff --git a/dash/include/dash/pattern/CSRPattern.h b/dash/include/dash/pattern/CSRPattern.h index a516895a9..6ec6803bf 100644 --- a/dash/include/dash/pattern/CSRPattern.h +++ b/dash/include/dash/pattern/CSRPattern.h @@ -586,6 +586,7 @@ class CSRPattern<1, Arrangement, IndexType> { return std::array {{ _local_sizes[_team->myid()] }}; } + /** * The actual number of elements in this pattern that are local to the * given unit, by dimension. @@ -885,6 +886,14 @@ class CSRPattern<1, Arrangement, IndexType> return _blockspec; } + /** + * Cartesian arrangement of local pattern blocks. + */ + constexpr const BlockSpec_t local_blockspec() const noexcept + { + return BlockSpec_t { 1 }; + } + /** * Index of block at given global coordinates. * @@ -897,6 +906,25 @@ class CSRPattern<1, Arrangement, IndexType> return static_cast(unit_at(g_coords[0])); } + /** + * Unit and local block index at given global coordinates. + * + * \see DashPatternConcept + */ + local_index_t local_block_at( + /// Global coordinates of element + const std::array & g_coords) const + { + local_index_t l_pos; + + auto unit_id = unit_at(g_coords[0]); + // auto block_size = _local_sizes[unit_id]; + // index_type offset = _block_offsets[unit_id]; + l_pos.unit = _teamspec.at({ unit_id }); + l_pos.index = 0; + return l_pos; + } + /** * View spec (offset and extents) of block at global linear block index * in cartesian element space. diff --git a/dash/include/dash/pattern/PatternProperties.h b/dash/include/dash/pattern/PatternProperties.h index 44e704e42..65d64b881 100644 --- a/dash/include/dash/pattern/PatternProperties.h +++ b/dash/include/dash/pattern/PatternProperties.h @@ -776,26 +776,30 @@ struct pattern_layout_traits template struct pattern_traits { - typedef typename PatternType::index_type + typedef typename std::decay::type pattern_type; + + typedef typename pattern_type::index_type index_type; - typedef typename PatternType::size_type + typedef typename pattern_type::size_type size_type; - typedef typename dash::pattern_partitioning_traits::type + typedef typename dash::pattern_partitioning_traits::type partitioning; - typedef typename dash::pattern_mapping_traits::type + typedef typename dash::pattern_mapping_traits::type mapping; - typedef typename dash::pattern_layout_traits::type + typedef typename dash::pattern_layout_traits::type layout; typedef typename std::decay< - decltype(std::declval().blockspec()) + decltype(std::declval().blockspec()) >::type blockspec_type; typedef typename std::decay< - decltype(std::declval().local_blockspec()) + decltype(std::declval().local_blockspec()) >::type local_blockspec_type; + + typedef std::integral_constant ndim; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/dash/include/dash/pattern/SeqTilePattern.h b/dash/include/dash/pattern/SeqTilePattern.h index 646899080..d6246ef8f 100644 --- a/dash/include/dash/pattern/SeqTilePattern.h +++ b/dash/include/dash/pattern/SeqTilePattern.h @@ -41,9 +41,9 @@ namespace dash { * */ template< - dim_t NumDimensions, - MemArrange Arrangement = ROW_MAJOR, - typename IndexType = dash::default_index_t> + dim_t NumDimensions, + MemArrange Arrangement = ROW_MAJOR, + typename IndexType = dash::default_index_t> class SeqTilePattern { public: @@ -266,7 +266,7 @@ class SeqTilePattern _local_blockspec(initialize_local_blockspec( _blockspec)), _local_memory_layout( - initialize_local_extents(_myid)), + initialize_local_extents(_local_blockspec)), _local_capacity( initialize_local_capacity(_local_memory_layout)) { DASH_LOG_TRACE("SeqTilePattern()", "(sizespec, dist, teamspec, team)"); @@ -332,7 +332,7 @@ class SeqTilePattern _local_blockspec(initialize_local_blockspec( _blockspec)), _local_memory_layout( - initialize_local_extents(_myid)), + initialize_local_extents(_local_blockspec)), _local_capacity( initialize_local_capacity(_local_memory_layout)) { DASH_LOG_TRACE("SeqTilePattern()", "(sizespec, dist, team)"); @@ -937,8 +937,8 @@ class SeqTilePattern } /** - * Global coordinates to global position in the pattern's block-wise iteration - * order. + * Global coordinates to global position in the pattern's block-wise + * iteration order. * * NOTE: * Expects extent[d] to be a multiple of blocksize[d] * nunits[d] @@ -1168,6 +1168,35 @@ class SeqTilePattern return block_idx; } + /** + * Local index of block at given global coordinates. + * + * \see DashPatternConcept + */ + local_index_t local_block_at( + /// Global coordinates of element + const std::array & g_coords) const + { + std::array block_coords; + // Coord to block coord to unit coord: + for (auto d = 0; d < NumDimensions; ++d) { + block_coords[d] = g_coords[d] / _blocksize_spec.extent(d); + } + // Block coord to block index: + auto block_idx = _blockspec.at(block_coords); + DASH_LOG_TRACE("SeqTilePattern.block_at", + "coords", g_coords, + "> block index", block_idx); + return local_index_t { + // unit id: + static_cast( + block_idx % _teamspec.size()), + // local block index: + static_cast( + block_idx / _teamspec.size()) + }; + } + /** * View spec (offset and extents) of block at global linear block index * in global cartesian element space. @@ -1559,12 +1588,22 @@ class SeqTilePattern // Number of local blocks in all dimensions: std::array l_blocks; auto min_local_blocks = num_blocks_total / _nunits; - l_blocks[0] = min_local_blocks; - if (unit_id < num_blocks_total % _nunits) { - l_blocks[0]++; - } - for (auto d = 1; d < NumDimensions; ++d) { - l_blocks[d] = 1; + if (Arrangement == dash::COL_MAJOR) { + l_blocks[0] = min_local_blocks; + if (unit_id < num_blocks_total % _nunits) { + l_blocks[0]++; + } + for (auto d = 1; d < NumDimensions; ++d) { + l_blocks[d] = 1; + } + } else { + l_blocks[NumDimensions - 1] = min_local_blocks; + if (unit_id < num_blocks_total % _nunits) { + l_blocks[NumDimensions - 1]++; + } + for (auto d = NumDimensions - 2; d >= 0; --d) { + l_blocks[d] = 1; + } } DASH_LOG_TRACE_VAR("SeqTilePattern.init_local_blockspec >", l_blocks); return BlockSpec_t(l_blocks); @@ -1611,9 +1650,8 @@ class SeqTilePattern * Resolve extents of local memory layout for a specified unit. */ std::array initialize_local_extents( - team_unit_t unit) const + team_unit_t unit) const { - DASH_LOG_DEBUG_VAR("SeqTilePattern.init_local_extents()", unit); auto l_blockspec = initialize_local_blockspec( _blockspec, unit); @@ -1626,6 +1664,22 @@ class SeqTilePattern DASH_LOG_DEBUG_VAR("SeqTilePattern.init_local_extents >", l_extents); return l_extents; } + + /** + * Resolve extents of local memory layout for a specified local blockspec. + */ + std::array initialize_local_extents( + const BlockSpec_t & l_blockspec) const + { + DASH_LOG_DEBUG_VAR("SeqTilePattern.init_local_extents()", + l_blockspec.extents()); + ::std::array l_extents; + for (auto d = 0; d < NumDimensions; ++d) { + l_extents[d] = _blocksize_spec.extent(d) * l_blockspec.extent(d); + } + DASH_LOG_DEBUG_VAR("SeqTilePattern.init_local_extents >", l_extents); + return l_extents; + } }; template< diff --git a/dash/include/dash/pattern/ShiftTilePattern.h b/dash/include/dash/pattern/ShiftTilePattern.h index c2e052671..6ddb6eaf1 100644 --- a/dash/include/dash/pattern/ShiftTilePattern.h +++ b/dash/include/dash/pattern/ShiftTilePattern.h @@ -1154,9 +1154,24 @@ class ShiftTilePattern /// Global coordinates of element const std::array & g_coords) const { - DASH_THROW( - dash::exception::NotImplemented, - "ShiftTilePattern.local_block_at is not implemented"); + local_index_t l_pos; + l_pos.unit = 0; + + std::array l_block_coords; + for (dim_t d = 0; d < NumDimensions; ++d) { + auto nunits_d = _teamspec.extent(d); + auto blocksize_d = _blocksize_spec.extent(d); + auto block_coord_d = g_coords[d] / blocksize_d; + l_block_coords[d] = block_coord_d / nunits_d; + l_pos.unit = (l_pos.unit + block_coord_d) % _teamspec.size(); + } + l_pos.index = _local_blockspec.at(l_block_coords); + + DASH_LOG_TRACE("ShiftTilePattern.local_block_at >", + "coords", g_coords, + "unit:", l_pos.unit, + "local block index:", l_pos.index); + return l_pos; } /** diff --git a/dash/include/dash/pattern/internal/LocalPattern.h b/dash/include/dash/pattern/internal/LocalPattern.h new file mode 100644 index 000000000..4d91a0eff --- /dev/null +++ b/dash/include/dash/pattern/internal/LocalPattern.h @@ -0,0 +1,58 @@ +#ifndef DASH__PATTERN__INTERNAL__LOCAL_PATTERN_H__INCLUDED +#define DASH__PATTERN__INTERNAL__LOCAL_PATTERN_H__INCLUDED + +#include + +#include + + +namespace dash { +namespace internal { + +template< + dim_t NumDimensions, + MemArrange Arrangement = dash::ROW_MAJOR, + typename IndexType = dash::default_index_t > +class LocalPattern; + + + +template< + MemArrange Arrangement, + typename IndexType > +class LocalPattern<1, Arrangement, IndexType> { +private: + static const dim_t NumDimensions = 1; + +public: + static constexpr char const * PatternName = "LocalPattern"; + +public: + /// Satisfiable properties in pattern property category Partitioning: + typedef pattern_partitioning_properties< + // Block extents are constant for every dimension. + pattern_partitioning_tag::rectangular, + // Identical number of elements in every block. + pattern_partitioning_tag::balanced, + // Size of blocks may differ. + pattern_partitioning_tag::unbalanced + > partitioning_properties; + /// Satisfiable properties in pattern property category Mapping: + typedef pattern_mapping_properties< + // Number of blocks assigned to a unit may differ. + pattern_mapping_tag::unbalanced + > mapping_properties; + /// Satisfiable properties in pattern property category Layout: + typedef pattern_layout_properties< + // Local indices iterate over block boundaries. + pattern_layout_tag::canonical, + // Local element order corresponds to canonical linearization + // within entire local memory. + pattern_layout_tag::linear + > layout_properties; +}; + +} // namespace internal +} // namespace dash + +#endif // DASH__PATTERN__INTERNAL__LOCAL_PATTERN_H__INCLUDED diff --git a/dash/include/dash/pattern/internal/PatternLogging.h b/dash/include/dash/pattern/internal/PatternLogging.h index c86f363fc..06e9408c9 100644 --- a/dash/include/dash/pattern/internal/PatternLogging.h +++ b/dash/include/dash/pattern/internal/PatternLogging.h @@ -3,6 +3,7 @@ #include #include +#include #include #include diff --git a/dash/include/dash/view/Apply.h b/dash/include/dash/view/Apply.h index a3f6db5cb..f940e9339 100644 --- a/dash/include/dash/view/Apply.h +++ b/dash/include/dash/view/Apply.h @@ -2,9 +2,6 @@ #define DASH__VIEW__APPLY_H__INCLUDED #include -#include - -#include namespace dash { diff --git a/dash/include/dash/view/Block.h b/dash/include/dash/view/Block.h index c04f3e7f3..574c7ef7c 100644 --- a/dash/include/dash/view/Block.h +++ b/dash/include/dash/view/Block.h @@ -6,26 +6,57 @@ #include #include +#include namespace dash { -#if 0 /** * * \concept{DashViewConcept} */ template < - class ViewT, - class BlockIndexT > -constexpr typename std::enable_if< - dash::view_traits::is_view::value, - dash::ViewBlockMod ->::type + class ViewT, + class BlockIndexT, + dim_t NDim + = dash::view_traits::rank::value, + typename std::enable_if< + dash::view_traits::is_view::value, + int >::type = 0 +> +constexpr auto block(BlockIndexT block_index, const ViewT & view) { - return ViewBlockMod(view, block_index); + return ViewBlockMod(view, block_index); +} + +template < + class ViewT, + class BlockIndexT, + dim_t NDim + = dash::view_traits::rank::value, + typename std::enable_if< + !dash::view_traits::is_view::value, + int >::type = 0 +> +constexpr auto +block(BlockIndexT block_index, const ViewT & view) { + return dash::blocks(view)[block_index]; +} + +template < + class BlockIndexT, + typename std::enable_if< + std::is_integral< + typename std::decay::type + >::value, + int + >::type = 0 > +static inline auto block(BlockIndexT b) { + return dash::make_pipeable( + [=](auto && x) { + return block(b, std::forward(x)); + }); } -#endif } diff --git a/dash/include/dash/view/Chunked.h b/dash/include/dash/view/Chunked.h deleted file mode 100644 index 188be233f..000000000 --- a/dash/include/dash/view/Chunked.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef DASH__VIEW__CHUNKED_H__INCLUDED -#define DASH__VIEW__CHUNKED_H__INCLUDED - -#include -#include - -#include -#include -#include -#include -#include -#include - - -namespace dash { - -// ------------------------------------------------------------------------ -// Forward-declarations -// ------------------------------------------------------------------------ - -template < - class DomainType > -class ViewBlockMod; - -#if 0 -template < - class ContainerType, - class OffsetT > -constexpr auto -block( - OffsetT block_idx, - const ContainerType & container) --> typename std::enable_if< - !dash::view_traits::is_view::value, - decltype(container.block(0)) - >::type { - return container.block(block_idx); -} -#endif - -/** - * Blocks view from global view - * - */ -template < - class ViewType, - class OffsetT > -constexpr auto -block( - OffsetT block_idx, - const ViewType & view) --> typename std::enable_if< - (// dash::view_traits::is_view::value && - !dash::view_traits::is_local::value ), - ViewBlockMod - >::type { - return ViewBlockMod(view, block_idx); -} - -/** - * Blocks view from local view - * - */ -template < - class ViewType, - class OffsetT > -constexpr auto -block( - OffsetT block_idx, - const ViewType & view) --> typename std::enable_if< - (// dash::view_traits::is_view::value && - dash::view_traits::is_local::value ), - decltype(dash::block(block_idx, dash::local(dash::origin(view)))) - >::type { - return dash::local(dash::origin(view)).block(block_idx); -} - -} // namespace dash - -#endif // DASH__VIEW__CHUNKED_H__INCLUDED diff --git a/dash/include/dash/view/Chunks.h b/dash/include/dash/view/Chunks.h new file mode 100644 index 000000000..d7583581f --- /dev/null +++ b/dash/include/dash/view/Chunks.h @@ -0,0 +1,43 @@ +#ifndef DASH__VIEW__CHUNK_H__INCLUDED +#define DASH__VIEW__CHUNK_H__INCLUDED + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace dash { + +// ------------------------------------------------------------------------ +// Forward-declarations +// ------------------------------------------------------------------------ + +/** + * Chunked view from global view. + * + */ +template < + class ViewType, + class OffsetT > +constexpr auto +chunks( + OffsetT block_idx, + const ViewType & view) + -> typename std::enable_if< + (// dash::view_traits::is_view::value && + !dash::view_traits::is_local::value ), + ViewChunksMod + >::type { + return ViewChunksMod(view, block_idx); +} + +} // namespace dash + +#endif // DASH__VIEW__CHUNK_H__INCLUDED diff --git a/dash/include/dash/view/Domain.h b/dash/include/dash/view/Domain.h index cb790a8c3..a912c3fc3 100644 --- a/dash/include/dash/view/Domain.h +++ b/dash/include/dash/view/Domain.h @@ -2,13 +2,30 @@ #define DASH__VIEW__DOMAIN_H__INCLUDED #include -#include +#include -#include +#include namespace dash { +namespace detail { + + /** + * Definition of type trait \c dash::detail::has_type_domain_type + * with static member \c value indicating whether type \c T provides + * dependent type \c domain_type. + */ + DASH__META__DEFINE_TRAIT__HAS_TYPE(domain_type); + +} + +// ----------------------------------------------------------------------- +// Forward-declarations + +template +struct view_traits; + // ------------------------------------------------------------------------ // dash::domain(View) @@ -22,7 +39,6 @@ template < constexpr auto domain(ViewT && view) -> typename std::enable_if< - // dash::view_traits::is_view::value, dash::detail::has_type_domain_type::value, decltype(std::forward(view).domain()) >::type { @@ -34,10 +50,8 @@ constexpr auto domain(const ViewT & view) -> typename std::enable_if< dash::detail::has_type_domain_type::value, - // dash::view_traits::is_view::value, decltype(view.domain()) // const typename dash::view_traits::domain_type & - // const typename ViewT::domain_type & >::type { return view.domain(); } @@ -53,7 +67,6 @@ template < class ContainerT, typename ContainerValueT = typename std::decay::type > constexpr typename std::enable_if< -//!dash::view_traits::is_view::value, !dash::detail::has_type_domain_type::value, ContainerT & >::type @@ -69,7 +82,6 @@ template < class ContainerT, typename ContainerValueT = typename std::decay::type > constexpr typename std::enable_if< -//!dash::view_traits::is_view::value, !dash::detail::has_type_domain_type::value, const ContainerT & >::type @@ -77,6 +89,13 @@ domain(const ContainerT & container) { return container; } +static inline auto domain() { + return dash::make_pipeable( + [](auto && x) { + return domain(std::forward(x)); + }); +} + } // namespace dash #endif // DASH__VIEW__DOMAIN_H__INCLUDED diff --git a/dash/include/dash/view/Expand.h b/dash/include/dash/view/Expand.h new file mode 100644 index 000000000..e786e2b53 --- /dev/null +++ b/dash/include/dash/view/Expand.h @@ -0,0 +1,185 @@ +#ifndef DASH__VIEW__EXPAND_H__INCLUDED +#define DASH__VIEW__EXPAND_H__INCLUDED + +#include +#include + +#include +#include +#include +#include + + +namespace dash { + +/** + * Origin cannot be expanded. + * + */ +template < + dim_t SubDim = 0, + class OriginT, + class OffsetFirstT, + class OffsetFinalT, + typename OriginValueT + = typename std::decay::type +> +constexpr auto +expand( + OffsetFirstT begin, + OffsetFinalT end, + OriginT && origin) + -> typename std::enable_if< + dash::view_traits::is_origin::value, + decltype(std::forward(origin)) + >::type { + return std::forward(origin); +} + + +namespace detail { + + template < + dim_t CurDim, + dim_t SubDim, + class DomainT, + class OffsetFirstT, + class OffsetFinalT, + typename OffsetsT, + typename ExtentsT, + typename std::enable_if< (CurDim < 0), char >::type = 0 + > + constexpr auto + expand_dim( + OffsetFirstT begin, + OffsetFinalT end, + DomainT && domain, + OffsetsT cur_offsets, + ExtentsT cur_extents) { + return std::forward(domain); + } + + template < + dim_t CurDim, + dim_t SubDim, + class DomainT, + class OffsetFirstT, + class OffsetFinalT, + typename DomainValueT + = typename std::decay::type, + typename OffsetsT, + typename ExtentsT, + typename std::enable_if< (CurDim >= 0), char >::type = 0 + > + constexpr auto + expand_dim( + OffsetFirstT begin, + OffsetFinalT end, + DomainT && domain, + OffsetsT cur_offsets, + ExtentsT cur_extents) { + return expand_dim( + begin, end, + ( CurDim == SubDim + // span in current dimension is to be expanded + ? dash::sub( + ( cur_offsets[CurDim] + begin > 0 + ? cur_offsets[CurDim] + begin + : 0 ), + ( cur_offsets[CurDim] + cur_extents[CurDim] + end < + domain.extents()[CurDim] + ? cur_offsets[CurDim] + cur_extents[CurDim] + end + : domain.extents()[CurDim] ), + std::forward(domain)) + // span in current dimension is unchanged + : dash::sub( + (cur_offsets[CurDim]), + (cur_offsets[CurDim] + cur_extents[CurDim]), + std::forward(domain)) + ), + cur_offsets, + cur_extents); + } + +} // namespace detail + + +template < + dim_t SubDim = 0, + class DomainT, + class OffsetFirstT, + class OffsetFinalT, + typename DomainValueT + = typename std::decay::type, + dim_t NDim + = dash::rank::value, + typename std::enable_if< + !dash::view_traits::is_origin::value, + char >::type = 0 +> +constexpr auto +expand( + OffsetFirstT begin, + OffsetFinalT end, + DomainT && domain) { + return detail::expand_dim< + static_cast(NDim - 1), + static_cast(SubDim) + >(begin, end, + dash::origin( + std::forward(domain)), + (domain.offsets()), + (domain.extents())); +} + + +template < + dim_t SubDim = 0, + class OffsetT0, + class OffsetT1, + typename std::enable_if< + ( std::is_integral::value && + std::is_integral::value ), + int + >::type = 0 > +static inline auto expand(OffsetT0 a, OffsetT1 b) { + return dash::make_pipeable( + [=](auto && x) { + return expand(a,b, std::forward(x)); + }); +} + +template < + dim_t SubDim = 0, + class OffsetT0, + class OffsetT1, + typename std::enable_if< + ( std::is_integral::value && + std::is_integral::value ), + int + >::type = 0 > +static inline auto stretch(OffsetT0 a, OffsetT1 b) { + return dash::make_pipeable( + [=](auto && x) { + return expand(a,b, std::forward(x)); + }); +} + +template < + dim_t SubDim = 0, + class OffsetT, + typename std::enable_if< + std::is_integral::value, + int + >::type = 0 > +static inline auto shift(OffsetT offs) { + return dash::make_pipeable( + [=](auto && x) { + return expand( + offs,offs, std::forward(x)); + }); +} + +} // namespace dash + +#endif // DASH__VIEW__EXPAND_H__INCLUDED diff --git a/dash/include/dash/view/Global.h b/dash/include/dash/view/Global.h index 2999e07a5..b53a47bbf 100644 --- a/dash/include/dash/view/Global.h +++ b/dash/include/dash/view/Global.h @@ -1,6 +1,7 @@ #ifndef DASH__VIEW__GLOBAL_H__INCLUDED #define DASH__VIEW__GLOBAL_H__INCLUDED +#include #include @@ -34,6 +35,13 @@ global(ContainerType & c) { return c; } +static inline auto global() { + return dash::make_pipeable( + [](auto && x) { + return global(std::forward(x)); + }); +} + } // namespace dash #endif // DASH__VIEW__GLOBAL_H__INCLUDED diff --git a/dash/include/dash/view/IndexRange.h b/dash/include/dash/view/IndexRange.h index 80553103c..365fb8ee6 100644 --- a/dash/include/dash/view/IndexRange.h +++ b/dash/include/dash/view/IndexRange.h @@ -6,38 +6,40 @@ #include +#ifndef DOXYGEN namespace dash { -// N-dimensional index range +/** + * Multidimensional index range. + */ template < dim_t NDim, typename IndexType > -class IndexRange -{ +class IndexRange { typedef IndexRange self_t; // One-dimensional index range in every dimension: std::array< IndexRange<1, IndexType>, NDim > _ranges; -public: + public: template constexpr self_t sub(IndexType first, IndexType last) const { return self_t(*this); // _ranges[SDim].sub(first, last) } }; -// Specialization for one-dimensional index range -template < - typename IndexType > -class IndexRange<1, IndexType> -{ +/** + * Specialization for one-dimensional index range + */ +template +class IndexRange<1, IndexType> { typedef IndexRange<1, IndexType> self_t; IndexType _first; IndexType _last; -public: + public: constexpr IndexRange(IndexType first, IndexType last) : _first(first) , _last(last) @@ -52,4 +54,6 @@ class IndexRange<1, IndexType> } // namespace dash +#endif // DOXYGEN + #endif // DASH__VIEW__INDEX_RANGE_H__INCLUDED diff --git a/dash/include/dash/view/IndexSet.h b/dash/include/dash/view/IndexSet.h index bdb9679dd..edd6d0295 100644 --- a/dash/include/dash/view/IndexSet.h +++ b/dash/include/dash/view/IndexSet.h @@ -1,6 +1,11 @@ #ifndef DASH__VIEW__INDEX_SET_H__INCLUDED #define DASH__VIEW__INDEX_SET_H__INCLUDED +#include +#include +#include + +#include #include #include #include @@ -11,8 +16,6 @@ #include -#include - #include #include #include @@ -21,6 +24,85 @@ #include +/** + * \defgroup DashIndexSetConcept Index Set Concept + * + * \ingroup DashNDimConcepts + * \{ + * \par Description + * + * An \c IndexSet specifies a injective, non-surjective map from a + * random-accessible sequence \f$ I = { i : (0...n) } \f$ to elements in + * another index set \$ F \$ (\em family or \em image set). + * More general, an index set can be considered an enumeration of elements + * in a domain. + * Index sets do not provide the inverse mapping, from integer to element. + * + * In the context of views and ranges, the function \c dash::index returns + * the index set of a view expression. + * Index sets establish a uniform, canonical interface to domains that do + * not exhibit range semantics such as non-contiguous, multi-dimensional + * and unordered element spaces. + * + * \see DashDimensionalConcept + * \see DashRangeConcept + * \see DashIteratorConcept + * \see DashViewConcept + * \see \c dash::view_traits + * + * + * \par Terminology + * + * + * \par Types + * + * \code + * template < + * class IndexSetT, + * class DomainT, + * dim_t NDim = view_traits::rank::value > + * class IndexSetBase; + * \endcode + * + * Generic adapter base class with default implementation for models of the + * \c IndexSet concept. + * + * Type | Synopsis + * ------------------- | -------------------------------------------------- + * IndexSetT | Specific index set, CRTP type + * DomainT | Indexed domain set, model of \c View concept + * NDim | Number of dimensions in the index set + * + * + * \par Expressions + * + * For a index domain \f$ Id \f$, \f$ ia, ib \in Id \f$ mapped by an index + * set \f$ I \f$, the following operations and expressions are defined: + * + * Expression | Returns | Synopsis + * ----------------------- | ----------- | ----------------------------- + * sub(ia,ib, Id) | I | \f$ I := \f$ + * + * + * \par Examples + * + * \code + * // containers are view expressions: + * dash::Array array; + * + * a_idx_global = dash::index(array); + * // (0, 1, ..., n) -> (0, 1, ..., n] + * + * a_idx_sub = dash::sub({4, 14}, array); + * // (0, 1, ..., 9) -> (4, 5, ..., 14] + * + * a_idx_sub_loc = dash::local(a_idx_sub); + * // assuming array elements in global index range (7, 13] are not local: + * // (0, 1, 2, 3, 4) -> (4, 5, 6, 13, 14) + * \endcode + * + * \} + */ #ifndef DOXYGEN namespace dash { @@ -54,7 +136,7 @@ using global_index_t // Forward-declarations -template +template class IndexSetBase; template @@ -66,9 +148,14 @@ class IndexSetLocal; template class IndexSetGlobal; -template +template class IndexSetSub; +template +class IndexSetBlocks; + +template +class IndexSetBlock; // ----------------------------------------------------------------------- @@ -82,9 +169,9 @@ constexpr auto index(DomainType && v) -> typename std::enable_if< dash::view_traits::is_view::value, - decltype(std::forward(v).index_set()) + typename std::decay::type >::type { - return std::forward(v).index_set(); + return std::move(v).index_set(); } template < @@ -99,6 +186,30 @@ index(const DomainType & v) return v.index_set(); } +template < + MemArrange MemOrder = dash::ROW_MAJOR, + class ViewType, + typename CoordT, + dim_t NDim = dash::view_traits< + typename dash::view_traits::origin_type + >::rank::value, + class IndexT = typename dash::view_traits::index_type > +auto linearize( + const ViewType & view, + const std::array< + CoordT, + static_cast(NDim)> & coords) + -> IndexT { + return dash::CartesianIndexSpace< NDim, MemOrder, IndexT >( + view.extents()).at( + // coords: + dash::array_value_cast(coords) + // offsets: + // , + // dash::array_value_cast(view.offsets()) + ); +} + namespace detail { @@ -122,8 +233,8 @@ class IndexSetIterator BaseStride >, index_type, int, std::nullptr_t, index_type > base_t; private: - const IndexSetType * const _index_set; - index_type _stride = BaseStride; + const IndexSetType * _index_set; + index_type _stride = BaseStride; public: constexpr IndexSetIterator() = delete; constexpr IndexSetIterator(self_t &&) = default; @@ -164,12 +275,26 @@ template < class ContainerType, class ContainerDecayType = typename std::decay::type > constexpr auto -index(const ContainerType & c) +index(ContainerType && c) -> typename std::enable_if < + dash::view_traits::is_origin::value || !dash::view_traits::is_view::value, - const IndexSetIdentity + IndexSetIdentity >::type { - return IndexSetIdentity(c); + return IndexSetIdentity( + std::forward(c)); +} + +template < + class ContainerType > +constexpr auto +index(const ContainerType & c) +-> typename std::enable_if < + dash::view_traits::is_origin::value || + !dash::view_traits::is_view::value, + IndexSetIdentity + >::type { + return IndexSetIdentity(c); } // ----------------------------------------------------------------------- @@ -191,26 +316,22 @@ index(const ContainerType & c) template < class IndexSetType, class DomainType, - std::size_t NDim > + dim_t NDim > constexpr auto local( const IndexSetBase & index_set) -> decltype(index_set.local()) { -// -> typename view_traits>::global_type & { -// -> const IndexSetLocal & { return index_set.local(); } template < class IndexSetType, class DomainType, - std::size_t NDim > + dim_t NDim > constexpr auto global( const IndexSetBase & index_set) - -> decltype(index_set.global()) { -// -> typename view_traits>::global_type & { -// -> const IndexSetGlobal & { + -> decltype(index_set.global()) { return index_set.global(); } @@ -220,21 +341,26 @@ namespace detail { template struct index_set_domain_bind_t { typedef typename - std::conditional< dash::is_view::value, - DomainT, - const DomainT & >::type - type; + std::conditional< + dash::view_traits< + typename std::decay::type + >::is_origin::value && + !std::is_copy_constructible::value, + const DomainT &, + DomainT + >::type + type; }; } // namespace detail /** - * \concept{DashRangeConcept} + * \concept{DashIndexSetConcept} */ template < class IndexSetType, class DomainType, - std::size_t NDim = DomainType::rank::value > + dim_t NDim = DomainType::rank::value > class IndexSetBase { typedef IndexSetBase self_t; @@ -246,15 +372,13 @@ class IndexSetBase view_origin_type; typedef DomainValueT view_domain_type; - typedef typename DomainValueT::local_type + typedef typename dash::view_traits::local_type view_local_type; typedef typename dash::view_traits::global_type view_global_type; typedef typename view_traits::index_set_type domain_type; - typedef typename view_traits::pattern_type - pattern_type; typedef typename dash::view_traits::index_set_type local_type; typedef typename dash::view_traits::index_set_type @@ -271,17 +395,20 @@ class IndexSetBase typedef index_type value_type; - typedef typename detail::index_set_domain_bind_t::type + typedef typename detail::index_set_domain_bind_t::type domain_member_type; - typedef std::integral_constant + typedef std::integral_constant rank; - static constexpr std::size_t ndim() { return NDim; } + typedef typename view_origin_type::pattern_type + pattern_type; + + static constexpr dim_t ndim() { return NDim; } protected: - domain_member_type _domain; - const pattern_type * _pattern; + domain_member_type _domain; + const pattern_type * _pattern = nullptr; constexpr const IndexSetType & derived() const { return static_cast(*this); @@ -289,12 +416,12 @@ class IndexSetBase constexpr explicit IndexSetBase(const DomainType & domain) : _domain(domain) - , _pattern(&dash::origin(domain).pattern()) + , _pattern(&dash::origin(_domain).pattern()) { } constexpr explicit IndexSetBase(DomainType && domain) - : _domain(std::forward(domain)) - , _pattern(&dash::origin(view_domain()).pattern()) + : _domain(std::move(domain)) + , _pattern(&dash::origin(_domain).pattern()) { } typedef struct { @@ -310,6 +437,7 @@ class IndexSetBase std::min(a.end, b.end) }; } + static constexpr index_type index_range_size( const index_range_t & irng) noexcept { return irng.end - irng.begin; @@ -320,8 +448,8 @@ class IndexSetBase const PatternT_ & pat, const index_range_t & grng) noexcept { return index_range_t { - pat.local_coords({{ grng.begin }})[0], - pat.local_coords({{ grng.end }})[0] + pat.local_coords({{ static_cast(grng.begin) }})[0], + pat.local_coords({{ static_cast(grng.end) }})[0] }; } @@ -342,6 +470,10 @@ class IndexSetBase constexpr IndexSetBase(const self_t &) = default; self_t & operator=(self_t &&) = default; self_t & operator=(const self_t &) = default; + + constexpr const pattern_type & pattern() const { + return *_pattern; + } constexpr const DomainType & view_domain() const & { return _domain; @@ -352,15 +484,13 @@ class IndexSetBase } constexpr auto domain() const -// -> decltype(dash::index( -// std::declval() -// )) { - -> typename view_traits::index_set_type { - return dash::index(this->view_domain()); - } - - constexpr const pattern_type & pattern() const { - return *_pattern; +#if DASH_CXX_VERSION < 14 + -> decltype(dash::index( + std::declval() )) +// -> typename view_traits::index_set_type { +#endif + { + return dash::index(_domain); } constexpr const local_type local() const { @@ -375,9 +505,20 @@ class IndexSetBase return dash::view_traits::is_local::value; } + constexpr bool is_sub() const noexcept { + // TODO: must not be defined depending on size as size() might + // use is_sub() itself + return ( + this->is_local() + ? derived().size() < this->pattern().local_size() + : derived().size() < this->pattern().size() + ) || dash::domain(derived()).is_sub(); + } + constexpr bool is_strided() const noexcept { return ( - ( this->pattern().blockspec().size() > this->pattern().team().size() ) + ( this->pattern().blockspec().size() > + this->pattern().team().size() ) || ( this->pattern().ndim() > 1 && this->domain().extent(1) < ( this->domain().is_local() @@ -386,39 +527,60 @@ class IndexSetBase ); } - // ---- extents --------------------------------------------------------- + constexpr bool is_shifted() const noexcept { + typedef typename dash::pattern_mapping_traits::type + pat_mapping_traits; + return pat_mapping_traits::shifted || + pat_mapping_traits::diagonal; + } + + // ---- extents -------------------------------------------------------- constexpr std::array extents() const { return pattern().extents(); } - template + template constexpr size_type extent() const { return derived().extents()[ShapeDim]; } - constexpr size_type extent(std::size_t shape_dim) const { + constexpr size_type extent(dim_t shape_dim) const { return derived().extents()[shape_dim]; } - // ---- offsets --------------------------------------------------------- + // ---- offsets -------------------------------------------------------- constexpr std::array offsets() const { return std::array { }; } - template + template constexpr index_type offset() const { return derived().offsets()[ShapeDim]; } - constexpr index_type offset(std::size_t shape_dim) const { + constexpr index_type offset(dim_t shape_dim) const { return derived().offsets()[shape_dim]; } - // ---- access ---------------------------------------------------------- + // ---- size ----------------------------------------------------------- + + constexpr bool empty() const noexcept { + return derived().size() == 0; + } + + constexpr bool operator!() const noexcept { + return derived().empty(); + } + + constexpr explicit operator bool() const noexcept { + return !derived().empty(); + } + + // ---- access --------------------------------------------------------- constexpr index_type rel(index_type image_index) const { return image_index; @@ -467,6 +629,7 @@ class IndexSetBase } }; + // ----------------------------------------------------------------------- // IndexSetIdentity // ----------------------------------------------------------------------- @@ -518,7 +681,7 @@ global(const IndexSetIdentity & index_set) } /** - * \concept{DashRangeConcept} + * \concept{DashIndexSetConcept} */ template class IndexSetIdentity @@ -539,12 +702,14 @@ class IndexSetIdentity self_t & operator=(const self_t &) = default; public: typedef typename DomainType::index_type index_type; + public: constexpr explicit IndexSetIdentity(const DomainType & view) : base_t(view) { } + constexpr explicit IndexSetIdentity(DomainType && view) - : base_t(std::forward(view)) + : base_t(std::move(view)) { } constexpr index_type rel(index_type image_index) const { @@ -584,7 +749,7 @@ class IndexSetIdentity template < class DomainType, - std::size_t SubDim > + dim_t SubDim > constexpr auto local(const IndexSetSub & index_set) -> decltype(index_set.local()) { @@ -593,7 +758,7 @@ local(const IndexSetSub & index_set) template < class DomainType, - std::size_t SubDim > + dim_t SubDim > constexpr auto global(const IndexSetSub & index_set) -> decltype(index_set.global()) { @@ -601,11 +766,11 @@ global(const IndexSetSub & index_set) } /** - * \concept{DashRangeConcept} + * \concept{DashIndexSetConcept} */ template < class DomainType, - std::size_t SubDim = 0 > + dim_t SubDim = 0 > class IndexSetSub : public IndexSetBase< IndexSetSub, @@ -618,7 +783,6 @@ class IndexSetSub typedef typename base_t::size_type size_type; typedef typename base_t::view_origin_type view_origin_type; typedef typename base_t::view_domain_type view_domain_type; - typedef typename base_t::pattern_type pattern_type; typedef typename base_t::local_type local_type; typedef typename base_t::global_type global_type; typedef typename base_t::iterator iterator; @@ -635,7 +799,7 @@ class IndexSetSub index_type _domain_begin_idx; index_type _domain_end_idx; - static constexpr std::size_t NDim = base_t::ndim(); + static constexpr dim_t NDim = base_t::ndim(); public: /** * Constructor, creates index set for given view. @@ -656,14 +820,21 @@ class IndexSetSub DomainType && view, index_type begin_idx, index_type end_idx) - : base_t(std::forward(view)) + : base_t(std::move(view)) , _domain_begin_idx(begin_idx) , _domain_end_idx(end_idx) { } +#if 0 + constexpr bool is_sub() const noexcept { + return true; // not necessarily true, sub<0, extent> should return + // false despite of index set type + } +#endif + // ---- extents --------------------------------------------------------- - template + template constexpr size_type extent() const { return ( ExtDim == SubDim ? _domain_end_idx - _domain_begin_idx @@ -671,7 +842,7 @@ class IndexSetSub ); } - constexpr size_type extent(std::size_t shape_dim) const { + constexpr size_type extent(dim_t shape_dim) const { return ( shape_dim == SubDim ? _domain_end_idx - _domain_begin_idx : this->domain().extent(shape_dim) @@ -686,7 +857,7 @@ class IndexSetSub // ---- offsets --------------------------------------------------------- - template + template constexpr index_type offset() const { return ( ExtDim == SubDim ? _domain_begin_idx @@ -694,7 +865,7 @@ class IndexSetSub ); } - constexpr index_type offset(std::size_t shape_dim) const { + constexpr index_type offset(dim_t shape_dim) const { return ( shape_dim == SubDim ? _domain_begin_idx : this->domain().offset(shape_dim) @@ -709,7 +880,7 @@ class IndexSetSub // ---- size ------------------------------------------------------------ - constexpr size_type size(std::size_t sub_dim = 0) const { + constexpr size_type size(dim_t sub_dim = 0) const { return extent(sub_dim) * (sub_dim + 1 < NDim && NDim > 0 ? size(sub_dim + 1) @@ -794,16 +965,22 @@ global(IndexSetLocal && index_set) -> } /** - * \concept{DashRangeConcept} + * \concept{DashIndexSetConcept} */ template class IndexSetLocal : public IndexSetBase< IndexSetLocal, - DomainType > + DomainType + > { - typedef IndexSetLocal self_t; - typedef IndexSetBase base_t; + typedef IndexSetLocal + self_t; + typedef IndexSetBase< + self_t, + DomainType + > + base_t; constexpr static bool view_domain_is_local = dash::view_traits::is_local::value; @@ -813,11 +990,6 @@ class IndexSetLocal typedef self_t local_type; typedef IndexSetGlobal global_type; -//typedef decltype( -// dash::global( -// dash::index( -// std::declval()) -// )) global_type; typedef global_type preimage_type; typedef typename base_t::iterator iterator; @@ -849,10 +1021,25 @@ class IndexSetLocal * Constructor, creates index set for given view. */ constexpr explicit IndexSetLocal(DomainType && view) - : base_t(std::forward(view)) + : base_t(std::move(view)) , _size(calc_size()) { } + constexpr bool is_local() const noexcept { + return true; + } + + constexpr bool is_strided() const noexcept { + return ( + // Local sub range of one-dimensional range is contiguous: + this->ndim() == 1 + ? base_t::is_strided() + : // Elements are contiguous within single block, block view + // is not strided: + this->domain().is_strided() + ); + } + constexpr const local_type & local() const noexcept { return *this; } @@ -883,18 +1070,36 @@ class IndexSetLocal return this->pattern().local_extents(); } - template + template constexpr index_type extent() const noexcept { return this->pattern().local_extents()[ShapeDim]; } - constexpr index_type extent(std::size_t shape_dim) const noexcept { + constexpr index_type extent(dim_t shape_dim) const noexcept { return this->pattern().local_extents()[shape_dim]; } + // ---- offsets --------------------------------------------------------- + +#if TODO + constexpr std::array + offsets() const { + return std::array { }; + } + + template + constexpr index_type offset() const { + return derived().offsets()[ShapeDim]; + } + + constexpr index_type offset(dim_t shape_dim) const { + return derived().offsets()[shape_dim]; + } +#endif + // ---- size ------------------------------------------------------------ - constexpr size_type size(std::size_t sub_dim) const noexcept { + constexpr size_type size(dim_t sub_dim) const noexcept { return _size; } @@ -908,6 +1113,8 @@ class IndexSetLocal constexpr index_type calc_size() const noexcept { typedef typename dash::pattern_partitioning_traits::type pat_partitioning_traits; + typedef typename dash::pattern_mapping_traits::type + pat_mapping_traits; static_assert( pat_partitioning_traits::rectangular, @@ -923,74 +1130,102 @@ class IndexSetLocal ); */ return ( - !this->is_strided() - // blocked (not blockcyclic) distribution: single local - // element space with contiguous global index range - ? this->index_range_size( - this->index_range_intersect( - // local range in global index space: - { this->pattern().lbegin(), - this->pattern().lend() - 1 }, - // domain range in global index space; - { this->domain().first(), - this->domain().last() } - )) + 1 - // blockcyclic distribution: local element space chunked - // in global index range - : this->index_range_size( - this->index_range_g2l( - this->pattern(), - // intersection of local range and domain range: - this->index_range_intersect( - // local range in global index space: - { - this->pattern().lbegin(), - ( this->pattern().lend() < this->domain().last() - // domain range contains end of local range: - ? this->pattern().lend() - 1 - // domain range ends in local range, determine last - // local index contained in domain from last local - // block contained in domain range: - // - // gbi: 0 1 2 3 4 5 - // lbi: 0 0 1 1 2 2 - // : : - // [ | |xxxx| |xxxx| | |xxxx] - // '---------------------' - // - // --> domain.end.gbi = 4 ------------. - // domain.end.lbi = 2 -. | - // | | - // v | - // local.lblock(lbi = 2).gbi = 5 | - // | | - // ! 5 > domain.end.gbi = 4 <-----'-' - // --> local.lblock(lbi = 1) - // - // Resolve global index past the last element: - // - : ( domain_block_gidx_last() >= local_block_gidx_last() - // Last local block is included in domain: - ? this->pattern().block( - local_block_gidx_last() - ).range(0).end - 1 - // Domain ends before last local block: - : local_block_gidx_at_block_lidx( - domain_block_lidx_last()) - > domain_block_gidx_last() - ? this->pattern().local_block( - domain_block_lidx_last() - 1 - ).range(0).end - 1 - : this->pattern().local_block( - domain_block_lidx_last() - ).range(0).end - 1 ) - ) - }, - // domain range in global index space; - { this->domain().first(), - this->domain().last() - }) - )) + 1 + !this->domain().is_sub() + // parent domain is not a sub-range, use full local size: + ? this->pattern().local_size() + // parent domain is sub-space, calculate size from sub-range: + : ( !this->is_strided() + // blocked (not blockcyclic) distribution: single local + // element space with contiguous global index range + ? ( this->ndim() == 1 + // one-dimensional, simple intersect: + ? this->index_range_size( + this->index_range_intersect( + // local range in global index space: + { this->pattern().lbegin(), + this->pattern().lend() - 1 }, + // domain range in global index space; + { this->domain().first(), + this->domain().last() } + )) + 1 + // multi-dimensional, size calculation requires view spec: + : ( this->pattern().block_at( + this->pattern().coords(this->domain().first())) == + this->pattern().block_at( + this->pattern().coords(this->domain().last())) + // First and last element are in same block so entire + // range is within single block: + ? ( this->pattern().unit_at(this->domain().first()) == + this->pattern().team().myid() + ? this->domain().size() + : 0 ) + // Range spans multiple blocks: + : 123 ) + ) + // strided, e.g. blockcyclic distribution: local element space + // chunked in global index range + : ( this->ndim() == 1 + ? this->index_range_size( + this->index_range_g2l( + this->pattern(), + // intersection of local range and domain range: + this->index_range_intersect( + // local range in global index space: + { + this->pattern().lbegin(), + ( this->pattern().lend() < this->domain().last() + // domain range contains end of local range: + ? this->pattern().lend() - 1 + // domain range ends in local range, determine last + // local index contained in domain from last local + // block contained in domain range: + // + // gbi: 0 1 2 3 4 5 + // lbi: 0 0 1 1 2 2 + // : : + // [ | |xxxx| |xxxx| | |xxxx] + // '---------------------' + // + // --> domain.end.gbi = 4 ------------. + // domain.end.lbi = 2 -. | + // | | + // v | + // local.lblock(lbi = 2).gbi = 5 | + // | | + // ! 5 > domain.end.gbi = 4 <-----'-' + // --> local.lblock(lbi = 1) + // + // Resolve global index past the last element: + // + : ( domain_block_gidx_last() + >= local_block_gidx_last() + // Last local block is included in domain: + ? this->pattern().block( + local_block_gidx_last() + ).range(0).end - 1 + // Domain ends before last local block: + : local_block_gidx_at_block_lidx( + domain_block_lidx_last()) + > domain_block_gidx_last() + ? this->pattern().local_block( + domain_block_lidx_last() - 1 + ).range(0).end - 1 + : this->pattern().local_block( + domain_block_lidx_last() + ).range(0).end - 1 ) + ) + }, + // domain range in global index space; + { this->domain().first(), + this->domain().last() + }) + )) + 1 + // ndim != 1, multi-dimensional + : ( + 100 + ) + ) + ) // domain.is_sub() ); } @@ -1009,7 +1244,8 @@ class IndexSetLocal this->pattern().coords( this->pattern().lend() - 1)); } - constexpr index_type local_block_gidx_at_block_lidx(index_type lbi) const { + constexpr index_type local_block_gidx_at_block_lidx( + index_type lbi) const { return this->pattern().block_at( this->pattern().coords( this->pattern().local_block(lbi).offset(0))); @@ -1068,7 +1304,7 @@ constexpr auto local(IndexSetGlobal && index_set) -> decltype(index_set.local()) { // Note: Not a universal reference, index_set has partially defined type - return index_set.local(); + return std::move(index_set).local(); } template @@ -1078,16 +1314,22 @@ global(const IndexSetGlobal & index_set) { } /** - * \concept{DashRangeConcept} + * \concept{DashIndexSetConcept} */ template class IndexSetGlobal : public IndexSetBase< IndexSetGlobal, - DomainType > + DomainType + > { - typedef IndexSetGlobal self_t; - typedef IndexSetBase base_t; + typedef IndexSetGlobal + self_t; + typedef IndexSetBase< + self_t, + DomainType + > + base_t; constexpr static bool view_domain_is_local = dash::view_traits::is_local::value; @@ -1127,7 +1369,7 @@ class IndexSetGlobal * Constructor, creates index set for given view. */ constexpr explicit IndexSetGlobal(DomainType && view) - : base_t(std::forward(view)) + : base_t(std::move(view)) { } constexpr auto local() const noexcept @@ -1179,25 +1421,41 @@ class IndexSetBlocks : public IndexSetBase< IndexSetBlocks, DomainType, - // Number of dimensions in the domain pattern's block spec: dash::pattern_traits< - typename dash::view_traits< - typename std::decay::type - >::pattern_type + typename view_traits::origin_type::pattern_type >::blockspec_type::ndim::value > { - typedef IndexSetBlocks self_t; - typedef IndexSetBase base_t; + typedef + typename dash::pattern_traits< + typename view_traits::origin_type::pattern_type + >::blockspec_type::ndim + blocks_ndim; + + typedef IndexSetBlocks + self_t; + typedef IndexSetBase< + self_t, + DomainType, + blocks_ndim::value + > + base_t; public: - typedef typename DomainType::index_type index_type; + typedef typename base_t::index_type index_type; + typedef typename base_t::size_type size_type; + + typedef typename base_t::view_origin_type view_origin_type; + typedef typename base_t::view_domain_type view_domain_type; + + typedef typename view_traits::origin_type::pattern_type + pattern_type; typedef self_t local_type; typedef IndexSetGlobal global_type; - typedef global_type preimage_type; typedef typename base_t::iterator iterator; - typedef typename base_t::pattern_type pattern_type; + + typedef global_type preimage_type; typedef dash::local_index_t local_index_type; typedef dash::global_index_t global_index_type; @@ -1207,8 +1465,9 @@ class IndexSetBlocks // Rank of blocks index set should depend on blockspec dimensions of // the domain's pattern type. - static constexpr std::size_t NBlocksDim = base_t::rank::value; + static constexpr dim_t NBlocksDim = blocks_ndim::value; + public: constexpr static bool view_domain_is_local = dash::view_traits::is_local::value; public: @@ -1232,10 +1491,28 @@ class IndexSetBlocks * Constructor, creates index set for given view. */ constexpr explicit IndexSetBlocks(DomainType && view) - : base_t(std::forward(view)) + : base_t(std::move(view)) , _size(calc_size()) { } + // ---- extents --------------------------------------------------------- + + constexpr std::array + extents() const { + return ( this->is_local() + ? this->pattern().local_blockspec().extents() + : this->pattern().blockspec().extents() ); + } + + // ---- offsets --------------------------------------------------------- + + constexpr std::array + offsets() const { + return std::array { }; + } + + // ---- access ---------------------------------------------------------- + constexpr iterator begin() const { return iterator(*this, 0); } @@ -1321,39 +1598,57 @@ class IndexSetBlocks } }; // class IndexSetBlocks + // ----------------------------------------------------------------------- // IndexSetBlock // ----------------------------------------------------------------------- -#if 0 -// Currently using IndexSetSub instead -// + template class IndexSetBlock : public IndexSetBase< IndexSetBlock, DomainType, - 1 > + dash::pattern_traits< + typename view_traits::origin_type::pattern_type + >::ndim::value + > { - typedef IndexSetBlock self_t; - typedef IndexSetBase base_t; + typedef + typename dash::pattern_traits< + typename view_traits::origin_type::pattern_type + >::ndim + pattern_ndim; + + typedef IndexSetBlock + self_t; + typedef IndexSetBase< + self_t, + DomainType, + dash::pattern_traits< + typename view_traits::origin_type::pattern_type + >::ndim::value + > + base_t; public: typedef typename DomainType::index_type index_type; - - typedef self_t local_type; + typedef typename DomainType::size_type size_type; + + typedef self_t local_type; typedef IndexSetGlobal global_type; - typedef global_type preimage_type; + typedef global_type preimage_type; + + typedef typename base_t::iterator iterator; + typedef typename base_t::pattern_type pattern_type; + + typedef dash::local_index_t local_index_type; + typedef dash::global_index_t global_index_type; - typedef typename base_t::iterator iterator; - typedef typename base_t::pattern_type pattern_type; - - typedef dash::local_index_t local_index_type; - typedef dash::global_index_t global_index_type; - private: index_type _block_idx; index_type _size; - constexpr static dim_t NDim = 1; + constexpr static dim_t NDomainDim = pattern_ndim::value; + constexpr static dim_t NBlockDim = pattern_ndim::value; constexpr static bool view_domain_is_local = dash::view_traits::is_local::value; public: @@ -1367,12 +1662,59 @@ class IndexSetBlock public: constexpr explicit IndexSetBlock( const DomainType & view, - index_type block_idx) + index_type block_idx) : base_t(view) , _block_idx(block_idx) , _size(calc_size()) { } + constexpr explicit IndexSetBlock( + DomainType && view, + index_type block_idx) + : base_t(std::move(view)) + , _block_idx(block_idx) + , _size(calc_size()) + { } + + constexpr bool is_local() const noexcept { + return // Domain is local, block must be local: + dash::view_traits::is_local::value || + // First element is local, so block is local: + ( this->pattern().unit_at(this->first()) == + this->pattern().team().myid() ); + } + + constexpr bool is_strided() const noexcept { + return ( + // Elements are contiguous within single block, block view + // is not strided: + !dash::pattern_layout_traits::type::blocked || + // Block elements are contiguous but missing columns/rows for + // row-major/column-major storage order: + ( pattern_type::memory_order() == dash::ROW_MAJOR + ? this->extent(1) < this->pattern().blocksize(1) && + this->extent(0) > 1 + : this->extent(0) < this->pattern().blocksize(0) && + this->extent(1) > 1 ) + ); + } + + // ---- extents --------------------------------------------------------- + + constexpr std::array + extents() const { + return calc_viewspec().extents(); + } + + // ---- offsets --------------------------------------------------------- + + constexpr std::array + offsets() const { + return calc_viewspec().offsets(); + } + + // ---- access ---------------------------------------------------------- + constexpr iterator begin() const { return iterator(*this, 0); } @@ -1382,31 +1724,65 @@ class IndexSetBlock } constexpr index_type rel(index_type block_phase) const { - return block_phase + - ( view_domain_is_local - ? ( // index of block at last index in domain - this->pattern().local_block_at( - this->pattern().coords( - // local offset to global offset: - this->pattern().global( - *(this->domain().begin()) - ) - ) - ).index ) - : ( // index of block at first index in domain - this->pattern().block_at( - {{ *(this->domain().begin()) }} - ) ) + return ( view_domain_is_local + ? ( // translate block phase to local index: + dash::CartesianIndexSpace( + this->pattern().local_extents() + ).at( + // phase to in-block coords + dash::CartesianIndexSpace( + this->extents() + ).coords( + block_phase >= this->pattern() + .local_block(_block_idx).size() + ? block_phase - 1 + : block_phase ), + // block viewspec + this->pattern().local_block_local(_block_idx).intersect( + // domain viewspec + ViewSpec( + this->view_domain().offsets(), + this->view_domain().extents())) + ) + ( + block_phase >= this->pattern() + .local_block(_block_idx).size() + ? 1 + : 0) + ) + : ( // translate block phase to global index: + dash::CartesianIndexSpace( + this->pattern().extents() + ).at( + // phase to in-block coords + dash::CartesianIndexSpace( + this->extents() + ).coords( + block_phase >= this->pattern().block(_block_idx).size() + ? block_phase - 1 + : block_phase ), + // block viewspec + this->pattern().block(_block_idx).intersect( + // domain viewspec + ViewSpec( + this->view_domain().offsets(), + this->view_domain().extents())) + ) + ( + block_phase >= this->pattern().block(_block_idx).size() + ? 1 + : 0) + ) ); } - constexpr index_type operator[](index_type block_phase) const noexcept { + constexpr index_type operator[](index_type block_phase) + const noexcept { return rel(block_phase); } template constexpr index_type operator[]( - const std::array & block_phase_coords) const noexcept { + const std::array & block_phase_coords) + const noexcept { return -1; } @@ -1416,31 +1792,37 @@ class IndexSetBlock private: constexpr index_type calc_size() const { + return calc_viewspec().size(); + } + + ViewSpec calc_viewspec() const { return ( view_domain_is_local - ? ( // index of block at last index in domain - this->pattern().local_block_at( - {{ *( this->domain().begin() - + (this->domain().size() - 1) ) }} - ).index - - // index of block at first index in domain - this->pattern().local_block_at( - {{ *( this->domain().begin() ) }} - ).index + 1 ) - : ( // index of block at last index in domain - this->pattern().block_at( - {{ *( this->domain().begin() - + (this->domain().size() - 1) ) }} - ) - - // index of block at first index in domain - this->pattern().block_at( - {{ *(this->domain().begin()) }} - ) + 1 ) + ? // local viewspec of local block referenced by this view: + this->pattern().local_block_local(_block_idx).intersect( + // viewspec of domain: + ViewSpec( + this->view_domain().offsets(), + this->view_domain().extents()) ) + : // viewspec of block referenced by this view: + this->pattern().block(_block_idx).intersect( + // viewspec of domain: + ViewSpec( + this->view_domain().offsets(), + this->view_domain().extents()) ) ); } + }; // class IndexSetBlock -#endif + +static inline auto index() { + return dash::make_pipeable( + [](auto && x) { + return index(std::forward(x)); + }); +} } // namespace dash + #endif // DOXYGEN #endif // DASH__VIEW__INDEX_SET_H__INCLUDED diff --git a/dash/include/dash/view/Intersect.h b/dash/include/dash/view/Intersect.h new file mode 100644 index 000000000..bd8c43069 --- /dev/null +++ b/dash/include/dash/view/Intersect.h @@ -0,0 +1,127 @@ +#ifndef DASH__VIEW__INTERSECT_H__INCLUDED +#define DASH__VIEW__INTERSECT_H__INCLUDED + +#include +#include + +#include +#include + + +namespace dash { + +/** + * \concept{DashViewConcept} + */ +template < + class ViewTypeA, + class ViewTypeB, + typename std::enable_if< + dash::rank::value == 1 && + dash::rank::value == 1, + int >::type = 0 +> +constexpr auto +intersect( + const ViewTypeA & va, + const ViewTypeB & vb) + -> decltype(dash::sub(0, 0, va)) +{ + return dash::sub( + dash::index(va).pre()[ + std::max( + *dash::begin(dash::index(va)), + *dash::begin(dash::index(vb)) + ) + ], + dash::index(va).pre()[ + std::min( + *dash::end(dash::index(va)), + *dash::end(dash::index(vb)) + ) + ], + va + ); +} + +namespace detail { + +template < + dim_t CurDim, + class ViewTypeA, + class ViewTypeB, + typename std::enable_if< (CurDim < 0), int >::type = 0 +> +constexpr auto +intersect_dim( + ViewTypeA && va, + ViewTypeB && vb) { + return std::forward(va); +} + +template < + dim_t CurDim, + class ViewTypeA, + class ViewTypeB, + dim_t NDimA = dash::rank::value, + dim_t NDimB = dash::rank::value, + typename std::enable_if< + (NDimA == NDimB) && (NDimA > 1) && (NDimB > 1) && + (CurDim >= 0), + int >::type = 0 +> +constexpr auto +intersect_dim( + const ViewTypeA & va, + ViewTypeB && vb) { + return intersect_dim( + dash::expand( + std::max( + 0, std::forward(vb).offsets()[CurDim] - + (va).offsets()[CurDim] + ), + std::min( + 0, ( std::forward(vb).offsets()[CurDim] + + std::forward(vb).extents()[CurDim] ) - + ( (va).offsets()[CurDim] + + (va).extents()[CurDim] ) + ), + (va) + ), + std::forward(vb)); +} + +} // namespace detail + +template < + class ViewTypeA, + class ViewTypeB, + dim_t NDimA = dash::rank::value, + dim_t NDimB = dash::rank::value, + typename std::enable_if< + (NDimA == NDimB) && (NDimA > 1) && (NDimB > 1), + int >::type = 0 +> +constexpr auto +intersect( + const ViewTypeA & va, + ViewTypeB && vb) { + return detail::intersect_dim( + va, + std::forward(vb)); +} + +template < + class ViewType > +static inline auto intersect(const ViewType & v_rhs) { + return dash::make_pipeable( + [=](auto && v_lhs) { + return intersect( + std::forward(v_lhs), + v_rhs); + }); +} + +} // namespace dash + +#endif // DASH__VIEW__INTERSECT_H__INCLUDED diff --git a/dash/include/dash/view/Local.h b/dash/include/dash/view/Local.h index 1a351dd04..043e3f821 100644 --- a/dash/include/dash/view/Local.h +++ b/dash/include/dash/view/Local.h @@ -2,8 +2,8 @@ #define DASH__VIEW__LOCAL_H__INCLUDED #include -#include +#include #include @@ -35,21 +35,20 @@ local(ViewType & v) return v; } -#if 0 template < - class ContainerLocalType, - typename ContainerLocalDecayType - = typename std::decay::type > + class ContainerType, + typename ContainerDecayType + = typename std::decay::type > constexpr typename std::enable_if< - ( dash::view_traits::is_origin::value && - dash::view_traits::is_local::value ), - ContainerLocalType & + ( !dash::view_traits::is_local::value && + !std::is_member_function_pointer< + decltype(&ContainerDecayType::local)>::value ), + const typename ContainerType::local_type & >::type -local(ContainerLocalType & cl) { - return cl; +local(const ContainerType & c) { + return c.local; } -#endif template < class ContainerType, @@ -57,15 +56,47 @@ template < = typename std::decay::type > constexpr typename std::enable_if< - ( !dash::view_traits::is_view::value && - !dash::view_traits::is_local::value && - dash::view_traits::is_origin::value ), - const typename ContainerType::local_type & + ( !dash::view_traits::is_local::value && + !std::is_member_function_pointer< + decltype(&ContainerDecayType::local)>::value ), + typename ContainerType::local_type & >::type -local(const ContainerType & c) { +local(ContainerType & c) { return c.local; } +template < + class ContainerType, + typename ContainerDecayType + = typename std::decay::type > +constexpr +typename std::enable_if< + ( !dash::view_traits::is_local::value && + !dash::view_traits::is_view::value && + std::is_member_function_pointer< + decltype(&ContainerDecayType::local)>::value ), + decltype(std::declval().local()) +>::type +local(const ContainerType & c) { + return c.local(); +} + +template < + class ContainerType, + typename ContainerDecayType + = typename std::decay::type > +constexpr +typename std::enable_if< + ( !dash::view_traits::is_local::value && + !dash::view_traits::is_view::value && + std::is_member_function_pointer< + decltype(&ContainerDecayType::local)>::value ), + decltype(std::declval().local()) +>::type +local(ContainerType & c) { + return c.local(); +} + #if 0 /** * \concept{DashViewConcept} @@ -82,20 +113,24 @@ local(const ViewType & v) return IndexSetIdentity( v.local()); } -#endif /** * \concept{DashViewConcept} */ -template +template < + class ViewType, + typename ViewValueT = typename std::decay::type > constexpr auto local(const ViewType & v) -> typename std::enable_if< - dash::view_traits::is_view::value, + ( dash::view_traits::is_view::value && + !dash::view_traits::is_origin::value && + !dash::view_traits::is_local::value ), decltype(v.local()) >::type { return v.local(); } +#endif template < class ViewType, @@ -104,10 +139,11 @@ constexpr auto local(ViewType && v) -> typename std::enable_if< ( dash::view_traits::is_view::value && + !dash::view_traits::is_origin::value && !dash::view_traits::is_local::value ), decltype(std::forward(v).local()) >::type { - return std::forward(v).local(); + return std::forward(v).local(); } #if 0 @@ -147,6 +183,13 @@ constexpr auto local( return g_it.local(); } +static inline auto local() { + return dash::make_pipeable( + [](auto && x) { + return local(std::forward(x)); + }); +} + // ========================================================================= // Multidimensional Views // ========================================================================= diff --git a/dash/include/dash/view/Origin.h b/dash/include/dash/view/Origin.h index 9b69a2835..dea4e4e25 100644 --- a/dash/include/dash/view/Origin.h +++ b/dash/include/dash/view/Origin.h @@ -24,72 +24,134 @@ origin(ViewT & view); #else +#if 0 template typename std::enable_if< - dash::view_traits::is_origin::value, - ContainerT & + view_traits::type>::is_origin::value || + !view_traits::type>::is_view::value, + ContainerT >::type -origin(ContainerT & container) { +origin(ContainerT && container) { + return std::forward(container); +} +#else +template < + class ContainerT, + typename ContainerValueT = typename std::decay::type > +typename std::enable_if< + view_traits::is_origin::value || + !view_traits::is_view::value, + const ContainerT & +>::type +origin(const ContainerT & container) { return container; } +#endif -template +template < + class ViewT, + typename ViewValueT = typename std::decay::type > constexpr auto origin(const ViewT & view) -> typename std::enable_if< - ( dash::view_traits::is_view::value && - !dash::view_traits::is_local::value ), - const typename dash::view_traits::origin_type & + ( dash::view_traits::is_view::value && + !dash::view_traits::is_origin::value && + !dash::view_traits::is_local::value ), + const typename dash::view_traits::origin_type & +// decltype(dash::origin(view.domain())) >::type { // Recurse to origin of global view: return dash::origin(view.domain()); } +template < + class ViewT, + typename ViewValueT = typename std::decay::type > +constexpr auto +origin(ViewT && view) + -> typename std::enable_if< + ( dash::view_traits::is_view::value && + std::is_copy_constructible< + typename dash::view_traits::origin_type + >::value && + !dash::view_traits::is_origin::value && + !dash::view_traits::is_local::value ), + typename dash::view_traits::origin_type +// decltype(dash::origin(std::forward(view).domain())) + >::type { + // Recurse to origin of global view: + return dash::origin(std::forward(view).domain()); +} -template -typename std::enable_if< - dash::view_traits::is_origin::value, - ContainerT & ->::type -global_origin(ContainerT & container) { +template < + class ContainerT, + typename ContainerValueT = typename std::decay::type > +constexpr auto +global_origin(const ContainerT & container) + -> typename std::enable_if< + dash::view_traits::is_origin::value, + const ContainerT & + >::type { return container; } -template +template < + class ContainerT, + typename ContainerValueT = typename std::decay::type > +constexpr auto +global_origin(ContainerT && container) + -> typename std::enable_if< + dash::view_traits::is_origin::value, + decltype(std::forward(container)) + >::type { + return std::forward(container); +} + +template < + class ViewT, + typename ViewValueT = typename std::decay::type > constexpr auto global_origin(const ViewT & view) -> typename std::enable_if< - !dash::view_traits::is_origin::value, - const typename dash::view_traits::origin_type & + !dash::view_traits::is_origin::value, + const typename dash::view_traits::origin_type & >::type { // Recurse to origin of local view: return dash::global_origin(view.domain()); } -template +template < + class ViewT, + typename ViewValueT = typename std::decay::type > constexpr auto -origin(const ViewT & view) +origin(ViewT && view) -> typename std::enable_if< - ( dash::view_traits::is_view::value && + ( dash::view_traits::is_view::value && dash::view_traits< - typename dash::view_traits::domain_type + typename dash::view_traits::domain_type >::is_local::value ), - const typename dash::view_traits::origin_type::local_type & + decltype(dash::local( + dash::global_origin(std::forward(view).domain()))) >::type { // Recurse to origin of local view: - return dash::local(dash::global_origin(view.domain())); + return dash::local( + dash::global_origin( + std::forward(view).domain())); } -template +template < + class ViewT, + typename ViewValueT = typename std::decay::type > constexpr auto origin(const ViewT & view) -> typename std::enable_if< - ( dash::view_traits::is_view::value && - dash::view_traits::is_local::value && + ( dash::view_traits::is_view::value && + dash::view_traits::is_local::value && !dash::view_traits< - typename dash::view_traits::domain_type + typename dash::view_traits::domain_type >::is_local::value ), - const typename dash::view_traits::origin_type & +// const typename dash::view_traits::origin_type & + decltype(dash::global_origin(view.domain())) >::type { // Recurse to global origin of local view: return dash::global_origin(view.domain()); @@ -97,6 +159,13 @@ origin(const ViewT & view) #endif // DOXYGEN +static inline auto origin() { + return dash::make_pipeable( + [](auto && x) { + return origin(std::forward(x)); + }); +} + } // namespace dash #endif // DASH__VIEW__ORIGIN_H__INCLUDED diff --git a/dash/include/dash/view/PatternIndexSet.h b/dash/include/dash/view/PatternIndexSet.h new file mode 100644 index 000000000..8c59c3de9 --- /dev/null +++ b/dash/include/dash/view/PatternIndexSet.h @@ -0,0 +1,402 @@ +#ifndef DASH__VIEW__PATTERN_INDEX_SET_H__INCLUDED +#define DASH__VIEW__PATTERN_INDEX_SET_H__INCLUDED + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#include + + +#ifndef DOXYGEN +namespace dash { + + +// Forward-declarations + +template +class IndexSetBase; + +template +class PatternIndexSetBase; + +template +class IndexSetIdentity; + +template +class IndexSetLocal; + +template +class IndexSetGlobal; + +template +class IndexSetSub; + +template +class IndexSetBlocks; + +template +class IndexSetBlock; + + +template < + class IndexSetType, + class DomainType, + dim_t NDim = DomainType::rank::value > +class IndexSetBase +{ + typedef IndexSetBase self_t; + + typedef typename std::decay::type DomainValueT; + + public: + typedef typename dash::view_traits::origin_type + view_origin_type; + typedef DomainValueT + view_domain_type; + typedef typename dash::view_traits::local_type + view_local_type; + typedef typename dash::view_traits::global_type + view_global_type; + + typedef typename view_traits::index_set_type + domain_type; + typedef typename dash::view_traits::index_set_type + local_type; + typedef typename dash::view_traits::index_set_type + global_type; + + typedef detail::IndexSetIterator + iterator; + typedef detail::IndexSetIterator + const_iterator; + typedef typename DomainType::size_type + size_type; + typedef typename DomainType::index_type + index_type; + typedef index_type + value_type; + + typedef typename detail::index_set_domain_bind_t::type + domain_member_type; + + typedef std::integral_constant + rank; + + static constexpr dim_t ndim() { return NDim; } + + protected: + domain_member_type _domain; + + constexpr const IndexSetType & derived() const { + return static_cast(*this); + } + + constexpr explicit IndexSetBase(const DomainType & domain) + : _domain(domain) + { } + + constexpr explicit IndexSetBase(DomainType && domain) + : _domain(std::move(domain)) + { } + + typedef struct { + index_type begin; + index_type end; + } index_range_t; + + static constexpr index_range_t index_range_intersect( + const index_range_t & a, + const index_range_t & b) noexcept { + return index_range_t { + std::max(a.begin, b.begin), + std::min(a.end, b.end) + }; + } + static constexpr index_type index_range_size( + const index_range_t & irng) noexcept { + return irng.end - irng.begin; + } + + ~IndexSetBase() = default; + public: + constexpr IndexSetBase() = delete; + constexpr IndexSetBase(self_t &&) = default; + constexpr IndexSetBase(const self_t &) = default; + self_t & operator=(self_t &&) = default; + self_t & operator=(const self_t &) = default; + + constexpr const DomainType & view_domain() const & { + return _domain; + } + + constexpr DomainType view_domain() const && { + return _domain; + } + + constexpr const typename view_origin_type::pattern_type & pattern() const { + return derived().pattern(); + } + + constexpr auto domain() const +// -> decltype(dash::index( +// std::declval() +// )) { + -> typename view_traits::index_set_type { + return dash::index(_domain); + } + + constexpr const local_type local() const { + return dash::index(dash::local(_domain)); + } + + constexpr const global_type global() const { + return dash::index(dash::global(_domain)); + } + + constexpr bool is_local() const noexcept { + return dash::view_traits::is_local::value; + } + + constexpr bool is_strided() const noexcept { + return false; + } + + constexpr bool is_sub() const noexcept { + return ( + derived().size() < this->extents().size() + ); + } + + constexpr bool is_shifted() const noexcept { + return false; + } + + // ---- extents --------------------------------------------------------- + + constexpr std::array + extents() const { + return derived().extents(); + } + + template + constexpr size_type extent() const { + return derived().extents()[ShapeDim]; + } + + constexpr size_type extent(dim_t shape_dim) const { + return derived().extents()[shape_dim]; + } + + // ---- offsets --------------------------------------------------------- + + constexpr std::array + offsets() const { + return std::array { }; + } + + template + constexpr index_type offset() const { + return derived().offsets()[ShapeDim]; + } + + constexpr index_type offset(dim_t shape_dim) const { + return derived().offsets()[shape_dim]; + } + + // ---- access ---------------------------------------------------------- + + constexpr index_type rel(index_type image_index) const { + return image_index; + } + + constexpr index_type rel( + const std::array & coords) const { + return -1; + } + + constexpr index_type operator[](index_type image_index) const { + return domain()[derived().rel(image_index)]; + } + + constexpr index_type operator[]( + const std::array & coords) const { + return domain()[derived().rel(coords)]; + } + + constexpr const_iterator begin() const { + return iterator(derived(), 0); + } + + constexpr const_iterator end() const { + return iterator(derived(), derived().size()); + } + + constexpr index_type first() const { + return derived()[0]; + } + + constexpr index_type last() const { + return derived()[ derived().size() - 1 ]; + } + + /* + * dash::index(r(10..100)).step(2)[8] -> 26 + * dash::index(r(10..100)).step(-5)[4] -> 80 + */ + constexpr const_iterator step(index_type stride) const { + return ( + stride > 0 + ? iterator(derived(), 0, stride) + : iterator(derived(), derived().size(), stride) + ); + } +}; + +/** + * \concept{DashIndexSetConcept} + */ +template < + class IndexSetType, + class DomainType, + class PatternType, + dim_t NDim = PatternType::ndim() > +class PatternIndexSetBase +: public IndexSetBase< +// IndexSetType, + PatternIndexSetBase< + IndexSetType, DomainType, PatternType, NDim + >, + DomainType, + NDim > +{ + typedef PatternIndexSetBase< + IndexSetType, + DomainType, + PatternType, + NDim + > + self_t; + typedef IndexSetBase< +// IndexSetType, + PatternIndexSetBase< + IndexSetType, + DomainType, + PatternType, + NDim + >, + DomainType, NDim + > + base_t; + + typedef typename std::decay::type DomainValueT; + + using typename base_t::index_range_t; + + public: + using typename base_t::size_type; + using typename base_t::index_type; + + typedef PatternType pattern_type; + + private: + const pattern_type * _pattern = nullptr; + + protected: + constexpr const IndexSetType & derived() const { + return static_cast(*this); + } + + template + static constexpr index_range_t index_range_g2l( + const PatternT_ & pat, + const index_range_t & grng) noexcept { + return index_range_t { + pat.local_coords({{ grng.begin }})[0], + pat.local_coords({{ grng.end }})[0] + }; + } + + template + static constexpr index_range_t index_range_l2g( + const PatternT_ & pat, + const index_range_t & lrng) noexcept { + return index_range_t { + pat.global(lrng.begin), + pat.global(lrng.end) + }; + } + + public: + constexpr PatternIndexSetBase() = delete; + constexpr PatternIndexSetBase(self_t &&) = default; + constexpr PatternIndexSetBase(const self_t &) = default; + self_t & operator=(self_t &&) = default; + self_t & operator=(const self_t &) = default; + + constexpr explicit PatternIndexSetBase(const DomainType & domain) + : base_t(domain) + , _pattern(&dash::origin(this->domain()).pattern()) + { } + + constexpr explicit PatternIndexSetBase(DomainType && domain) + : base_t(std::move(domain)) + , _pattern(&dash::origin(this->domain()).pattern()) + { } + + constexpr const pattern_type & pattern() const { + return *_pattern; + } + + constexpr bool is_strided() const noexcept { + return ( + ( this->pattern().blockspec().size() > + this->pattern().team().size() ) + || + ( this->pattern().ndim() > 1 && + this->domain().extent(1) < ( this->domain().is_local() + ? this->pattern().local_extents()[1] + : this->pattern().extents()[1] )) + ); + } + + constexpr bool is_shifted() const noexcept { + typedef typename dash::pattern_mapping_traits::type + pat_mapping_traits; + return pat_mapping_traits::shifted || + pat_mapping_traits::diagonal; + } + + size_type size() const { + return derived().size(); + } + + // ---- extents --------------------------------------------------------- + + constexpr std::array + extents() const { + return this->pattern().extents(); + } +}; +#endif + +} // namespace dash + +#endif // DOXYGEN + +#endif // DASH__VIEW__PATTERN_INDEX_SET_H__INCLUDED diff --git a/dash/include/dash/view/SetIntersect.h b/dash/include/dash/view/SetDifference.h similarity index 81% rename from dash/include/dash/view/SetIntersect.h rename to dash/include/dash/view/SetDifference.h index ed3045eba..3b6fc8bd2 100644 --- a/dash/include/dash/view/SetIntersect.h +++ b/dash/include/dash/view/SetDifference.h @@ -1,5 +1,5 @@ -#ifndef DASH__VIEW__SET_INTERSECT_H__INCLUDED -#define DASH__VIEW__SET_INTERSECT_H__INCLUDED +#ifndef DASH__VIEW__SET_DIFFERENCE_H__INCLUDED +#define DASH__VIEW__SET_DIFFERENCE_H__INCLUDED #include #include @@ -16,7 +16,7 @@ template < class ViewTypeA, class ViewTypeB > constexpr auto -intersect( +difference( const ViewTypeA & va, const ViewTypeB & vb) -> decltype(dash::sub(0, 0, va)) @@ -40,4 +40,4 @@ intersect( } // namespace dash -#endif // DASH__VIEW__SET_INTERSECT_H__INCLUDED +#endif // DASH__VIEW__SET_DIFFERENCE_H__INCLUDED diff --git a/dash/include/dash/view/Sub.h b/dash/include/dash/view/Sub.h index 8c9960f80..f439f6f8a 100644 --- a/dash/include/dash/view/Sub.h +++ b/dash/include/dash/view/Sub.h @@ -5,6 +5,7 @@ #include #include +#include namespace dash { @@ -13,21 +14,7 @@ namespace dash { // View Modifiers (not coupled with origin memory / index space): // ------------------------------------------------------------------------- -/** - * Sub-section, view dimensions maintain domain dimensions. - * - * \concept{DashViewConcept} - */ -template < - dim_t SubDim = 0, - dim_t NViewDim, - class OffsetFirstT, - class OffsetFinalT > -constexpr ViewSubMod, SubDim> -sub(OffsetFirstT begin, - OffsetFinalT end) { - return ViewSubMod, SubDim>(begin, end); -} +#if 0 /** * Sub-section, view dimensions maintain domain dimensions. @@ -43,25 +30,11 @@ sub(const IndexRangeT & range) { return sub(dash::begin(range), dash::end(range)); } - -#if 0 -/** - * Sub-space projection, view reduces domain by one dimension. - * - * \concept{DashViewConcept} - */ -template < - dim_t SubDim = 0, - class OffsetT > -constexpr ViewSubMod -sub( - OffsetT offset) { - return ViewSubMod(offset); -} #endif + // ------------------------------------------------------------------------- -// View Proxies (coupled with origin memory / index space): +// View Operations (coupled with origin memory / index space): // ------------------------------------------------------------------------- template < @@ -69,21 +42,20 @@ template < class DomainT, class OffsetFirstT, class OffsetFinalT, - typename DomainValueT = typename std::decay::type > + typename DomainDecayT = typename std::decay::type > constexpr ViewSubMod< - DomainValueT, + DomainDecayT, SubDim, - dash::view_traits::rank::value > -sub( - OffsetFirstT begin, + dash::rank::value > +sub(OffsetFirstT begin, OffsetFinalT end, - const DomainT & domain) { + DomainT && domain) { return ViewSubMod< - DomainValueT, + DomainDecayT, SubDim, - dash::view_traits::rank::value - >(domain, + dash::view_traits::rank::value + >(std::forward(domain), begin, end); } @@ -91,27 +63,73 @@ sub( template < dim_t SubDim = 0, class DomainT, - class OffsetFirstT, - class OffsetFinalT, - typename DomainValueT = typename std::decay::type > -constexpr -ViewSubMod< - DomainValueT, - SubDim, - dash::view_traits::rank::value > -sub( - OffsetFirstT begin, - OffsetFinalT end, - DomainT && domain) { - return ViewSubMod< - DomainValueT, - SubDim, - dash::view_traits::rank::value - >(std::forward(domain), - begin, - end); + class OffsetT, + typename DomainDecayT = typename std::decay::type, + typename std::enable_if< + (!std::is_integral::value && + std::is_integral::value ), + int + >::type = 0 > +constexpr auto +sub(OffsetT offset, + DomainT && domain) + -> decltype(dash::sub(offset, offset+1, domain)) { + return dash::sub(offset, offset+1, domain); +} + +template < + dim_t SubDim = 0, + class OffsetT0, + class OffsetT1, + typename std::enable_if< + ( std::is_integral::value && + std::is_integral::value ), + int + >::type = 0 > +static inline auto sub(OffsetT0 a, OffsetT1 b) { + return dash::make_pipeable( + [=](auto && x) { + return sub(a,b, std::forward(x)); + }); +} + +// ------------------------------------------------------------------------- +// Rectangular Region +// ------------------------------------------------------------------------- + +#if 0 +template < + class DomainT > +auto region( + DomainT && domain) { + return std::forward(domain); } +/** + * + * \code + * auto reg = matrix | region({ 2,6 }, { 1,5 }); + * // returns sub-matrix within rectangle (2,1), (6,5) + * \endcode + */ +template < + class DomainT, + typename IndexT = typename dash::view_traits::index_type, + dim_t NDim = dash::rank::value, + typename ... Args > +auto region( + DomainT && domain, + const std::array & dsub, + Args ... subs) { + return region( + dash::sub( + std::get<0>(dsub), + std::get<1>(dsub), + std::forward(domain)), + subs...); +} +#endif + } // namespace dash #endif // DASH__VIEW__SUB_H__INCLUDED diff --git a/dash/include/dash/view/Utility.h b/dash/include/dash/view/Utility.h new file mode 100644 index 000000000..fd32d6eff --- /dev/null +++ b/dash/include/dash/view/Utility.h @@ -0,0 +1,126 @@ +#ifndef DASH__VIEW__UTILITY_H__INCLUDED +#define DASH__VIEW__UTILITY_H__INCLUDED + +#include +#include + +/* + * Pipe utils adapted from implementation in range-v3, + * published under Boost Software License Version 1.0 + * (c) Eric Niebler, Casey Carter + * + * See: + * https://github.com/ericniebler/range-v3/ + * Source: + * include/range/v3/utility/functional.hpp + * + */ + +namespace dash { + +namespace internal { + + struct PipeableBase + {}; + + template + struct is_pipeable : std::is_base_of + {}; + + template + struct is_pipeable : is_pipeable + {}; + + struct PipeableAccess + { + template + struct impl : PipeableT { + using PipeableT::pipe; + }; + + template + struct impl : impl + {}; + }; + + template + struct Pipeable : PipeableBase { + private: + friend PipeableAccess; + template + static auto pipe(Arg && arg, Pipe p) + -> decltype(p(static_cast(arg))) { + p(static_cast(arg)); + } + }; + + template + struct PipeableBinder : Bind, Pipeable< PipeableBinder > { + PipeableBinder(Bind bind) + : Bind(std::move(bind)) + {} + }; + + template + struct ComposedPipe { + PipeA pipe_a; + PipeB pipe_b; + template + auto operator()(Arg && arg) const + -> decltype(static_cast(arg) | pipe_a | pipe_b) { + return static_cast(arg) | pipe_a | pipe_b; + } + }; + + struct make_pipeable_fn { + template + PipeableBinder operator()(Fun fun) const { + return { std::move(fun) }; + } + }; + +} // namespace internal + +inline namespace { + constexpr internal::make_pipeable_fn make_pipeable { }; +} + +/** + * Compose pipes. + * + * ... | + */ +template < + typename PipeA, + typename PipeB, + typename std::enable_if< + ( internal::is_pipeable::value && + internal::is_pipeable::value ), + int + >::type = 0 > +auto operator|(PipeA a, PipeB b) +-> decltype(make_pipeable(internal::ComposedPipe { a, b })) { + return make_pipeable(internal::ComposedPipe { a, b }); +} + +/** + * Evaluate a pipe. + * + * arg | + */ +template < + typename Arg, + typename Pipe, + typename std::enable_if< + (!internal::is_pipeable::value && + internal::is_pipeable::value ), + int + >::type = 0 > +auto operator|(Arg && arg, Pipe pipe) +-> decltype(pipe(arg)) { + return pipe(arg); +} + +} // namespace dash + +#endif // DASH__VIEW__UTILITY_H__INCLUDED diff --git a/dash/include/dash/view/ViewBlocksMod.h b/dash/include/dash/view/ViewBlocksMod.h index 433b90f99..caad3a1c7 100644 --- a/dash/include/dash/view/ViewBlocksMod.h +++ b/dash/include/dash/view/ViewBlocksMod.h @@ -11,14 +11,17 @@ #include #include +#include #include #include #include #include #include -#include +#include #include +#include + namespace dash { @@ -27,63 +30,287 @@ namespace dash { // ------------------------------------------------------------------------ // Forward-declarations // ------------------------------------------------------------------------ -// + +template < + class DomainType, + dim_t NDim > +class ViewBlockMod; + template < class DomainType, - dim_t NDim = dash::view_traits< - typename std::decay::type>::rank::value > + dim_t NDim = dash::view_traits< + typename std::decay::type>::rank::value > class ViewBlocksMod; + // ------------------------------------------------------------------------ // ViewBlockMod // ------------------------------------------------------------------------ template < - class DomainType > -struct view_traits > { + class DomainType, + dim_t NDim > +struct view_traits > { typedef DomainType domain_type; typedef typename view_traits::origin_type origin_type; - typedef typename view_traits::pattern_type pattern_type; - typedef ViewBlockMod image_type; - typedef ViewBlockMod local_type; - typedef ViewBlockMod global_type; + typedef ViewBlockMod image_type; + typedef ViewBlockMod local_type; + typedef ViewBlockMod global_type; typedef typename DomainType::index_type index_type; - // TODO: Defaulting to SubDim = 0 here, clarify - typedef dash::IndexSetSub index_set_type; + typedef typename DomainType::size_type size_type; +//typedef typename view_traits::size_type size_type; + typedef typename std::conditional< + NDim == 1, + dash::IndexSetSub, + dash::IndexSetBlock + >::type index_set_type; typedef std::integral_constant is_projection; typedef std::integral_constant is_view; typedef std::integral_constant is_origin; - typedef std::integral_constant::is_local::value > is_local; + typedef typename view_traits::is_local is_local; + + typedef std::integral_constant is_contiguous; - typedef std::integral_constant rank; + typedef std::integral_constant rank; }; +// ------------------------------------------------------------------------ +// ViewBlockMod +// ------------------------------------------------------------------------ + template < - class DomainType > + class DomainType, + dim_t NDim > class ViewBlockMod -// Actually just an adapter for block_idx -> sub(begin_idx, end_idx), -// should sublass +: public ViewModBase < + ViewBlockMod, + DomainType, + NDim > +{ + private: + typedef ViewBlockMod self_t; + typedef ViewModBase< + ViewBlockMod, DomainType, NDim> base_t; + public: + typedef DomainType domain_type; + typedef typename view_traits::index_type index_type; + typedef typename view_traits::size_type size_type; + typedef typename base_t::origin_type origin_type; + public: + typedef dash::IndexSetBlock index_set_type; + typedef ViewLocalMod local_type; + typedef self_t global_type; + + typedef std::integral_constant is_local; + + typedef decltype( + dash::begin( + std::declval< + typename std::add_lvalue_reference< + origin_type>::type + >() )) + origin_iterator; + + typedef decltype( + dash::begin( + std::declval< + typename std::add_lvalue_reference< + const origin_type>::type + >() )) + const_origin_iterator; + + typedef ViewIterator + iterator; + typedef ViewIterator + const_iterator; + + typedef + decltype(*dash::begin( + std::declval< + typename std::add_lvalue_reference< + origin_type>::type + >() )) + reference; + + typedef + decltype(*dash::begin( + std::declval< + typename std::add_lvalue_reference< + const origin_type>::type + >() )) + const_reference; + + private: + index_set_type _index_set; + + public: + constexpr ViewBlockMod() = delete; + constexpr ViewBlockMod(self_t &&) = default; + constexpr ViewBlockMod(const self_t &) = default; + ~ViewBlockMod() = default; + self_t & operator=(self_t &&) = default; + self_t & operator=(const self_t &) = default; + + constexpr ViewBlockMod( + const domain_type & domain, + index_type block_idx) + : base_t(domain) + , _index_set(domain, + block_idx) + { } + + /** + * Constructor, creates a view on a block in the specified domain. + */ + constexpr ViewBlockMod( + domain_type && domain, + index_type block_idx) + : base_t(std::move(domain)) + , _index_set(this->domain(), + block_idx) + { } + + // ---- properties ------------------------------------------------------ + + constexpr bool is_strided() const noexcept { + return _index_set.is_strided(); + } + + constexpr bool is_local_at(dash::team_unit_t uid) const noexcept { + return _index_set.is_local() + && uid == _index_set.pattern().team().myid(); + } + + // ---- extents --------------------------------------------------------- + + constexpr std::array extents() const { + return _index_set.extents(); + } + + template + constexpr size_type extent() const { + return _index_set.template extent(); + } + + constexpr size_type extent(dim_t shape_dim) const { + return _index_set.extent(shape_dim); + } + + // ---- offsets --------------------------------------------------------- + + template + constexpr index_type offset() const { + return _index_set.template offset(); + } + + constexpr std::array offsets() const { + return _index_set.offsets(); + } + + constexpr index_type offset(dim_t shape_dim) const { + return _index_set.offset(shape_dim); + } + + // ---- size ------------------------------------------------------------ + + constexpr size_type size() const { + return index_set().size(); + } + + constexpr const_iterator begin() const { + return const_iterator(dash::origin(*this).begin(), + _index_set, 0); + } + + iterator begin() { + return iterator(dash::origin( + const_cast(*this) + ).begin(), + _index_set, 0); + } + + constexpr const_iterator end() const { + return const_iterator(dash::origin(*this).begin(), + _index_set, _index_set.size()); + } + + iterator end() { + return iterator(dash::origin( + const_cast(*this) + ).begin(), + _index_set, _index_set.size()); + } + + constexpr const_reference operator[](int offset) const { + return *(const_iterator(dash::origin(*this).begin(), + _index_set, offset)); + } + + reference operator[](int offset) { + return *(iterator(dash::origin(*this).begin(), + _index_set, offset)); + } + + constexpr const_reference operator[]( + const std::array< + typename self_t::index_set_type::index_type, + self_t::rank::value + > & coords) const { + return *(const_iterator(dash::origin(*this).begin(), + _index_set, + // offset: + dash::linearize(*this, coords))); + } + + reference operator[]( + const std::array< + typename self_t::index_set_type::index_type, + self_t::rank::value + > & coords) { + return *(iterator(dash::origin(*this).begin(), + _index_set, + // offset: + dash::linearize(*this, coords))); + } + + constexpr const index_set_type & index_set() const { + return _index_set; + } + + constexpr local_type local() const { + return local_type(*this); + } +}; // class ViewBlockMod + + +// ------------------------------------------------------------------------ +// ViewBlockMod<1> +// ------------------------------------------------------------------------ + +template < + class DomainType > +class ViewBlockMod +// One-dimensional blocks are actually just an adapter for +// block_idx -> sub(begin_idx, end_idx), could be defined by sublassing // // public ViewSubMod // : public ViewModBase < - ViewBlockMod, - DomainType > + ViewBlockMod, + DomainType, + 1 > { private: - typedef ViewBlockMod self_t; - typedef ViewModBase< ViewBlockMod, DomainType > base_t; + typedef ViewBlockMod self_t; + typedef ViewModBase< ViewBlockMod, DomainType, 1 > base_t; public: typedef DomainType domain_type; typedef typename view_traits::index_type index_type; -//typedef typename view_traits::origin_type origin_type; typedef typename base_t::origin_type origin_type; public: - // TODO: Defaulting to SubDim = 0 here, clarify typedef dash::IndexSetSub< DomainType, 0 > index_set_type; typedef ViewLocalMod local_type; typedef self_t global_type; @@ -93,14 +320,16 @@ class ViewBlockMod typedef decltype( dash::begin( std::declval< - typename std::add_lvalue_reference::type + typename std::add_lvalue_reference< + origin_type>::type >() )) origin_iterator; typedef decltype( dash::begin( std::declval< - typename std::add_lvalue_reference::type + typename std::add_lvalue_reference< + const origin_type>::type >() )) const_origin_iterator; @@ -112,14 +341,16 @@ class ViewBlockMod typedef decltype(*dash::begin( std::declval< - typename std::add_lvalue_reference::type + typename std::add_lvalue_reference< + origin_type>::type >() )) reference; typedef decltype(*dash::begin( std::declval< - typename std::add_lvalue_reference::type + typename std::add_lvalue_reference< + const origin_type>::type >() )) const_reference; @@ -149,20 +380,31 @@ class ViewBlockMod constexpr ViewBlockMod( domain_type && domain, index_type block_idx) - : base_t(std::forward(domain)) + : base_t(std::move(domain)) , _index_set(this->domain(), block_first_gidx(this->domain(), block_idx), block_final_gidx(this->domain(), block_idx)) { } + constexpr bool is_strided() const noexcept { + return false; // 1-dimensional blocks are contiguous + } + + constexpr bool is_local_at(dash::team_unit_t uid) const noexcept { + return // Domain is local, block must be local: + dash::view_traits::is_local::value || + // First element is local, so block is local: + _index_set.pattern().unit_at(_index_set[0]) == uid; + } + constexpr const_iterator begin() const { return const_iterator(dash::origin(*this).begin(), _index_set, 0); } iterator begin() { - return iterator(const_cast( - dash::origin(*this) + return iterator(dash::origin( + const_cast(*this) ).begin(), _index_set, 0); } @@ -173,8 +415,8 @@ class ViewBlockMod } iterator end() { - return iterator(const_cast( - dash::origin(*this) + return iterator(dash::origin( + const_cast(*this) ).begin(), _index_set, _index_set.size()); } @@ -201,8 +443,8 @@ class ViewBlockMod // If domain is local, block_idx refers to local block range // so use pattern().local_block(block_idx) // - // TODO: Currently values passed as `block_idx` are global block indices - // even if domain is local + // TODO: Currently values passed as `block_idx` are global block + // indices, even if domain is local return std::max( ( // block viewspec (extents, offsets) ( false && @@ -226,8 +468,8 @@ class ViewBlockMod // If domain is local, block_idx refers to local block range // so use pattern().local_block(block_idx) // - // TODO: Currently values passed as `block_idx` are global block indices - // even if domain is local + // TODO: Currently values passed as `block_idx` are global block + // indices, even if domain is local return std::min( dash::index(vdomain).last() + 1, ( // block viewspec (extents, offsets) @@ -249,18 +491,12 @@ class ViewBlockMod ) - dash::index(vdomain).first(); } -}; +}; // class ViewBlockMod<1> // ------------------------------------------------------------------------ // ViewBlocksMod // ------------------------------------------------------------------------ -template -constexpr ViewBlocksMod -blocks(const ViewType & domain) { - return ViewBlocksMod(domain); -} - template < class ViewType, class ViewValueT @@ -270,26 +506,39 @@ blocks(ViewType && domain) { return ViewBlocksMod(std::forward(domain)); } +#if 0 +/** + * `blocks(block(D)) -> block(D)` + */ +template < + class BlockDomain, + dim_t NBlockDim > +constexpr ViewBlockMod & +blocks(ViewBlockMod & block_view) { + return block_view; +} +#endif + template < class DomainType, dim_t NDim > struct view_traits > { typedef DomainType domain_type; typedef typename view_traits::origin_type origin_type; - typedef typename view_traits::pattern_type pattern_type; typedef ViewBlocksMod image_type; - typedef typename domain_type::local_type local_type; + typedef typename view_traits::local_type local_type; typedef ViewBlocksMod global_type; - typedef typename DomainType::index_type index_type; - typedef dash::IndexSetBlocks> + typedef typename view_traits::index_type index_type; + typedef typename view_traits::size_type size_type; + typedef dash::IndexSetBlocks index_set_type; typedef std::integral_constant is_projection; typedef std::integral_constant is_view; typedef std::integral_constant is_origin; - typedef std::integral_constant::is_local::value > is_local; + typedef typename view_traits::is_local is_local; + typedef typename view_traits::is_contiguous is_contiguous; typedef std::integral_constant rank; }; @@ -301,17 +550,18 @@ class ViewBlocksMod : public ViewModBase< ViewBlocksMod, DomainType, NDim > { private: typedef ViewBlocksMod self_t; +//typedef ViewBlocksMod const_self_t; + typedef ViewBlocksMod const_self_t; typedef ViewModBase, DomainType, NDim> base_t; - typedef ViewBlocksMod const_self_t; public: typedef DomainType domain_type; typedef typename base_t::origin_type origin_type; typedef typename view_traits::index_type index_type; typedef typename view_traits::size_type size_type; private: - typedef ViewBlockMod block_type; - typedef typename domain_type::local_type domain_local_type; + typedef ViewBlockMod block_type; + typedef typename view_traits::local_type domain_local_type; public: typedef dash::IndexSetBlocks index_set_type; typedef self_t global_type; @@ -370,7 +620,8 @@ class ViewBlocksMod ViewBlocksModType && blocks_view, index_type position) : iterator_base_t(position) - , _blocks_view_domain(std::forward(blocks_view)) + , _blocks_view_domain( + dash::domain(std::move(blocks_view))) { } constexpr block_type dereference(index_type idx) const { @@ -378,21 +629,22 @@ class ViewBlocksMod // with iterator position. // Note that block index is relative to the domain and is // translated to global block index in IndexSetBlocks. - return ViewBlockMod( - _blocks_view_domain, - idx); + return block_type(_blocks_view_domain, idx); } }; public: - typedef block_iterator iterator; - typedef block_iterator const_iterator; + typedef block_iterator iterator; + typedef block_iterator const_iterator; + + using reference = typename iterator::reference; + using const_reference = typename const_iterator::reference; public: + ~ViewBlocksMod() = default; constexpr ViewBlocksMod() = delete; constexpr ViewBlocksMod(const self_t &) = default; constexpr ViewBlocksMod(self_t &&) = default; - ~ViewBlocksMod() = default; self_t & operator=(self_t &&) = default; self_t & operator=(const self_t &) = default; @@ -410,12 +662,40 @@ class ViewBlocksMod */ constexpr explicit ViewBlocksMod( domain_type && domain) - : base_t(std::forward(domain)) + : base_t(std::move(domain)) , _index_set(this->domain()) { } + // ---- extents --------------------------------------------------------- + + constexpr decltype(_index_set.extents()) extents() const { + return _index_set.extents(); + } + + template + constexpr size_type extent() const { + return _index_set.template extent(); + } + + constexpr size_type extent(dim_t shape_dim) const { + return _index_set.extent(shape_dim); + } + // ---- offsets --------------------------------------------------------- + template + constexpr index_type offset() const { + return _index_set.template offset(); + } + + constexpr decltype(_index_set.offsets()) offsets() const { + return _index_set.offsets(); + } + + constexpr index_type offset(dim_t shape_dim) const { + return _index_set.offset(shape_dim); + } + // ---- size ------------------------------------------------------------ constexpr size_type size() const { @@ -425,19 +705,21 @@ class ViewBlocksMod // ---- access ---------------------------------------------------------- constexpr const_iterator begin() const { - return const_iterator(*const_cast(this), + return const_iterator(*this, _index_set.first()); } iterator begin() { - return iterator(*this, _index_set.first()); + return iterator(const_cast(*this), + _index_set.first()); } constexpr const_iterator end() const { - return const_iterator(*const_cast(this), + return const_iterator(*this, _index_set.last() + 1); } iterator end() { - return iterator(*this, _index_set.last() + 1); + return iterator(const_cast(*this), + _index_set.last() + 1); } constexpr block_type operator[](int offset) const { @@ -466,6 +748,20 @@ class ViewBlocksMod #endif // DOXYGEN +static inline auto blocks() { + return dash::make_pipeable( + [](auto && x) { + return blocks(std::forward(x)); + }); +} + +static inline auto block(int bi) { + return dash::make_pipeable( + [=](auto && x) { + return blocks(std::forward(x))[bi]; + }); +} + } // namespace dash #endif // DASH__VIEW__VIEW_BLOCKS_MOD_H__INCLUDED diff --git a/dash/include/dash/view/ViewChunksMod.h b/dash/include/dash/view/ViewChunksMod.h new file mode 100644 index 000000000..f64202e48 --- /dev/null +++ b/dash/include/dash/view/ViewChunksMod.h @@ -0,0 +1,33 @@ +#ifndef DASH__VIEW__VIEW_CHUNKS_MOD_H__INCLUDED +#define DASH__VIEW__VIEW_CHUNKS_MOD_H__INCLUDED + +#include +#include +#include + +#include +#include +#include + + +namespace dash { + +#ifndef DOXYGEN + +// ------------------------------------------------------------------------ +// Forward-declarations +// ------------------------------------------------------------------------ +// +template < + class DomainType, + dim_t NDim = dash::view_traits< + typename std::decay::type>::rank::value > +class ViewChunksMod; + + + +#endif // DOXYGEN + +} // namespace dash + +#endif // DASH__VIEW__VIEW_CHUNKS_MOD_H__INCLUDED diff --git a/dash/include/dash/view/ViewIterator.h b/dash/include/dash/view/ViewIterator.h index 1ddd66542..c7e62e824 100644 --- a/dash/include/dash/view/ViewIterator.h +++ b/dash/include/dash/view/ViewIterator.h @@ -25,7 +25,7 @@ class ViewIterator typename DomainIterator::difference_type, // difference type typename DomainIterator::pointer, // pointer typename DomainIterator::reference // reference -> { + > { typedef ViewIterator self_t; typedef dash::internal::IndexIteratorBase< ViewIterator, @@ -42,11 +42,25 @@ class ViewIterator typedef typename base_t::reference reference; typedef typename base_t::value_type value_type; typedef typename IndexSetType::index_type index_type; + typedef typename DomainIterator::pattern_type pattern_type; + typedef typename DomainIterator::local_type local_type; + + typedef std::integral_constant has_view; + + typedef IndexSetType index_set_type; + + typedef DomainIterator domain_iterator; private: DomainIterator _domain_it; IndexSetType _index_set; public: - constexpr ViewIterator() = delete; + constexpr ViewIterator() = delete; + + ViewIterator(self_t && other) = default; + self_t & operator=(self_t && other) = default; + + ViewIterator(const self_t & other) = default; + self_t & operator=(const self_t & other) = default; template ViewIterator( @@ -84,14 +98,18 @@ class ViewIterator return (_index_set)[this->pos()]; } - constexpr const value_type * local() const { - return (_domain_it + (_index_set[this->pos()])).local(); + constexpr bool is_local() const { + return (_domain_it + (_index_set[this->pos()])).is_local(); } - inline value_type * local() { + constexpr local_type local() const { return (_domain_it + (_index_set[this->pos()])).local(); } + constexpr const self_t & global() const { + return *this; + } + constexpr dart_gptr_t dart_gptr() const { return (_domain_it + _index_set[this->pos()]).dart_gptr(); } @@ -100,9 +118,29 @@ class ViewIterator return dart_gptr(); } - constexpr explicit operator DomainIterator() const { + constexpr const dash::Team & team() const { + return _domain_it.team(); + } + + constexpr explicit operator domain_iterator() const { + return (_domain_it + _index_set[this->pos()]); + } + + explicit operator domain_iterator() { return (_domain_it + _index_set[this->pos()]); } + + constexpr domain_iterator domain() const { + return (_domain_it + _index_set[this->pos()]); + } + + constexpr const pattern_type & pattern() const { + return _domain_it.pattern(); + } + + constexpr const index_set_type & index_set() const { + return _index_set; + } }; template < @@ -116,7 +154,7 @@ class ViewIterator DomainIterator *, DomainIterator & > { - typedef ViewIterator self_t; + typedef ViewIterator self_t; typedef dash::internal::IndexIteratorBase< ViewIterator, DomainIterator, @@ -132,24 +170,60 @@ class ViewIterator typedef DomainIterator & reference; typedef DomainIterator value_type; typedef std::ptrdiff_t index_type; + typedef self_t local_type; private: DomainIterator * _domain_it; IndexSetType _index_set; public: - constexpr ViewIterator() = delete; + constexpr ViewIterator() = delete; - template + ViewIterator(const self_t & other) + : base_t(other.pos()) + , _domain_it(other._domain_it) + , _index_set(other._index_set) + { } + + ViewIterator(self_t && other) + : base_t(other.pos()) + , _domain_it(other._domain_it) + , _index_set(other._index_set) + { } + + self_t & operator=(const self_t & other) { + base_t::operator=(other); + _domain_it = other._domain_it; + _index_set = other._index_set; + } + + self_t & operator=(self_t && other) { + base_t::operator=(other); + _domain_it = other._domain_it; + _index_set = other._index_set; + } + + template ViewIterator( DomainItType * domain_it, - const IndexSetType & index_set, + const IndexSetO & index_set, index_type position) : base_t(position) , _domain_it(domain_it) , _index_set(index_set) { } + template ViewIterator( const self_t & other, + const IndexSetO & index_set, + index_type position) + : base_t(position) + , _domain_it(other._domain_it) + , _index_set(index_set) + { } + + template + ViewIterator( + const ViewIteratorO & other, index_type position) : base_t(position) , _domain_it(other._domain_it) @@ -171,6 +245,18 @@ class ViewIterator inline value_type * local() { return (_domain_it + (_index_set[this->pos()])).local(); } + + constexpr explicit operator const value_type *() const { + return (_domain_it + (_index_set[this->pos()])).local(); + } + + explicit operator value_type *() { + return (_domain_it + (_index_set[this->pos()])).local(); + } + + constexpr explicit operator DomainIterator() const { + return (_domain_it + _index_set[this->pos()]); + } }; template diff --git a/dash/include/dash/view/ViewMod.h b/dash/include/dash/view/ViewMod.h index bd660ee93..530e9fcbd 100644 --- a/dash/include/dash/view/ViewMod.h +++ b/dash/include/dash/view/ViewMod.h @@ -2,8 +2,8 @@ #define DASH__VIEW__VIEW_MOD_H__INCLUDED #include -#include #include +#include #include #include @@ -146,8 +146,6 @@ class ViewGlobalMod; #endif // DOXYGEN - - // ------------------------------------------------------------------------ // ViewModBase // ------------------------------------------------------------------------ @@ -159,29 +157,23 @@ template < class ViewModBase { typedef ViewModBase self_t; -public: - typedef DomainType domain_type; + public: + typedef DomainType domain_type; - typedef typename std::conditional< - view_traits::is_origin::value, + // TODO: Clarify if origins should always be considered const + // + typedef typename std::conditional<( + view_traits::is_origin::value && + !view_traits::is_view::value && + !std::is_copy_constructible::value + ), const domain_type &, domain_type >::type domain_member_type; - // TODO: BUG! - // For example, assume - // domain = sub(local(array)) - // then view_traits::is_local resolves to `true` - // and domain_type is defined as ViewSub> - // instead of ViewLocal or Array::local_type. - // - // Note that the origin of ViewLocalMod is the global origin - // while the origin of and view on ViewLocalMod is the local - // origin. typedef typename std::conditional< view_traits::is_local::value, - // domain_type, typename view_traits< typename view_traits::origin_type >::local_type, @@ -225,9 +217,15 @@ class ViewModBase static constexpr dim_t ndim() { return NDim; } -protected: + protected: domain_member_type _domain; + // TODO: Index set should be member of ViewModBase as all models of the + // view concept depend on an index set type. + // As constructors of index set classes depend on the concrete view + // type, index sets should be instantiated in derived view subclass + // and passed to ViewModBase base constructor. + ViewModType & derived() { return static_cast(*this); } @@ -239,7 +237,7 @@ class ViewModBase * Constructor, creates a view on a given domain. */ constexpr explicit ViewModBase(domain_type && domain) - : _domain(std::forward(domain)) + : _domain(std::move(domain)) { } /** @@ -252,17 +250,17 @@ class ViewModBase constexpr ViewModBase() = delete; ~ViewModBase() = default; -public: + public: constexpr ViewModBase(const self_t &) = default; constexpr ViewModBase(self_t &&) = default; self_t & operator=(const self_t &) = default; self_t & operator=(self_t &&) = default; - constexpr const domain_type & domain() const & { + constexpr domain_type domain() const && { return _domain; } - constexpr domain_type domain() const && { + constexpr const domain_type & domain() const & { return _domain; } @@ -274,8 +272,9 @@ class ViewModBase return !(derived() == rhs); } - constexpr bool is_local() const { - return view_traits::is_local::value; + constexpr bool is_local_at(dash::team_unit_t uid) const noexcept { + return view_traits::is_local::value + && uid == dash::index(*this).pattern().team().myid(); } // ---- extents --------------------------------------------------------- @@ -313,6 +312,28 @@ class ViewModBase constexpr index_type size() const { return dash::index(derived()).size(); } + + constexpr bool empty() const noexcept { + return size() == 0; + } + + constexpr bool operator!() const noexcept { + return empty(); + } + + constexpr explicit operator bool() const noexcept { + return !empty(); + } + + // ---- access ---------------------------------------------------------- + + template + constexpr const_reference operator[]( + const std::array< + IdxT, self_t::rank::value + > & coords) const { + return derived()[ dash::linearize(derived(), coords) ]; + } }; @@ -326,19 +347,20 @@ template < struct view_traits > { typedef DomainType domain_type; typedef typename view_traits::origin_type origin_type; - typedef typename view_traits::pattern_type pattern_type; - typedef typename domain_type::local_type image_type; - typedef ViewLocalMod local_type; + typedef typename view_traits::local_type image_type; + typedef ViewLocalMod local_type; typedef domain_type global_type; typedef typename view_traits::index_type index_type; typedef typename view_traits::size_type size_type; typedef dash::IndexSetLocal index_set_type; - typedef std::integral_constant is_projection; - typedef std::integral_constant is_view; - typedef std::integral_constant is_origin; - typedef std::integral_constant is_local; + typedef std::integral_constant is_projection; + typedef std::integral_constant is_view; + typedef std::integral_constant is_origin; + typedef std::integral_constant is_local; + + typedef typename view_traits::is_contiguous is_contiguous; typedef std::integral_constant rank; }; @@ -351,17 +373,17 @@ class ViewLocalMod ViewLocalMod, DomainType, NDim > { -public: + public: typedef DomainType domain_type; typedef typename view_traits::origin_type origin_type; typedef typename domain_type::local_type image_type; typedef typename view_traits::index_type index_type; typedef typename view_traits::size_type size_type; -private: - typedef ViewLocalMod self_t; + private: + typedef ViewLocalMod self_t; typedef ViewModBase< - ViewLocalMod, DomainType, NDim > base_t; -public: + ViewLocalMod, DomainType, NDim > base_t; + public: typedef dash::IndexSetLocal index_set_type; typedef self_t local_type; typedef typename domain_type::global_type global_type; @@ -373,17 +395,26 @@ class ViewLocalMod dash::begin( dash::local(dash::origin( std::declval< - typename std::add_lvalue_reference::type >() + typename std::add_lvalue_reference< + domain_type>::type >() )))) - iterator; + origin_iterator; typedef decltype( dash::begin( dash::local(dash::origin( std::declval< - typename std::add_lvalue_reference::type >() + typename std::add_lvalue_reference< + const domain_type>::type >() )))) + const_origin_iterator; + + typedef ViewIterator< + origin_iterator, index_set_type > + iterator; + typedef ViewIterator< + const_origin_iterator, index_set_type > const_iterator; typedef @@ -391,7 +422,8 @@ class ViewLocalMod *(dash::begin( dash::local(dash::origin( std::declval< - typename std::add_lvalue_reference::type >() + typename std::add_lvalue_reference< + domain_type>::type >() ))))) reference; @@ -400,13 +432,14 @@ class ViewLocalMod *(dash::begin( dash::local(dash::origin( std::declval< - typename std::add_lvalue_reference::type >() + typename std::add_lvalue_reference< + const domain_type>::type >() ))))) const_reference; -private: + private: index_set_type _index_set; -public: + public: constexpr ViewLocalMod() = delete; constexpr ViewLocalMod(self_t &&) = default; constexpr ViewLocalMod(const self_t &) = default; @@ -419,7 +452,7 @@ class ViewLocalMod */ constexpr explicit ViewLocalMod( domain_type && domain) - : base_t(std::forward(domain)) + : base_t(std::move(domain)) , _index_set(this->domain()) { } @@ -429,7 +462,7 @@ class ViewLocalMod constexpr explicit ViewLocalMod( const DomainType & domain) : base_t(domain) - , _index_set(domain) + , _index_set(this->domain()) { } constexpr bool operator==(const self_t & rhs) const { @@ -450,11 +483,13 @@ class ViewLocalMod template constexpr size_type extent() const { - return _index_set.template extent(); +// return _index_set.template extent(); + return _index_set.extents()[ShapeDim]; } constexpr size_type extent(dim_t shape_dim) const { - return _index_set.extent(shape_dim); +// return _index_set.extent(shape_dim); + return _index_set.extents()[shape_dim]; } // ---- offsets --------------------------------------------------------- @@ -472,48 +507,54 @@ class ViewLocalMod // ---- access ---------------------------------------------------------- constexpr const_iterator begin() const { - return dash::begin( - dash::local( - dash::origin(*this) )) - + _index_set[0]; + return const_iterator( + dash::begin( + dash::local( + dash::origin(*this) )), + _index_set, 0); } iterator begin() { - return dash::begin( - dash::local( - const_cast(dash::origin(*this)) - )) - + _index_set[0]; + return iterator( + dash::begin( + dash::local( + dash::origin( + const_cast(*this) ))), + _index_set, 0); } constexpr const_iterator end() const { - return dash::begin( - dash::local( - dash::origin(*this) )) - + _index_set[_index_set.size() - 1] + 1; + return const_iterator( + dash::begin( + dash::local( + dash::origin(*this) )), + _index_set, _index_set.size()); } iterator end() { - return dash::begin( - dash::local( - const_cast(dash::origin(*this)) - )) - + _index_set[_index_set.size() - 1] + 1; + return iterator( + dash::begin( + dash::local( + dash::origin( + const_cast(*this) ))), + _index_set, _index_set.size()); } constexpr const_reference operator[](int offset) const { - return *(dash::begin( + return *const_iterator( + dash::begin( dash::local( - dash::origin(*this) )) - + _index_set[offset]); + dash::origin(*this) )), + _index_set, offset); } reference operator[](int offset) { - return *(dash::begin( + return *iterator( + dash::begin( dash::local( - const_cast(dash::origin(*this)) - )) - + _index_set[offset]); + dash::origin( + const_cast(*this) ))), + _index_set, offset); } constexpr const local_type & local() const { @@ -531,7 +572,7 @@ class ViewLocalMod constexpr const index_set_type & index_set() const { return _index_set; } -}; +}; // ViewLocalMod // ------------------------------------------------------------------------ @@ -545,9 +586,7 @@ template < struct view_traits > { typedef DomainType domain_type; typedef typename view_traits::origin_type origin_type; - typedef typename view_traits::pattern_type pattern_type; typedef ViewSubMod image_type; -//typedef ViewSubMod local_type; typedef ViewLocalMod< ViewSubMod, NDim> local_type; typedef ViewSubMod global_type; @@ -559,8 +598,9 @@ struct view_traits > { typedef std::integral_constant is_projection; typedef std::integral_constant is_view; typedef std::integral_constant is_origin; - typedef std::integral_constant::is_local::value > is_local; + typedef typename view_traits::is_local is_local; + + typedef std::integral_constant is_contiguous; typedef std::integral_constant rank; }; @@ -621,7 +661,7 @@ class ViewSubMod domain_type && domain, index_type begin, index_type end) - : base_t(std::forward(domain)) + : base_t(std::move(domain)) , _index_set(this->domain(), begin, end) { } @@ -635,7 +675,7 @@ class ViewSubMod // ---- extents --------------------------------------------------------- - constexpr std::array extents() const { + constexpr decltype(_index_set.extents()) extents() const { return _index_set.extents(); } @@ -655,7 +695,7 @@ class ViewSubMod return _index_set.template offset(); } - constexpr std::array offsets() const { + constexpr decltype(_index_set.offsets()) offsets() const { return _index_set.offsets(); } @@ -679,8 +719,8 @@ class ViewSubMod iterator begin() { return iterator( - const_cast( - dash::origin(*this) + dash::origin( + const_cast(*this) ).begin(), _index_set, 0); } @@ -693,8 +733,8 @@ class ViewSubMod iterator end() { return iterator( - const_cast( - dash::origin(*this) + dash::origin( + const_cast(*this) ).begin(), _index_set, _index_set.size()); } @@ -705,8 +745,8 @@ class ViewSubMod } reference operator[](int offset) { - return *(iterator(const_cast( - dash::origin(*this) + return *(iterator(dash::origin( + const_cast(*this) ).begin(), _index_set, offset)); } diff --git a/dash/include/dash/view/ViewMod1D.h b/dash/include/dash/view/ViewMod1D.h index dc4859fa2..9f7cae81e 100644 --- a/dash/include/dash/view/ViewMod1D.h +++ b/dash/include/dash/view/ViewMod1D.h @@ -2,7 +2,6 @@ #define DASH__VIEW__VIEW_MOD_1D_H__INCLUDED #include -#include #include #include @@ -18,67 +17,66 @@ #include #include +#include namespace dash { -#ifndef DOXYGEN -// ------------------------------------------------------------------------ -// ViewSubMod -// ------------------------------------------------------------------------ +template +class IndexSetBase; -template < - class DomainType, - dim_t SubDim > -struct view_traits > { - typedef DomainType domain_type; - typedef typename view_traits::origin_type origin_type; - typedef typename view_traits::pattern_type pattern_type; - typedef ViewSubMod image_type; -//typedef ViewSubMod local_type; - typedef ViewLocalMod< - ViewSubMod, 1> local_type; - typedef ViewSubMod global_type; - - typedef typename DomainType::index_type index_type; - typedef typename DomainType::size_type size_type; - typedef dash::IndexSetSub index_set_type; - - typedef std::integral_constant is_projection; - typedef std::integral_constant is_view; - typedef std::integral_constant is_origin; - - typedef std::integral_constant::is_local::value > is_local; - - typedef std::integral_constant rank; -}; +template +class IndexSetIdentity; + +template +class IndexSetLocal; + +template +class IndexSetGlobal; + +template +class IndexSetSub; + +template +class IteratorRange; + +template +class IteratorRangeOrigin; + +template +class IteratorRangeOrigin; + + +#ifndef DOXYGEN +// ----------------------------------------------------------------------- +// ViewSubMod +// ----------------------------------------------------------------------- template < class DomainType, dim_t SubDim > class ViewSubMod : public ViewModBase< - ViewSubMod, - DomainType > -{ + ViewSubMod, DomainType, 1 + > { public: - typedef DomainType domain_type; + typedef DomainType domain_type; private: - typedef ViewSubMod self_t; - typedef ViewModBase< ViewSubMod, domain_type > base_t; + typedef ViewSubMod self_t; + typedef ViewModBase< + ViewSubMod, domain_type > base_t; public: - typedef typename base_t::origin_type origin_type; + typedef typename base_t::origin_type origin_type; - typedef typename view_traits::index_type index_type; - typedef typename view_traits::size_type size_type; + typedef typename view_traits::index_type index_type; + typedef typename view_traits::size_type size_type; public: - typedef dash::IndexSetSub index_set_type; - typedef ViewLocalMod local_type; - typedef self_t global_type; + typedef dash::IndexSetSub index_set_type; + typedef dash::ViewLocalMod local_type; + typedef self_t global_type; - typedef std::integral_constant is_local; + typedef std::integral_constant is_local; typedef ViewIterator< typename base_t::origin_iterator, index_set_type > @@ -102,17 +100,17 @@ class ViewSubMod self_t & operator=(const self_t &) = default; constexpr ViewSubMod( - domain_type && domain, + DomainType && domain, index_type begin, index_type end) - : base_t(std::forward(domain)) + : base_t(std::move(domain)) , _index_set(this->domain(), begin, end) { } constexpr ViewSubMod( - const domain_type & domain, - index_type begin, - index_type end) + const domain_type & domain, + index_type begin, + index_type end) : base_t(domain) , _index_set(domain, begin, end) { } @@ -131,14 +129,14 @@ class ViewSubMod constexpr const_iterator end() const { return const_iterator(dash::origin(*this).begin(), - _index_set, _index_set.size()); + _index_set, _index_set.size() - 1) + 1; } iterator end() { return iterator(const_cast( dash::origin(*this) ).begin(), - _index_set, _index_set.size()); + _index_set, _index_set.size() - 1) + 1; } constexpr const_reference operator[](int offset) const { @@ -157,37 +155,27 @@ class ViewSubMod return _index_set; } - constexpr local_type local() const { + constexpr const local_type local() const { + return local_type(*this); + } + + local_type local() { return local_type(*this); } + + constexpr const self_t & global() const { + return *this; + } + + self_t & global() { + return *this; + } }; // class ViewSubMod -// ------------------------------------------------------------------------ +// ----------------------------------------------------------------------- // ViewLocalMod -// ------------------------------------------------------------------------ - -template < - class DomainType > -struct view_traits > { - typedef DomainType domain_type; - typedef typename view_traits::origin_type origin_type; - typedef typename view_traits::pattern_type pattern_type; - typedef typename domain_type::local_type image_type; - typedef ViewLocalMod local_type; - typedef domain_type global_type; - - typedef typename view_traits::index_type index_type; - typedef typename view_traits::size_type size_type; - typedef dash::IndexSetLocal index_set_type; - - typedef std::integral_constant is_projection; - typedef std::integral_constant is_view; - typedef std::integral_constant is_origin; - typedef std::integral_constant is_local; - - typedef std::integral_constant rank; -}; +// ----------------------------------------------------------------------- template < class DomainType > @@ -196,21 +184,21 @@ class ViewLocalMod ViewLocalMod, DomainType > { public: - typedef DomainType domain_type; - typedef typename view_traits::origin_type origin_type; - typedef typename domain_type::local_type image_type; - typedef typename domain_type::index_type index_type; - typedef typename domain_type::size_type size_type; + typedef DomainType domain_type; + typedef typename view_traits::origin_type origin_type; + typedef typename view_traits::local_type image_type; + typedef typename domain_type::index_type index_type; + typedef typename domain_type::size_type size_type; private: - typedef ViewLocalMod self_t; + typedef ViewLocalMod self_t; typedef ViewModBase< - ViewLocalMod, DomainType, 1 > base_t; + ViewLocalMod, DomainType > base_t; public: - typedef dash::IndexSetLocal index_set_type; - typedef self_t local_type; - typedef typename domain_type::global_type global_type; + typedef dash::IndexSetLocal index_set_type; + typedef self_t local_type; + typedef typename domain_type::global_type global_type; - typedef std::integral_constant is_local; + typedef std::integral_constant is_local; typedef decltype( @@ -226,7 +214,8 @@ class ViewLocalMod dash::begin( dash::local(dash::origin( std::declval< - typename std::add_lvalue_reference::type >() + typename std::add_lvalue_reference< + const domain_type>::type >() )))) const_iterator; @@ -244,7 +233,8 @@ class ViewLocalMod *(dash::begin( dash::local(dash::origin( std::declval< - typename std::add_lvalue_reference::type >() + typename std::add_lvalue_reference< + const domain_type>::type >() ))))) const_reference; @@ -263,7 +253,7 @@ class ViewLocalMod */ constexpr explicit ViewLocalMod( domain_type && domain) - : base_t(std::forward(domain)) + : base_t(std::move(domain)) , _index_set(this->domain()) { } @@ -345,52 +335,30 @@ class ViewLocalMod }; // class ViewLocalMod -// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------- // ViewGlobalMod -// ------------------------------------------------------------------------ - -template < - class DomainType > -struct view_traits > { - typedef DomainType domain_type; - typedef typename view_traits::origin_type origin_type; - typedef typename view_traits::pattern_type pattern_type; - typedef typename domain_type::global_type image_type; - typedef typename domain_type::local_type local_type; - typedef ViewGlobalMod global_type; - - typedef typename DomainType::index_type index_type; - typedef typename DomainType::size_type size_type; - typedef dash::IndexSetLocal< DomainType > index_set_type; - - typedef std::integral_constant is_projection; - typedef std::integral_constant is_view; - typedef std::integral_constant is_origin; - typedef std::integral_constant is_local; - - typedef std::integral_constant rank; -}; +// ------------------------------------------------------------------------- template < class DomainType > class ViewGlobalMod : public ViewModBase< ViewGlobalMod, DomainType > { public: - typedef DomainType domain_type; + typedef DomainType domain_type; private: - typedef ViewGlobalMod self_t; - typedef ViewModBase< ViewLocalMod, DomainType > base_t; + typedef ViewGlobalMod self_t; + typedef ViewModBase< ViewLocalMod, DomainType > base_t; public: - typedef typename base_t::origin_type origin_type; - typedef typename domain_type::global_type image_type; - typedef typename view_traits::index_type index_type; - typedef typename view_traits::size_type size_type; + typedef typename base_t::origin_type origin_type; + typedef typename domain_type::global_type image_type; + typedef typename view_traits::index_type index_type; + typedef typename view_traits::size_type size_type; public: - typedef dash::IndexSetGlobal< DomainType > index_set_type; - typedef self_t global_type; - typedef typename domain_type::local_type local_type; + typedef dash::IndexSetGlobal< DomainType > index_set_type; + typedef self_t global_type; + typedef typename domain_type::local_type local_type; - typedef std::integral_constant is_local; + typedef std::integral_constant is_local; private: index_set_type _index_set; @@ -407,7 +375,7 @@ class ViewGlobalMod */ constexpr explicit ViewGlobalMod( domain_type && domain) - : base_t(std::forward(domain)) + : base_t(std::move(domain)) , _index_set(this->domain()) { } @@ -468,8 +436,1097 @@ class ViewGlobalMod } }; // class ViewGlobalMod + + +// ======================================================================= +// +// Iterator Range Interface +// +// ======================================================================= + +template < + class Iterator, + class Sentinel > +class IteratorRangeLocalOrigin; + +template < + class Iterator, + class Sentinel > +class IteratorRangeOrigin; + +template +class IteratorRangeViewDomain; + +template +class IteratorRange; + +// ----------------------------------------------------------------------- +// Iterator Range Local Origin +// +// Concept adapter for iterator range +// +// local(range(Container.iter, +// Container.iter) +// = +// range(Container.local.iter, +// Container.local.iter) +// +// to semantics of Container.local type. +// +// ----------------------------------------------------------------------- + +template < + class Iterator, + class Sentinel > +struct view_traits > { + private: + typedef IteratorRangeLocalOrigin RangeT; + public: + typedef IteratorRangeOrigin domain_type; + typedef IteratorRangeOrigin origin_type; + typedef RangeT image_type; + + typedef std::integral_constant rank; + + typedef RangeT local_type; + typedef IteratorRangeOrigin global_type; + + typedef typename Iterator::index_type index_type; + typedef typename std::make_unsigned::type size_type; + + typedef dash::IndexSetLocal index_set_type; + + typedef std::integral_constant is_projection; + typedef std::integral_constant is_view; + typedef std::integral_constant is_origin; + typedef std::integral_constant is_local; + + typedef std::integral_constant is_contiguous; +}; + +template < + class OriginIter, + class Sentinel > +class IteratorRangeLocalOrigin +: public ViewModBase< + IteratorRangeLocalOrigin, + IteratorRangeOrigin, + IteratorRangeOrigin::rank::value > +{ + // Do not depend on DomainType (IndexRangeOrigin): + // Use OriginIter, OriginSntl in template parameters to decouple + // cyclic type dependency. + typedef OriginIter g_origin_iterator; + typedef OriginIter const_g_origin_iterator; + + typedef IteratorRangeLocalOrigin self_t; + public: + typedef IteratorRangeOrigin domain_type; + typedef IteratorRangeOrigin origin_type; + typedef IteratorRangeLocalOrigin image_type; + private: + typedef ViewModBase< + self_t, + domain_type, + domain_type::rank::value > base_t; + typedef typename g_origin_iterator::pattern_type pattern_type; + public: + typedef typename g_origin_iterator::value_type value_type; + + typedef typename g_origin_iterator::index_type index_type; + typedef typename std::make_unsigned::type size_type; + + typedef std::integral_constant rank; + + typedef IndexSetLocal index_set_type; + + typedef std::integral_constant is_local; + + typedef typename g_origin_iterator::local_type + iterator; + typedef typename g_origin_iterator::local_type + const_iterator; + + typedef value_type & + reference; + typedef const value_type & + const_reference; + + typedef typename domain_type::global_type global_type; + typedef self_t local_type; + + private: + index_set_type _index_set; + + public: + constexpr explicit IteratorRangeLocalOrigin( + const IteratorRangeOrigin & range_origin) + : base_t(range_origin) + , _index_set(this->domain()) + { } + + constexpr const_iterator begin() const { + return dash::local( + dash::begin( + const_cast( + dash::domain(*this)) + ) + _index_set.pattern().global(0) + ) + _index_set[0]; + } + + iterator begin() { + return dash::local( + dash::begin( + const_cast( + dash::domain(*this)) + ) + _index_set.pattern().global(0) + ) + _index_set[0]; + } + + constexpr const_iterator end() const { + return dash::local( + dash::begin( + const_cast( + dash::domain(*this)) + ) + _index_set.pattern().global(0) + ) + _index_set[_index_set.size() - 1] + 1; + } + + iterator end() { + return dash::local( + dash::begin( + const_cast( + dash::domain(*this)) + ) + _index_set.pattern().global(0) + ) + _index_set[_index_set.size() - 1] + 1; + } + + constexpr const_reference operator[](int offset) const { + return *(dash::local( + dash::begin( + const_cast( + dash::domain(*this)) + ) + _index_set.pattern().global(0) + ) + _index_set[offset]); + } + + reference operator[](int offset) { + return *(dash::local( + dash::begin( + const_cast( + dash::domain(*this)) + ) + _index_set.pattern().global(0) + ) + _index_set[offset]); + } + + constexpr size_type size() const { return _index_set.size(); } + + constexpr const pattern_type & pattern() const { + return this->begin().pattern(); + } + + constexpr const index_set_type & index_set() const { + return _index_set; + } + + constexpr const local_type & local() const { + return *this; + } + + local_type & local() { + return *this; + } + + constexpr const global_type & global() const { + return dash::global(dash::domain(*this)); + } + + global_type & global() { + return dash::global(dash::domain(*this)); + } +}; // IteratorRangeLocalOrigin + +// ----------------------------------------------------------------------- +// Iterator Range Origin +// ----------------------------------------------------------------------- +// Concept adapter for iterator range +// +// range(Container.iter, Container.iter) +// +// to model of Container concept. +// ----------------------------------------------------------------------- + +namespace detail { + template < + class RangeType, + bool has_index_set = dash::detail::has_type_index_set_type< + typename std::decay< + typename RangeType::iterator>::type + >::value > + struct iterator_range_traits; + + template + struct iterator_range_traits { + typedef typename std::decay< + typename RangeType::iterator + >::type::index_set_type + index_set_type; + }; + + template + struct iterator_range_traits { + typedef dash::IndexSetIdentity + index_set_type; + }; +} // namespace detail + +template < + class RangeOrigin, + class IndexSet > +struct view_traits> { + private: + typedef IteratorRangeViewDomain RangeT; + typedef typename RangeOrigin::pattern_type PatternT; + typedef typename RangeOrigin::iterator iterator; + public: + typedef RangeOrigin domain_type; +//typedef RangeOrigin origin_type; + typedef typename dash::view_traits< + typename std::decay::type + >::origin_type origin_type; + typedef RangeT image_type; + + typedef IndexSet index_set_type; + + typedef std::integral_constant< + dim_t, static_cast(PatternT::ndim())> rank; + + typedef RangeT global_type; +//typedef ViewLocalMod local_type; + typedef ViewLocalMod local_type; + + typedef typename iterator::index_type index_type; + typedef typename std::make_unsigned::type size_type; + + typedef std::integral_constant is_projection; + typedef std::integral_constant is_view; + typedef std::integral_constant is_origin; + typedef std::integral_constant is_local; + + typedef typename view_traits::is_contiguous is_contiguous; +}; + + +template < + class RangeOrigin, + class IndexSet> +class IteratorRangeViewDomain +: public ViewModBase< + IteratorRangeViewDomain, + RangeOrigin > +{ + typedef IteratorRangeViewDomain self_t; + typedef ViewModBase< + IteratorRangeViewDomain, + RangeOrigin > base_t; + + public: + typedef RangeOrigin domain_type; +//typedef RangeOrigin origin_type; + typedef typename dash::view_traits< + typename std::decay::type + >::origin_type origin_type; + typedef self_t image_type; + + typedef IndexSet index_set_type; + + typedef typename domain_type::iterator iterator; + typedef typename domain_type::const_iterator const_iterator; + typedef typename domain_type::sentinel sentinel; + typedef typename domain_type::const_sentinel const_sentinel; + + typedef typename iterator::value_type value_type; + + typedef typename iterator::reference reference; + typedef typename iterator::const_reference const_reference; + + typedef typename iterator::index_type index_type; + typedef typename std::make_unsigned::type size_type; + + typedef typename iterator::pattern_type pattern_type; + typedef typename index_set_type::rank rank; + + typedef std::integral_constant is_local; + + typedef self_t global_type; + typedef ViewLocalMod local_type; + + private: + static const dim_t NDim = rank::value; + + // TODO: index_set_type should be IndexSetSub + index_set_type _index_set; + index_type _begin_idx; + index_type _end_idx; + + public: + constexpr explicit IteratorRangeViewDomain(const domain_type & dom) + : base_t(dom) + , _index_set(dom.begin().index_set()) + , _begin_idx(0) + , _end_idx(dom.begin().index_set().size()) + { } + + constexpr IteratorRangeViewDomain( + const iterator & begin, + const sentinel & end) + : base_t(domain_type( + begin, // - begin.pos(), + end)) // begin + (begin.pattern().size() - begin.pos()))) + , _index_set(begin.index_set()) + , _begin_idx(begin.pos()) + , _end_idx(end.pos()) + { } + + constexpr IteratorRangeViewDomain( + iterator && begin, + sentinel && end) + : base_t(domain_type( + std::move(begin), // - begin.pos(), + std::move(end))) + // std::move(begin) + (begin.pattern().size() - begin.pos()))) + , _index_set(begin.index_set()) + , _begin_idx(begin.pos()) + , _end_idx(end.pos()) + { } + + constexpr IteratorRangeViewDomain() = delete; + constexpr IteratorRangeViewDomain(const self_t & other) = default; + constexpr IteratorRangeViewDomain(self_t && other) = default; + self_t & operator=(const self_t & other) = default; + self_t & operator=(self_t && other) = default; + + // ---- extents --------------------------------------------------------- + + constexpr std::array extents() const { + return _index_set.extents(); + } + + template + constexpr size_type extent() const { + return _index_set.template extent(); + } + + constexpr size_type extent(dim_t shape_dim) const { + return _index_set.extent(shape_dim); + } + + // ---- offsets --------------------------------------------------------- + + template + constexpr index_type offset() const { + return _index_set.template offset(); + } + + constexpr std::array offsets() const { + return _index_set.offsets(); + } + + constexpr index_type offset(dim_t shape_dim) const { + return _index_set.offset(shape_dim); + } + + // ---- size ------------------------------------------------------------ + + constexpr size_type size(dim_t sub_dim = 0) const { + return _index_set.size(); + } + + // ---- access ---------------------------------------------------------- + +#if 0 + constexpr const_iterator begin() const { + return const_iterator( + dash::origin(*this).begin(), + _index_set, _begin_idx); + } + + iterator begin() { + return iterator( + dash::origin( + const_cast(*this) + ).begin(), + _index_set, _begin_idx); + } + + constexpr const_iterator end() const { + return const_iterator( + dash::origin(*this).begin(), + _index_set, _end_idx); + } + + iterator end() { + return iterator( + dash::origin( + const_cast(*this) + ).begin(), + _index_set, _end_idx); + } + + constexpr const_reference operator[](int offset) const { + return *(const_iterator(dash::origin(*this).begin(), + _index_set, offset)); + } + + reference operator[](int offset) { + return *(iterator(dash::origin( + const_cast(*this) + ).begin(), + _index_set, _begin_idx + offset)); + } +#else + constexpr const_iterator begin() const { + return dash::domain(*this).begin(); + } + + iterator begin() { + return dash::domain(*this).begin(); + } + + constexpr const_iterator end() const { + return dash::domain(*this).end(); + } + + iterator end() { + return dash::domain(*this).end(); + } + + constexpr const_reference operator[](int offset) const { + return *(this->begin() + offset); + } + + reference operator[](int offset) { + return *(this->begin() + offset); + } +#endif + + constexpr const pattern_type & pattern() const noexcept { + return this->begin().pattern(); + } + + constexpr local_type local() const noexcept { + return local_type(*this); + } + + constexpr const self_t & global() const { + return *this; + } + + self_t & global() { + return *this; + } + + constexpr const index_set_type & index_set() const { + return _index_set; + } +}; // IteratorRangeViewDomain + + +template < + class Iterator, + class Sentinel > +struct view_traits > { + private: + typedef IteratorRangeOrigin RangeT; + typedef typename Iterator::pattern_type PatternT; + public: + typedef IteratorRangeOrigin domain_type; + typedef IteratorRangeOrigin origin_type; + typedef IteratorRangeOrigin image_type; + + typedef std::integral_constant< + dim_t, static_cast(PatternT::ndim())> rank; + + typedef RangeT global_type; + typedef IteratorRangeLocalOrigin local_type; + + typedef typename Iterator::index_type index_type; + typedef typename std::make_unsigned::type size_type; + + typedef typename detail::iterator_range_traits::index_set_type + index_set_type; + + typedef std::integral_constant is_projection; + typedef std::integral_constant is_view; + typedef std::integral_constant is_origin; + typedef std::integral_constant is_local; + + typedef std::integral_constant is_contiguous; +}; + + +template < + class Iterator, + class Sentinel > +class IteratorRangeOrigin +{ + typedef IteratorRangeOrigin self_t; + + public: + typedef Iterator iterator; + typedef Iterator const_iterator; + typedef Sentinel sentinel; + typedef Sentinel const_sentinel; + + typedef IteratorRangeOrigin domain_type; + typedef IteratorRangeOrigin origin_type; + typedef IteratorRangeOrigin image_type; + + typedef typename iterator::value_type value_type; + + typedef typename iterator::reference reference; + typedef typename iterator::const_reference const_reference; + + typedef typename Iterator::index_type index_type; + typedef typename std::make_unsigned::type size_type; + + typedef typename Iterator::pattern_type pattern_type; + typedef std::integral_constant rank; + + typedef std::integral_constant is_local; + + typedef self_t global_type; + typedef IteratorRangeLocalOrigin local_type; + + private: + iterator _begin; + sentinel _end; + public: + constexpr IteratorRangeOrigin( + const iterator & begin, + const sentinel & end) + : _begin(begin) + , _end(end) + { } + + constexpr IteratorRangeOrigin( + iterator && begin, + sentinel && end) + : _begin(std::move(begin)) + , _end(std::move(end)) + { } + + constexpr IteratorRangeOrigin() = delete; + constexpr IteratorRangeOrigin(const self_t & other) = default; + constexpr IteratorRangeOrigin(self_t && other) = default; + self_t & operator=(const self_t & other) = default; + self_t & operator=(self_t && other) = default; + + constexpr const_iterator begin() const { return _begin; } + constexpr const_sentinel end() const { return _end; } + + iterator begin() { return _begin; } + sentinel end() { return _end; } + + constexpr const_reference operator[](int offset) const { + return *(this->begin() + offset); + } + + reference operator[](int offset) { + return *(this->begin() + offset); + } + + // TODO: Not well-defined, should be identical to extents size + // + constexpr size_type size() const noexcept { + return dash::distance(_begin, _end); + } + + constexpr const std::array extents() const { + return this->pattern().extents(); + } + + constexpr const pattern_type & pattern() const noexcept { + return this->begin().pattern(); + } + + constexpr local_type local() const noexcept { + return local_type(*this); + } + + constexpr const self_t & global() const { + return *this; + } + + self_t & global() { + return *this; + } +}; // IteratorRangeOrigin + +// ----------------------------------------------------------------------- +// Iterator Range Origin (local pointers) +// +// Concept adapter for iterator range +// +// local(range(Container.iter, +// Container.iter) +// = +// range(Container.local.iter, +// Container.local.iter) +// +// to semantics of Container.local type. +// +// ----------------------------------------------------------------------- + +#if 0 +template < + class LocalIterator, + class LocalSentinel, + class IndexSet > +struct view_traits< + IteratorRangeOrigin< + ViewIterator, + ViewIterator + > > { + private: + typedef ViewIterator iterator; + typedef ViewIterator sentinel; + + typedef IteratorRangeOrigin RangeT; + public: + typedef RangeT domain_type; + typedef RangeT origin_type; + typedef RangeT image_type; + + typedef std::integral_constant rank; + + typedef RangeT global_type; + typedef RangeT local_type; + + typedef typename iterator::index_type index_type; + typedef typename std::make_unsigned::type size_type; + + typedef dash::IndexSetIdentity< + IteratorRangeOrigin > index_set_type; + + typedef std::integral_constant is_projection; + typedef std::integral_constant is_view; + typedef std::integral_constant is_origin; + typedef std::integral_constant is_local; +}; + +template < + typename LocalIterator, + typename LocalSentinel, + typename IndexSet > +class IteratorRangeOrigin< + ViewIterator, + ViewIterator > +{ + typedef IteratorRangeOrigin< + ViewIterator, + ViewIterator > + self_t; + + public: + typedef ViewIterator iterator; + typedef ViewIterator sentinel; + typedef ViewIterator const_iterator; + typedef ViewIterator const_sentinel; + + typedef dash::default_index_t index_type; + typedef dash::default_size_t size_type; + + typedef LocalIterator value_type; + + typedef self_t global_type; + + typedef typename IndexSet::pattern_type pattern_type; + + typedef std::integral_constant is_local; + + typedef std::integral_constant rank; + + private: + iterator _begin; + sentinel _end; + + public: + constexpr IteratorRangeOrigin(iterator begin, sentinel end) + : _begin(begin) + , _end(end) + { } + + constexpr IteratorRangeOrigin() = delete; + constexpr IteratorRangeOrigin(const self_t & other) = default; + constexpr IteratorRangeOrigin(self_t && other) = default; + self_t & operator=(const self_t & other) = default; + self_t & operator=(self_t && other) = default; + + constexpr const_iterator begin() const { return _begin; } + constexpr const_sentinel end() const { return _end; } + + iterator begin() { return _begin; } + sentinel end() { return _end; } + + constexpr size_type size() const { + return dash::distance(_begin, _end); + } +}; +#else +template < + class LocalIterator, + class LocalSentinel > +struct view_traits< + IteratorRangeOrigin< + LocalIterator *, + LocalSentinel *> + > { + private: + typedef typename std::decay::type iterator; + typedef typename std::decay::type sentinel; + + typedef IteratorRangeOrigin RangeT; + public: + typedef RangeT domain_type; + typedef RangeT origin_type; + typedef RangeT image_type; + + typedef std::integral_constant rank; + + typedef RangeT global_type; + typedef RangeT local_type; + + typedef typename std::ptrdiff_t index_type; + typedef typename std::make_unsigned::type size_type; + + typedef dash::IndexSetIdentity< + IteratorRangeOrigin > index_set_type; + + typedef std::integral_constant is_projection; + typedef std::integral_constant is_view; + typedef std::integral_constant is_origin; + typedef std::integral_constant is_local; + + typedef std::integral_constant is_contiguous; +}; + +template < + typename LocalIterator, + typename LocalSentinel > +class IteratorRangeOrigin< + LocalIterator *, + LocalSentinel * > +{ + typedef IteratorRangeOrigin< + LocalIterator *, + LocalSentinel * > + self_t; + + public: + typedef typename std::decay< LocalIterator *>::type iterator; + typedef typename std::decay::type const_iterator; + typedef typename std::decay< LocalSentinel *>::type sentinel; + typedef typename std::decay::type const_sentinel; + + typedef dash::default_index_t index_type; + typedef dash::default_size_t size_type; + + typedef typename std::decay::type value_type; + + typedef self_t global_type; + + typedef std::integral_constant is_local; + + typedef std::integral_constant rank; + + private: + iterator _begin; + sentinel _end; + + public: + constexpr IteratorRangeOrigin(iterator begin, sentinel end) + : _begin(begin) + , _end(end) + { } + + constexpr IteratorRangeOrigin() = delete; + constexpr IteratorRangeOrigin(const self_t & other) = default; + constexpr IteratorRangeOrigin(self_t && other) = default; + self_t & operator=(const self_t & other) = default; + self_t & operator=(self_t && other) = default; + + constexpr const_iterator begin() const { return _begin; } + constexpr const_sentinel end() const { return _end; } + + iterator begin() { return _begin; } + sentinel end() { return _end; } + + constexpr size_type size() const { + return dash::distance(_begin, _end); + } +}; // IteratorRangeOrigin +#endif + +// ---------------------------------------------------------------------- +// Iterator Range +// ---------------------------------------------------------------------- + +/** + * Specialization of \c dash::view_traits for IteratorRange. + */ +template +struct view_traits > { + private: + typedef IteratorRange RangeT; + public: + typedef RangeOrigin domain_type; +//typedef RangeOrigin origin_type; + typedef typename dash::view_traits< + typename std::decay::type + >::origin_type origin_type; + typedef RangeT image_type; + + typedef std::integral_constant rank; + + typedef RangeT global_type; + typedef ViewLocalMod local_type; + + typedef typename RangeT::index_type index_type; + typedef typename RangeT::size_type size_type; + + typedef dash::IndexSetSub index_set_type; + + typedef std::integral_constant is_projection; + typedef std::integral_constant is_view; + typedef std::integral_constant is_origin; + typedef typename view_traits< + typename std::decay::type + >::is_local is_local; + + typedef typename view_traits< + typename std::decay::type + >::is_contiguous is_contiguous; +}; + +/** + * Adapter template for range concept, wraps `begin` and `end` iterators + * in range type. + */ +template +class IteratorRange +: public ViewModBase< + IteratorRange, + RangeOrigin > +{ + typedef IteratorRange + self_t; + typedef ViewModBase, RangeOrigin> + base_t; + public: + typedef typename RangeOrigin::iterator iterator; + typedef typename RangeOrigin::const_iterator const_iterator; + typedef typename RangeOrigin::sentinel sentinel; + typedef typename RangeOrigin::const_sentinel const_sentinel; + + typedef RangeOrigin domain_type; + typedef typename dash::view_traits< + typename std::decay::type + >::origin_type origin_type; + typedef self_t image_type; + + typedef typename domain_type::value_type value_type; + + typedef typename dash::view_traits< + typename std::decay::type + >::rank rank; + + typedef self_t global_type; + typedef ViewLocalMod local_type; + + typedef typename view_traits< + typename std::decay::type + >::is_local is_local; + + typedef dash::default_index_t index_type; + typedef dash::default_size_t size_type; + + typedef dash::IndexSetSub index_set_type; + + using reference = + typename std::iterator_traits< iterator>::reference; + using const_reference = + typename std::iterator_traits::reference; + + private: + static const dim_t NDim = rank::value; + index_set_type _index_set; + + public: + constexpr IteratorRange(const iterator & begin, const sentinel & end) + : base_t(domain_type( + // Move begin iterator first position of its iteration scope: + begin - begin.pos(), + // Move end iterator to end position of its iteration scope: + // begin + (begin.pattern().size() - begin.pos()) + end + )) + // Convert iterator positions to sub-range index set: + , _index_set(this->domain(), begin.pos(), end.pos()) + { } + + constexpr IteratorRange(iterator && begin, sentinel && end) + : base_t(domain_type( + // Move begin iterator first position of its iteration scope: + std::move(begin) - begin.pos(), + // Move end iterator to end position of its iteration scope: + // std::move(begin) + (begin.pattern().size() - begin.pos()) + std::move(end) + )) + // Convert iterator positions to sub-range index set: + , _index_set(this->domain(), begin.pos(), end.pos()) + { } + + constexpr IteratorRange() = delete; + constexpr IteratorRange(const self_t & other) = default; + constexpr IteratorRange(self_t && other) = default; + self_t & operator=(const self_t & other) = default; + self_t & operator=(self_t && other) = default; + + // ---- extents ------------------------------------------------------- + + constexpr decltype(_index_set.extents()) extents() const { + return _index_set.extents(); + } + + template + constexpr size_type extent() const { + return _index_set.template extent(); + } + + constexpr size_type extent(dim_t shape_dim) const { + return _index_set.extent(shape_dim); + } + + // ---- offsets ------------------------------------------------------- + + template + constexpr index_type offset() const { + return _index_set.template offset(); + } + + constexpr decltype(_index_set.offsets()) offsets() const { + return _index_set.offsets(); + } + + constexpr index_type offset(dim_t shape_dim) const { + return _index_set.offset(shape_dim); + } + + // ---- size ---------------------------------------------------------- + + constexpr size_type size(dim_t sub_dim = 0) const { + return _index_set.size(sub_dim); + } + + // ---- access -------------------------------------------------------- + + constexpr const_iterator begin() const { + return dash::domain(*this).begin() + _index_set[0]; + } + + iterator begin() { + return dash::domain(*this).begin() + _index_set[0]; + } + + constexpr const_iterator end() const { + return dash::domain(*this).begin() + + (_index_set[_index_set.size() - 1] + 1); + } + + iterator end() { + return dash::domain(*this).begin() + + (_index_set[_index_set.size() - 1] + 1); + } + + constexpr const_reference operator[](int offset) const { + return *(dash::domain(*this).begin() + _index_set[offset]); + } + + reference operator[](int offset) { + return *(dash::domain(*this).begin() + _index_set[offset]); + } + + constexpr const index_set_type & index_set() const { + return _index_set; + } + + constexpr const local_type local() const { + return local_type(*this); + } + + local_type local() { + return local_type(*this); + } + + constexpr const self_t & global() const { + return *this; + } + + self_t & global() { + return *this; + } +}; // IteratorRange + #endif // DOXYGEN +// ----------------------------------------------------------------------- +// dash::make_range +// ----------------------------------------------------------------------- + +template +constexpr + typename std::enable_if< + !dash::detail::has_type_index_set_type::value, + dash::IteratorRange< + dash::IteratorRangeOrigin< + typename std::decay::type, + typename std::decay::type > > + >::type +make_range(Iterator && begin, Sentinel && end) { + return dash::IteratorRange< + dash::IteratorRangeOrigin< + typename std::decay::type, + typename std::decay::type > + >(std::forward(begin), + std::forward(end)); +} + +template +constexpr + typename std::enable_if< + dash::detail::has_type_index_set_type::value, + // dash::IteratorRange< + dash::IteratorRangeViewDomain< + dash::IteratorRangeOrigin< + typename std::decay::type, + typename std::decay::type >, + typename std::decay::type::index_set_type > + // > + >::type +make_range(Iterator && begin, Sentinel && end) { + // begin, end are view iterators: + return // dash::IteratorRange< + dash::IteratorRangeViewDomain< + dash::IteratorRangeOrigin< + typename std::decay::type, + typename std::decay::type >, + typename std::decay::type::index_set_type > + // > + (std::forward(begin), + std::forward(end)); +} + } // namespace dash #endif // DASH__VIEW__VIEW_MOD_1D_H__INCLUDED diff --git a/dash/include/dash/view/ViewOrigin.h b/dash/include/dash/view/ViewOrigin.h index 88d965ce2..f4f22531b 100644 --- a/dash/include/dash/view/ViewOrigin.h +++ b/dash/include/dash/view/ViewOrigin.h @@ -1,14 +1,13 @@ #ifndef DASH__VIEW__VIEW_ORIGIN_H__INCLUDED #define DASH__VIEW__VIEW_ORIGIN_H__INCLUDED +#include +#include + #include #include #include -#include -#include -#include - namespace dash { diff --git a/dash/include/dash/view/ViewSpec.h b/dash/include/dash/view/ViewSpec.h new file mode 100644 index 000000000..84ca82c3e --- /dev/null +++ b/dash/include/dash/view/ViewSpec.h @@ -0,0 +1,442 @@ +#ifndef DASH__VIEW__VIEW_SPEC_H__INCLUDED +#define DASH__VIEW__VIEW_SPEC_H__INCLUDED + +#include + +#include + + +namespace dash { + +/** + * Offset and extent in a single dimension. + */ +template +struct ViewPair { + typedef typename std::make_unsigned::type SizeType; + /// Offset in dimension. + IndexType offset; + /// Extent in dimension. + SizeType extent; +}; + +/** + * Representation of a ViewPair as region specified by origin and end + * coordinates. + */ +template< + dim_t NDim, + typename IndexType = dash::default_index_t> +struct ViewRegion { + // Region origin coordinates. + std::array begin; + // Region end coordinates. + std::array end; +}; + +template< + typename IndexType = dash::default_index_t> +struct ViewRange { + // Range begin offset. + IndexType begin; + // Range end offset. + IndexType end; +}; + +template +std::ostream & operator<<( + std::ostream & os, + const ViewRange & viewrange) { + os << "dash::ViewRange<" << typeid(IndexType).name() << ">(" + << "begin:" << viewrange.begin << " " + << "end:" << viewrange.end << ")"; + return os; +} + +/** + * Equality comparison operator for ViewPair. + */ +template +static bool operator==( + const ViewPair & lhs, + const ViewPair & rhs) { + if (&lhs == &rhs) { + return true; + } + return ( + lhs.offset == rhs.offset && + lhs.extent == rhs.extent); +} + +/** + * Inequality comparison operator for ViewPair. + */ +template +static bool operator!=( + const ViewPair & lhs, + const ViewPair & rhs) { + return !(lhs == rhs); +} + +template +std::ostream & operator<<( + std::ostream & os, + const ViewPair & viewpair) { + os << "dash::ViewPair<" << typeid(IndexType).name() << ">(" + << "offset:" << viewpair.offset << " " + << "extent:" << viewpair.extent << ")"; + return os; +} + +/** + * Specifies view parameters for implementing submat, rows and cols + * + * TODO: Should be specified as + * ViewSpec(begin Point { 0, 2, 3 }, + * end Point { 4, 7, 9 }) + * -> offset(d) = begin(d) + * extent(d) = end(d) - begin(d) + * + * + * \concept(DashCartesianSpaceConcept) + */ +template< + dim_t NDim, + typename IndexType = dash::default_index_t > +class ViewSpec +{ +private: + typedef ViewSpec + self_t; + typedef ViewPair + ViewPair_t; + +public: + typedef IndexType index_type; + typedef typename std::make_unsigned::type size_type; + typedef ViewRegion region_type; + typedef ViewRange range_type; + + typedef std::integral_constant rank; + +public: + template + friend std::ostream& operator<<( + std::ostream & os, + const ViewSpec & viewspec); + +private: + size_type _size = 0; + size_type _rank = NDim; + std::array _extents = {{ }}; + std::array _offsets = {{ }}; + +public: + /** + * Default constructor, initialize with extent and offset 0 in all + * dimensions. + */ + ViewSpec() + : _size(0), + _rank(NDim) + { + for (dim_t i = 0; i < NDim; i++) { + _extents[i] = 0; + _offsets[i] = 0; + } + } + + /** + * Constructor, initialize with given extents and offset 0 in all + * dimensions. + */ + ViewSpec( + const std::array & extents) + : _size(1), + _rank(NDim), + _extents(extents) + { + for (auto i = 0; i < NDim; ++i) { + _offsets[i] = 0; + _size *= _extents[i]; + } + } + + /** + * Constructor, initialize with given extents and offsets. + */ + ViewSpec( + const std::array & offsets, + const std::array & extents) + : _size(1), + _rank(NDim), + _extents(extents), + _offsets(offsets) + { + for (auto i = 0; i < NDim; ++i) { + _size *= _extents[i]; + } + } + + /** + * Copy constructor. + */ + constexpr ViewSpec(const self_t & other) = default; + + /** + * Move constructor. + */ + constexpr ViewSpec(self_t && other) = default; + + /** + * Assignment operator. + */ + self_t & operator=(const self_t & other) = default; + + /** + * Move-assignment operator. + */ + self_t & operator=(self_t && other) = default; + + /** + * Equality comparison operator. + */ + constexpr bool operator==(const self_t & other) const + { + return (_extents == other._extents && + _offsets == other._offsets && + _rank == other._rank); + } + + /** + * Equality comparison operator. + */ + constexpr bool operator!=(const self_t & other) const + { + return !(*this == other); + } + + /** + * Change the view specification's extent in every dimension. + */ + template + void resize(size_type arg, Args... args) + { + static_assert( + sizeof...(Args) == (NDim-1), + "Invalid number of arguments"); + std::array extents = + { arg, (size_type)(args)... }; + resize(extents); + } + + /** + * Change the view specification's extent and offset in every dimension. + */ + void resize(const std::array & view) + { + _rank = NDim; + for (dim_t i = 0; i < NDim; i++) { + _offsets[i] = view[i].offset; + _extents[i] = view[i].extent; + } + update_size(); + } + + /** + * Change the view specification's extent in every dimension. + */ + template + void resize(const std::array & extents) + { + _rank = NDim; + for (dim_t i = 0; i < NDim; i++) { + _extents[i] = extents[i]; + } + update_size(); + } + + /** + * Change the view specification's extent and offset in the + * given dimension. + */ + void resize_dim( + dim_t dimension, + index_type offset, + size_type extent) + { + _offsets[dimension] = offset; + _extents[dimension] = extent; + update_size(); + } + + /** + * Slice the view in the specified dimension at the given offset. + * This is different from resizing the dimension to extent 1 + * (\c resize_dim) which does not affect the view dimensionality or + * rank. + * Slicing removes the specified dimension and reduces the view + * dimensionality by 1. + * + * All dimensions higher than the sliced dimension are projected + * downwards. + * Example: + * + * dimensions: 0 1 2 3 + * : : : : + * extents: 3 4 5 6 + * | + * slice_dim(1, 2) + * | + * v + * dimensions: 0 x 1 2 + * : : : + * extents: 3 5 6 + * + * \return A copy if this view spec as a new instance of `ViewSpec` + * with the sliced dimension removed + */ + ViewSpec + slice(dim_t dimension) + { + std::array slice_extents; + std::array slice_offsets; + for (dim_t d = dimension; d < _rank-1; d++) { + slice_offsets[d] = _offsets[d+1]; + slice_extents[d] = _extents[d+1]; + } + return ViewSpec(slice_offsets, + slice_extents); + } + + /** + * Set rank of the view spec to a dimensionality between 1 and + * \c NDim. + */ + void set_rank(dim_t dimensions) + { + DASH_ASSERT_LT( + dimensions, NDim+1, + "Maximum dimension for ViewSpec::set_rank is " << NDim); + _rank = dimensions; + update_size(); + } + + constexpr size_type size() const + { + return _size; + } + + constexpr size_type size(dim_t dimension) const + { + return _extents[dimension]; + } + + constexpr const std::array & extents() const + { + return _extents; + } + + constexpr size_type extent(dim_t dim) const { + return _extents[dim]; + } + + constexpr const std::array & offsets() const { + return _offsets; + } + + constexpr index_type offset(dim_t dim) const { + return _offsets[dim]; + } + + constexpr range_type range(dim_t dim) const { + return range_type { + static_cast(_offsets[dim]), + static_cast(_offsets[dim] + _extents[dim]) }; + } + + region_type region() const + { + region_type reg; + reg.begin = _offsets; + reg.end = _offsets; + for (dim_t d = 0; d < NDim; ++d) { + reg.end[d] += static_cast(_extents[d]); + } + return reg; + } + + template + self_t intersect(const ViewSpec & other) { + // TODO: Implement using dash::ce::map(extents(), other.extents()) ... + auto isc_extents = extents(); + auto isc_offsets = offsets(); + for (dim_t d = 0; d < NDim_; ++d) { + auto offset_d = std::max(isc_offsets[d], other.offsets()[d]); + isc_extents[d] = std::min(isc_offsets[d] + isc_extents[d], + other.offset(d) + other.extent(d)) + - offset_d; + isc_offsets[d] = offset_d; + } + return self_t(isc_offsets, isc_extents); + } + +private: + void update_size() + { + _size = 1; + for (size_type d = 0; d < NDim; ++d) { + _size *= _extents[d]; + } + } +}; + + +template +struct is_view_region; + +template < + dim_t NDim, + typename IndexT > +struct is_view_region > +: std::integral_constant +{ }; + +template +struct rank; + +template < + dim_t NDim, + typename IndexT > +struct rank > +: std::integral_constant +{ }; + +template +std::ostream& operator<<( + std::ostream & os, + const ViewSpec & viewspec) +{ + std::ostringstream ss; + ss << "dash::ViewSpec<" << NDim << ">" + << "(offsets:"; + for (auto d = 0; d < NDim; ++d) { + if (d > 0) { + ss << ","; + } + ss << viewspec.offsets()[d]; + } + ss << " extents:"; + for (auto d = 0; d < NDim; ++d) { + if (d > 0) { + ss << ","; + } + ss << viewspec.extents()[d]; + } + ss << ")"; + return operator<<(os, ss.str()); +} + +} // namespace dash + +#endif // DASH__VIEW__VIEW_SPEC_H__INCLUDED diff --git a/dash/include/dash/view/ViewTraits.h b/dash/include/dash/view/ViewTraits.h index 248fe5a99..c1580e4b1 100644 --- a/dash/include/dash/view/ViewTraits.h +++ b/dash/include/dash/view/ViewTraits.h @@ -30,22 +30,35 @@ domain(const Viewable & v); template struct view_traits { - typedef typename ViewT::domain_type domain_type; - typedef typename ViewT::image_type image_type; - typedef typename ViewT::origin_type origin_type; - typedef typename ViewT::local_type local_type; - typedef typename ViewT::global_type global_type; + typedef typename ViewT::domain_type domain_type; + typedef typename ViewT::image_type image_type; + typedef typename ViewT::origin_type origin_type; + typedef typename ViewT::local_type local_type; + typedef typename ViewT::global_type global_type; + + typedef typename ViewT::index_set_type index_set_type; typedef std::integral_constant rank; typedef std::integral_constant is_origin; typedef std::integral_constant is_view; typedef std::integral_constant is_projection; + typedef std::integral_constant is_local; + + typedef std::integral_constant is_contiguous; }; #else // DOXYGEN +template +struct rank; + +template +struct rank +: std::integral_constant::type::rank::value> +{ }; + template struct view_traits; @@ -58,7 +71,6 @@ namespace detail { * with static member \c value indicating whether type \c T provides * dependent type \c domain_type. */ - DASH__META__DEFINE_TRAIT__HAS_TYPE(domain_type) DASH__META__DEFINE_TRAIT__HAS_TYPE(index_set_type) } @@ -72,6 +84,33 @@ template struct is_view : dash::detail::has_type_index_set_type { }; +template +struct is_view_region; + +template +struct is_view_region +: std::integral_constant< + bool, + dash::is_view::value> +{ }; + +template +struct is_local_view +: std::integral_constant< + bool, + ( dash::is_view::value && + dash::view_traits::is_local::value ) > +{ }; + +template +struct is_global_view +: std::integral_constant< + bool, + ( dash::is_view::value && + !dash::view_traits::is_local::value ) > +{ }; + + namespace detail { @@ -95,8 +134,7 @@ namespace detail { { typedef std::integral_constant is_projection; typedef std::integral_constant is_view; - /// Whether the view is the origin domain. - typedef std::integral_constant is_origin; + typedef std::integral_constant is_origin; typedef typename ViewT::index_type index_type; typedef typename ViewT::size_type size_type; @@ -111,6 +149,8 @@ namespace detail { dash::is_range::value >::is_local::value > is_local; + typedef std::integral_constant is_contiguous; + typedef typename ViewT::local_type local_type; typedef typename ViewT::global_type global_type; typedef typename std::conditional::type image_type; typedef typename dash::view_traits::origin_type origin_type; - typedef std::integral_constant rank; - - typedef typename dash::view_traits::pattern_type - pattern_type; + typedef dash::rank rank; }; /** @@ -143,8 +180,6 @@ namespace detail { typedef typename ContainerT::size_type size_type; typedef typename dash::IndexSetIdentity index_set_type; - typedef typename ContainerT::pattern_type pattern_type; - /// Whether the view type is a projection (has less dimensions than the /// view's domain type). typedef std::integral_constant is_projection; @@ -156,9 +191,11 @@ namespace detail { /// \c local_type typedef std::integral_constant::value > is_local; + typedef std::integral_constant is_contiguous; + typedef std::integral_constant rank; }; @@ -172,9 +209,9 @@ namespace detail { template struct view_traits : detail::_view_traits< - ViewableType, - dash::is_view::value, - dash::is_range::value > { + typename std::decay::type, + dash::is_view< typename std::decay::type>::value, + dash::is_range::type>::value > { }; #endif // DOXYGEN diff --git a/dash/test/PatternExprTest.cc b/dash/test/PatternExprTest.cc new file mode 100644 index 000000000..46270039b --- /dev/null +++ b/dash/test/PatternExprTest.cc @@ -0,0 +1,179 @@ + +#include + +#include +#include + +/* + * General findings and assumptions: + * + * 0) Patterns are domain-specific views and may differ from view + * expressions in: + * - design criteria + * - semantics + * - valid expressions (= algebra) + * + * Therefore, for example: + * - nviews do not depend on anything but the existence of a + * canonical index space (d'uh) + * - patterns are restricted to specific mapping + * signatures (smarter but less generic than nviews) and depend + * on concrete concepts such as Unit, Team, Locality, ... + * + * !! nviews are a pure-mathematical concoction, patterns are + * abstract algorithmic building blocks. + * + * + * I) Conceptional differences between nviews and pattern views: + * -- nview operations first and foremost must provide a zero-cost + * operation abstraction + * ( -> efficient to pipe, pass, invoke, confabulate, mogrify) + * + * some_origin | foo() | bar() | index() + * ... should not copy a darn thing. + * + * !! this is not a priority for patterns: + * - pattern instantiation may be "expensive" compared to views + * - pattern dereferentiation aka index access like + * + * pattern | global(34) | local() + * or + * pattern | global(34) | unit() + * + * - pattern expression modifiers (global, local, unit_at, ...) + * possibly have different semantics than view modifiers of + * the same name (but please should not). + * + * + * + * + * C) Advantages from switching to Pattern Views: + * + * -- With status quo pattern (class template) definitions, domain + * decomposition specified by a pattern object is immutable after + * its instantiation + * >> With pattern views, data space mappings can be modified just like + * nviews + * + * + * N) Some Wisenheimer words: + * + * - index: some numeric reference (scalar or n-dim point) to an + * element position + * - offset: a scalar index + * - point: an n-dim index + * + */ + + + +/*------------------------------------------------------------------------- + * pattern/PatternExpressionDefs.h + * + * + * Want: + * + * template< + * dim_t NumDimensions, + * MemArrange Arrangement = ROW_MAJOR, + * typename IndexType = dash::default_index_t + * > + * using BlockPattern = decltype(view_expr); + * + * template <...> + * struct pattern_mapping_properties { + * typedef pattern_mapping_properties< + * // Number of blocks assigned to a unit may differ. + * pattern_mapping_tag::unbalanced + * > mapping_properties; + * } + * + */ + +TEST_T(PatternExprTest, BlockCyclicPatternExpression) +{ + BlockPattern<1, dash::ROW_MAJOR, ssize_t> block_pat( + nlocal * nunits, + dash::DistributionSpec<1>(dash::BLOCKED)); + + dash::Array array(nlocal * nunits); + + // + +} + + + +/*-- snip ---------------------------------------------------------------- */ + + +// Need adapter from current pattern constructor interface to view +// expressions +BlockPattern(size_spec, dist_spec, team) +{ +//> size_spec: 100 * nunits +//> dist_spec: dash::BLOCKED + + // View object configured without any modifiers, comparable to + // dash::origin or dash::identity: + // + auto pat_id = make_pattern_id_view(size_spec); + + // mapping signatures: + // + // (1,2) + // + // gidx <--> (uidx, lidx) + // gidx <--> goffs + // ... + // Xidx <--> Xoffs + // + // ... with X as model of one of: + // + // - block index + // - element index + // - unit index + // ... + // whatev + // + // - Chaining mappings of X* index spaces allow for hierarchical + // patterns: + // + // global space block space sub-block space ... + // (Aidx, uidx) -> (Bidx, uidx) -> (Pidx, Bidx) ... + // + + // Provides: + // - (coord-like) <-> (offset-like) + pat_blk = pat_id | chunk() + // Now provides: + // + (index-like) <-> (chunk range) + // ... + // that is, the following expressions are valid: + // + // pat_blk[2] -> chunk + // with chunk ~> nview + // Therefore: + // + // pat_blk[2].extents() + // pat_blk[2].offsets() + // pat_blk[4] | index() -> block index (THIS is the block index) + // + // pat_unit_offs = pat_blk | cycle(nunits) | index() + // // = offset of unit in team spec, so + // // team_spec[unit_offs] -> unit_id + // + + + +} + +/*-- snip ---------------------------------------------------------------- */ + + + + + + + + diff --git a/dash/test/TestBase.h b/dash/test/TestBase.h index 8bc0bff78..72edd75ea 100644 --- a/dash/test/TestBase.h +++ b/dash/test/TestBase.h @@ -11,13 +11,22 @@ #include #include + #include +#include +#include + #include #include "TestGlobals.h" #include "TestPrinter.h" #include "TestLogHelpers.h" +#include +#include +#include + + namespace testing { namespace internal { @@ -221,6 +230,51 @@ static std::string range_str( return ss.str(); } +template +std::string nview_str( + const NViewType & nview) { + using value_t = typename NViewType::value_type; + auto view_nrows = nview.extents()[0]; + auto view_ncols = nview.extents()[1]; + auto nindex = dash::index(nview); + std::ostringstream ss; + for (int r = 0; r < view_nrows; ++r) { + for (int c = 0; c < view_ncols; ++c) { + int offset = r * view_ncols + c; + ss << std::fixed << std::setw(3) + << nindex[offset] + << ":" + << std::fixed << std::setprecision(5) + << static_cast(nview[offset]) + << " "; + } + ss << '\n'; + } + return ss.str(); +} + +template +std::string nrange_str( + const NViewType & nview) { + using value_t = typename NViewType::value_type; + auto view_nrows = nview.extents()[0]; + auto view_ncols = nview.extents()[1]; + std::ostringstream ss; + for (int r = 0; r < view_nrows; ++r) { + auto row_view = dash::sub<0>(r, r+1, nview); + for (int c = 0; c < row_view.size(); ++c) { + int offset = r * view_ncols + c; + ss << std::fixed << std::setw(3) + << offset << ":" + << std::fixed << std::setprecision(5) + << static_cast(row_view[c]) + << " "; + } + ss << '\n'; + } + return ss.str(); +} + template static bool expect_range_values_equal( const RangeA & rng_a, @@ -240,6 +294,30 @@ static bool expect_range_values_equal( return (end_a == it_a) && (end_b == it_b); } +template +static bool expect_range_values_equal( + const IteratorA & rng_a_begin, + const SentinelA & rng_a_end, + const IteratorB & rng_b_begin) { + auto it_a = rng_a_begin; + auto it_b = rng_b_begin; + const auto end_a = rng_a_end; + const auto end_b = rng_b_begin + dash::distance(it_a, end_a); + + const auto rng_a = dash::make_range(it_a, end_a); + const auto rng_b = dash::make_range(it_b, end_b); + + DASH_LOG_TRACE_VAR("TestBase.expect_range_values_equal", rng_a); + DASH_LOG_TRACE_VAR("TestBase.expect_range_values_equal", rng_b); + for (; it_a != end_a && it_b != end_b; ++it_a, ++it_b) { + if (static_cast(*it_a) != + static_cast(*it_b)) { + return false; + } + } + return (end_a == it_a) && (end_b == it_b); +} + class TestBase : public ::testing::Test { protected: diff --git a/dash/test/algorithm/CopyTest.cc b/dash/test/algorithm/CopyTest.cc index 8effa9ea4..17350c976 100644 --- a/dash/test/algorithm/CopyTest.cc +++ b/dash/test/algorithm/CopyTest.cc @@ -1,19 +1,25 @@ +#include "CopyTest.h" + #include #include #include #include +#include +#include +#include + #include #include #include -#include "../TestBase.h" -#include "../TestLogHelpers.h" -#include "CopyTest.h" +#include #include +#include + TEST_F(CopyTest, BlockingGlobalToLocalBlock) @@ -93,7 +99,6 @@ TEST_F(CopyTest, Blocking2DimGlobalToLocalBlock) // Assign initial values: for (size_t lb = 0; lb < num_blocks_per_unit; ++lb) { - LOG_MESSAGE("initialize values in local block %zu", lb); auto lblock = matrix.local.block(lb); auto lblock_view = lblock.begin().viewspec(); auto lblock_extents = lblock_view.extents(); @@ -101,10 +106,6 @@ TEST_F(CopyTest, Blocking2DimGlobalToLocalBlock) dash__unused(lblock_offsets); EXPECT_EQ_U(block_size_x, lblock_extents[0]); EXPECT_EQ_U(block_size_y, lblock_extents[1]); - LOG_MESSAGE("local block %zu offset: (%li,%li) extent: (%lu,%lu)", - lb, - lblock_offsets[0], lblock_offsets[1], - lblock_extents[0], lblock_extents[1]); for (auto bx = 0; bx < static_cast(lblock_extents[0]); ++bx) { for (auto by = 0; by < static_cast(lblock_extents[1]); ++by) { // Phase coordinates (bx,by) to global coordinates (gx,gy): @@ -118,8 +119,6 @@ TEST_F(CopyTest, Blocking2DimGlobalToLocalBlock) ((bx + 1) * 100) + by + 1 )); - LOG_MESSAGE("set local block %zu at phase:(%d,%d) g:(%li,%li) = %f", - lb, bx, by, gx, gy, value); lblock[bx][by] = value; } } @@ -133,9 +132,6 @@ TEST_F(CopyTest, Blocking2DimGlobalToLocalBlock) for (size_t x = 0; x < extent_x; ++x) { std::vector row; for (size_t y = 0; y < extent_y; ++y) { - DASH_LOG_DEBUG("CopyTest.Blocking2Dim", "get matrix value at", - "x:", x, - "y:", y); value_t value = matrix[x][y]; row.push_back(value); } @@ -149,10 +145,10 @@ TEST_F(CopyTest, Blocking2DimGlobalToLocalBlock) matrix.barrier(); // Array to store local copy: - value_t * local_copy = new value_t[num_elem_per_unit]; + std::vector local_copy(num_elem_per_unit); // Pointer to first value in next copy destination range: - value_t * copy_dest_begin = local_copy; - value_t * copy_dest_last = local_copy; + value_t * copy_dest_begin = local_copy.data(); + value_t * copy_dest_last = local_copy.data(); // // Create local copy of all blocks from a single remote unit: @@ -167,23 +163,98 @@ TEST_F(CopyTest, Blocking2DimGlobalToLocalBlock) auto g_block_view = pattern.block(gb); // Unit assigned to block at global block index gb: auto g_block_unit = pattern.unit_at( - std::array {0,0}, + std::array {{ 0,0 }}, g_block_view); - LOG_MESSAGE("Block %zu: assigned to unit %d", gb, g_block_unit.id); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", " ---- ", + "block gidx:", gb, + "assigned to unit", g_block_unit.id); if (g_block_unit == remote_unit_id) { // Block is assigned to selecte remote unit, create local copy: - LOG_MESSAGE("Creating local copy of block %zu", gb); - auto remote_block = matrix.block(gb); - auto remote_block_view = remote_block.begin().viewspec(); - dash__unused(remote_block_view); - LOG_MESSAGE("Block %zu index range: (%li..%li] " - "offset: (%li,%li) extent: (%lu,%lu)", - gb, remote_block.begin().pos(), remote_block.end().pos(), - remote_block_view.offset(0), remote_block_view.offset(1), - remote_block_view.extent(0), remote_block_view.extent(1)); - copy_dest_last = dash::copy(remote_block.begin(), - remote_block.end(), - copy_dest_begin); + auto remote_block_matrix = matrix.block(gb); + auto remote_block_view = dash::blocks(matrix)[gb]; + + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "source block view:", + dash::typestr(remote_block_view)); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "source block view", + "extents:", remote_block_view.extents(), + "offsets:", remote_block_view.offsets(), + "size:", remote_block_view.size()); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "source block view domain:", + dash::typestr(dash::domain(remote_block_view))); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "source block view origin:", + dash::typestr(dash::origin(remote_block_view))); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "source block view domain extents:", + dash::domain(remote_block_view).extents()); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "source block view iterator:", + dash::typestr(remote_block_view.begin())); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "begin.pos:", remote_block_view.begin().pos(), + "end.pos:", remote_block_view.end().pos(), + "begin.gpos:", remote_block_view.begin().gpos(), + "end.gpos:", remote_block_view.end().gpos()); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + dash::test::nview_str(remote_block_view)); + + EXPECT_EQ_U(remote_block_matrix.viewspec().offsets(), + dash::index(remote_block_view).offsets()); + EXPECT_EQ_U(remote_block_matrix.viewspec().extents(), + dash::index(remote_block_view).extents()); +#if 0 + copy_dest_last = dash::copy(remote_block_view.begin(), + remote_block_view.end(), + copy_dest_begin); +#else + copy_dest_last = dash::copy(remote_block_view, + copy_dest_begin); +#endif + +#if 0 + auto remote_block_range = dash::make_range( + remote_block_view.begin(), + remote_block_view.end()); + + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "source block range:", + dash::typestr(remote_block_range)); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "source block range", + "extents:", remote_block_range.extents(), + "offsets:", remote_block_range.offsets(), + "size:", remote_block_range.size()); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "source block range domain:", + dash::typestr(dash::domain(remote_block_range))); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "source block range origin:", + dash::typestr(dash::origin(remote_block_range))); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "source block range domain extents:", + dash::domain(remote_block_range).extents()); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "source block range iterator:", + dash::typestr(remote_block_range.begin())); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + "begin.pos:", remote_block_range.begin().pos(), + "end.pos:", remote_block_range.end().pos(), + "begin.gpos:", remote_block_range.begin().gpos(), + "end.gpos:", remote_block_range.end().gpos()); + DASH_LOG_DEBUG("CopyTest.Blocking2DimGlobalToLocalBlock", + dash::test::nview_str(remote_block_range)); + + EXPECT_EQ_U(remote_block_matrix.viewspec().offsets(), + dash::index(remote_block_range).offsets()); + EXPECT_EQ_U(remote_block_matrix.viewspec().extents(), + dash::index(remote_block_range).extents()); + + copy_dest_last = dash::copy(remote_block_range, + copy_dest_begin); +#endif // Validate number of copied elements: auto num_copied = copy_dest_last - copy_dest_begin; EXPECT_EQ_U(num_copied, block_size); @@ -227,7 +298,6 @@ TEST_F(CopyTest, Blocking2DimGlobalToLocalBlock) } } } - delete[] local_copy; // // Create local copy of first local block (local to local): @@ -235,14 +305,15 @@ TEST_F(CopyTest, Blocking2DimGlobalToLocalBlock) value_t local_block_copy[block_size]; int lb = 0; auto l_block = matrix.local.block(lb); - LOG_MESSAGE("Creating local copy of first local block"); - value_t * local_block_copy_last = - dash::copy(l_block.begin(), - l_block.end(), - local_block_copy); + DASH_LOG_DEBUG("CopyTest.Blocking2Dim", "matrix.local.block(0):", + "size:", l_block.size()); + EXPECT_EQ_U(block_size, l_block.size()); + auto local_block_copy_last = dash::copy(l_block.begin(), + l_block.end(), + local_block_copy); // Validate number of copied elements: auto num_copied = local_block_copy_last - local_block_copy; - EXPECT_EQ_U(num_copied, block_size); + EXPECT_EQ_U(block_size, num_copied); for (size_t bx = 0; bx < block_size_x; ++bx) { for (size_t by = 0; by < block_size_y; ++by) { auto l_offset = (bx * block_size_y) + by; @@ -463,6 +534,72 @@ TEST_F(CopyTest, AsyncLocalToGlobPtrWait) array.barrier(); } +TEST_F(CopyTest, BlockingLocalToGlobalBlockNDim) +{ + // Copy all elements contained in a single, continuous block. + const int num_rows_per_unit = 3; + const int num_cols_per_unit = 7; + + // Distribute row-wise, 3 rows per units: + dash::SizeSpec<2> sizespec(num_rows_per_unit * dash::size(), + num_cols_per_unit); + dash::DistributionSpec<2> distspec(dash::BLOCKED, dash::NONE); + dash::TeamSpec<2> teamspec(dash::size(), 1); + + using pattern_t = dash::BlockPattern<2>; + + dash::NArray matrix( + sizespec, distspec, dash::Team::All(), teamspec); + + std::iota(matrix.local.begin(), + matrix.local.end(), + (dash::myid() + 1) * 100); + matrix.barrier(); + + if (dash::myid() == 0) { + DASH_LOG_DEBUG("CopyTest.BlockingLocalToGlobalBlockNDim", + "initial matrix:"); + DASH_LOG_DEBUG("CopyTest.BlockingLocalToGlobalBlockNDim", + dash::test::nrange_str(matrix)); + } + matrix.barrier(); + + DASH_LOG_DEBUG_VAR("CopyTest.BlockingLocalToGlobalBlockNDim", + matrix.local.row(1)); + DASH_LOG_DEBUG_VAR("CopyTest.BlockingLocalToGlobalBlockNDim", + matrix.local.row(1).begin()); + DASH_LOG_DEBUG_VAR("CopyTest.BlockingLocalToGlobalBlockNDim", + matrix.local.row(1).end()); + + DASH_LOG_DEBUG("CopyTest.BlockingLocalToGlobalBlockNDim", + "source range:"); + auto in_range = dash::sub<0>(1, dash::local(matrix)); + DASH_LOG_DEBUG("CopyTest.BlockingLocalToGlobalBlockNDim", + dash::test::nview_str(in_range)); + + auto dest_row = ((dash::myid() + 1) * num_rows_per_unit) + % matrix.extents()[0]; + DASH_LOG_DEBUG_VAR("CopyTest.BlockingLocalToGlobalBlockNDim", + dest_row); + + matrix.barrier(); + + // Copy second local row into matrix row at next unit: + dash::copy(in_range.begin(), + in_range.end(), + dash::sub<0>( + dest_row, + dest_row + 1, + matrix).begin() + ); + + if (dash::myid() == 0) { + DASH_LOG_DEBUG("CopyTest.BlockingLocalToGlobalBlockNDim", + "result matrix:"); + DASH_LOG_DEBUG("CopyTest.BlockingLocalToGlobalBlockNDim", + dash::test::nrange_str(matrix)); + } +} TEST_F(CopyTest, AsyncLocalToGlobPtrTest) { @@ -743,7 +880,7 @@ TEST_F(CopyTest, AsyncGlobalToLocalTiles) dash::test::print_pattern_mapping( "matrix.a", pattern, 3, [](const pattern_t & _pattern, int _x, int _y) -> dart_unit_t { - return _pattern.unit_at(std::array {_x, _y}); + return _pattern.unit_at(std::array {{ _x, _y }}); }); dash::test::print_matrix("matrix.a", matrix_a, 2); } @@ -853,6 +990,52 @@ TEST_F(CopyTest, AsyncGlobalToLocalBlockWait) } } +TEST_F(CopyTest, GlobalToGlobal) +{ + using value_t = int; + constexpr int elem_per_unit = 100; + dash::Array source(dash::size() * elem_per_unit); + dash::Array target(dash::size() * elem_per_unit); + + dash::fill(target.begin(), target.end(), 0); + dash::generate_with_index(source.begin(), source.end(), + [](size_t idx) { + return dash::myid() * 1000 + idx; + } + ); + + source.barrier(); + + // copy the full range + dash::copy(source.begin(), source.end(), target.begin()); + source.barrier(); + + dash::for_each_with_index(target.begin(), target.end(), + [](value_t val, size_t idx) { + ASSERT_EQ_U(val, dash::myid() * 1000 + idx); + } + ); + + // copy the range with an offset (effectively moving the input + // range to the left by 1) + dash::copy(source.begin() + 1, source.end(), target.begin()); + source.barrier(); + + dash::for_each_with_index(target.begin(), target.end() - 1, + [](value_t val, size_t idx) { + std::cout << idx << ": " << val << std::endl; + // the array has shifted so the last element is different + if ((idx % elem_per_unit) == (elem_per_unit - 1)) { + // the last element comes from the next unit + // this element has not been copied on the last unit + ASSERT_EQ_U(val, (dash::myid() + 1) * 1000 + idx + 1); + } else { + ASSERT_EQ_U(val, dash::myid() * 1000 + idx + 1); + } + } + ); +} + TEST_F(CopyTest, AsyncGlobalToLocalTest) { // Copy all elements contained in a single, continuous block. diff --git a/dash/test/algorithm/TransformTest.cc b/dash/test/algorithm/TransformTest.cc index cb3b063fa..1d956a0b4 100644 --- a/dash/test/algorithm/TransformTest.cc +++ b/dash/test/algorithm/TransformTest.cc @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include @@ -221,3 +223,42 @@ TEST_F(TransformTest, MatrixGlobalPlusGlobalBlocking) EXPECT_EQ_U(first_l_block_a_begin, first_l_block_a_offsets); } + + +TEST_F(TransformTest, LocalIteratorInput) +{ + using value_t = int; + std::vector local_v(100); + size_t idx = 0; + std::fill(local_v.begin(), local_v.end(), (value_t)dash::myid()); + for (auto& elem : local_v) { + elem = dash::myid() * 1000 + idx; + idx++; + } + dash::Array global_v(local_v.size() + 1); + dash::fill(global_v.begin(), global_v.end(), 0.0); + global_v.barrier(); + // start from the second element + auto it = dash::transform( + local_v.begin(), + local_v.end(), + global_v.begin() + 1, + global_v.begin() + 1, + dash::max() + ); + + global_v.barrier(); + + ASSERT_EQ_U(it, global_v.end()); + +// size_t idx = 0; + + dash::for_each_with_index(global_v.begin() + 1, global_v.end(), + [](value_t val, size_t idx){ + ASSERT_EQ_U(val, (dash::size() - 1) * 1000 + (idx - 1)); + ++idx; + }); + + global_v.barrier(); +} + diff --git a/dash/test/container/MatrixTest.cc b/dash/test/container/MatrixTest.cc index 911d72ce0..1f0cb1574 100644 --- a/dash/test/container/MatrixTest.cc +++ b/dash/test/container/MatrixTest.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -156,8 +157,12 @@ TEST_F(MatrixTest, Views) l_block_view.offset(1), ")", "extent: (", l_block_view.extent(0), ",", l_block_view.extent(1), ")"); - // Verify matrix.block(b) == matrix.local.block(lb): - ASSERT_EQ_U(g_block_view, l_block_view); + // Verify matrix.block(b) vs. matrix.local.block(lb): + ASSERT_EQ_U(l_block_view.extents(), l_block_view.extents()); + ASSERT_EQ_U(l_block_view.offsets(), l_block_view.offsets()); + + ASSERT_TRUE_U(std::equal(g_block.begin(), g_block.end(), + l_block.begin(), l_block.end())); ++lb; } } @@ -688,7 +693,7 @@ TEST_F(MatrixTest, ViewIteration) } } -TEST_F(MatrixTest, BlockCopy) +TEST_F(MatrixTest, BlockCopyGlobalToGlobal) { typedef int element_t; int myid = dash::myid().id; @@ -721,28 +726,41 @@ TEST_F(MatrixTest, BlockCopy) dash::Team::All(), team_spec); // Fill matrix + auto block_a = matrix_a | dash::block(1); + auto block_b = matrix_b | dash::block(0); if (myid == 0) { LOG_MESSAGE("Assigning matrix values"); - for(size_t col = 0; col < matrix_a.extent(0); ++col) { - for(size_t row = 0; row < matrix_a.extent(1); ++row) { - auto value = (row * matrix_a.extent(0)) + col; - matrix_a[col][row] = value; - matrix_b[col][row] = value; + for(size_t row = 0; row < matrix_a.extent(0); ++row) { + for(size_t col = 0; col < matrix_a.extent(1); ++col) { + auto value = (row * 1000) + col; + matrix_a[row][col] = value; + matrix_b[row][col] = value; } } } - LOG_MESSAGE("Wait for team barrier ..."); - dash::barrier(); - LOG_MESSAGE("Team barrier passed"); + matrix_b.barrier(); + + LOG_MESSAGE("Copying block"); + +#if 0 // Copy block 1 of matrix_a to block 0 of matrix_b: - dash::copy(matrix_a.block(1).begin(), - matrix_a.block(1).end(), - matrix_b.block(0).begin()); + dash::copy(block_a, + block_b); + matrix_b.barrier(); - LOG_MESSAGE("Wait for team barrier ..."); - dash::barrier(); - LOG_MESSAGE("Team barrier passed"); + LOG_MESSAGE("Checking copy result"); + if (myid == 0) { + LOG_MESSAGE("Checking copied matrix block values"); + for(ssize_t col = 0; col < block_a.extent(0); ++col) { + for(ssize_t row = 0; row < block_a.extent(1); ++row) { + ASSERT_EQ_U( + static_cast(block_b[{ col, row }]), + static_cast(block_a[{ col, row }])); + } + } + } +#endif } TEST_F(MatrixTest, StorageOrder) @@ -1106,21 +1124,21 @@ TEST_F(MatrixTest, UnderfilledBlockedPatternExtents) EXPECT_LE_U( corner[0] + matrix.local.extent(0), h ); } -TEST_F(MatrixTest, UnderfilledLocalViewSpec){ +TEST_F(MatrixTest, UnderfilledLocalViewSpec) { auto myid = dash::myid(); auto numunits = dash::Team::All().size(); dash::TeamSpec<2> teamspec( numunits, 1 ); teamspec.balance_extents(); - uint32_t w= 13; - uint32_t h= 7; + uint32_t w = 13; + uint32_t h = 7; auto distspec= dash::DistributionSpec<2>( dash::BLOCKED, dash::BLOCKED ); dash::NArray narray( dash::SizeSpec<2>( h, w ), distspec, dash::Team::All(), teamspec ); narray.barrier(); - if ( 0 == myid ) { + if (0 == myid) { LOG_MESSAGE("global extent is %lu x %lu", narray.extent(0), narray.extent(1)); } @@ -1136,6 +1154,7 @@ TEST_F(MatrixTest, UnderfilledLocalViewSpec){ ASSERT_EQ_U(el, 1); }); dash::barrier(); + // test local view std::fill(narray.local.begin(), narray.local.end(), 2); std::for_each(narray.local.begin(), narray.local.end(), @@ -1144,7 +1163,7 @@ TEST_F(MatrixTest, UnderfilledLocalViewSpec){ }); uint32_t elementsvisited = std::distance(narray.lbegin(), narray.lend()); - auto local_elements= narray.local.extent(0) * narray.local.extent(1); + auto local_elements = narray.local.extent(0) * narray.local.extent(1); ASSERT_EQ_U(elementsvisited, local_elements); ASSERT_EQ_U(elementsvisited, narray.local.size()); @@ -1180,10 +1199,26 @@ TEST_F(MatrixTest, MatrixLBegin) matrix.barrier(); int * l_first = matrix.lbegin(); + DASH_LOG_DEBUG_VAR("MatrixTest.MatrixLBegin", l_first); + + int * l_matrix_first = static_cast(matrix.local.begin()); + DASH_LOG_DEBUG_VAR("MatrixTest.MatrixLBegin", l_matrix_first); + + EXPECT_EQ_U(l_first, l_matrix_first); + EXPECT_EQ_U(myid, *l_matrix_first); - EXPECT_EQ_U(myid, static_cast(*(matrix.lbegin()))); - EXPECT_EQ_U(myid, static_cast(*(matrix.local.block(0).begin()))); - EXPECT_EQ_U(myid, static_cast(*(matrix.local.begin()))); + DASH_LOG_DEBUG_VAR("MatrixTest.MatrixLBegin", + matrix.local.block(0).offsets()); + DASH_LOG_DEBUG_VAR("MatrixTest.MatrixLBegin", + matrix.local.block(0).extents()); + DASH_LOG_DEBUG_VAR("MatrixTest.MatrixLBegin", + matrix.local.block(0)); + + int * l_block_first = static_cast(matrix.local.block(0).begin()); + DASH_LOG_DEBUG_VAR("MatrixTest.MatrixLBegin", l_block_first); + + EXPECT_EQ_U(l_first, l_block_first); + EXPECT_EQ_U(myid, *l_block_first); } TEST_F(MatrixTest, DelayedPatternAllocation) @@ -1260,22 +1295,10 @@ TEST_F(MatrixTest, CopyRow) dash::barrier(); dash::test::print_matrix("Matrix<2>.local.row(0)", row, 2); - auto l_prange = dash::local_range(row.begin(), row.end()); - DASH_LOG_DEBUG_VAR("MatrixTest.CopyRow", - static_cast(l_prange.begin)); - DASH_LOG_DEBUG_VAR("MatrixTest.CopyRow", - static_cast(l_prange.end)); - auto l_irange = dash::local_index_range(row.begin(), row.end()); - DASH_LOG_DEBUG_VAR("MatrixTest.CopyRow", static_cast(l_irange.begin)); - DASH_LOG_DEBUG_VAR("MatrixTest.CopyRow", static_cast(l_irange.end)); - - EXPECT_EQ_U(row_size, l_irange.end - l_irange.begin); - EXPECT_EQ_U(row_size, l_prange.end - l_prange.begin); - EXPECT_EQ_U(1, decltype(row)::ndim()); EXPECT_EQ_U(n_lextent, row_size); - EXPECT_EQ_U(n_lextent, row.extents()[1]); + EXPECT_EQ_U(n_lextent, row.end() - row.begin()); // Check values and test for each expression: int li = 0; diff --git a/dash/test/meta/RangeTest.cc b/dash/test/meta/RangeTest.cc index 5150a860a..a77594d87 100644 --- a/dash/test/meta/RangeTest.cc +++ b/dash/test/meta/RangeTest.cc @@ -87,10 +87,13 @@ TEST_F(RangeTest, RangeTraits) dash::is_range::value == true, "dash::is_range>::value not matched"); - auto l_range = dash::make_range(array.local.begin(), - array.local.end()); - static_assert( - dash::is_range::value == true, - "dash::is_range::value not matched"); +// auto l_range = dash::make_range(array.local.begin(), +// array.local.end()); +// static_assert( +// dash::is_range::value == true, +// "dash::is_range::value not matched"); +// static_assert( +// dash::is_view::value == false, +// "dash::is_view::value not matched"); } diff --git a/dash/test/types/CartesianTest.cc b/dash/test/types/CartesianTest.cc index 296fb4c57..f58029072 100644 --- a/dash/test/types/CartesianTest.cc +++ b/dash/test/types/CartesianTest.cc @@ -13,7 +13,8 @@ TEST_F(CartesianTest, DefaultConstructor) { // 1-dimensional: dash::CartesianIndexSpace<1> cartesian1d; EXPECT_EQ(cartesian1d.size(), 0); - EXPECT_EQ(cartesian1d.rank(), 1); + EXPECT_EQ(cartesian1d.rank(), 0); + EXPECT_EQ(decltype(cartesian1d)::ndim::value, 1); EXPECT_EQ(cartesian1d.extent(0), 0); #if defined(DASH_ENABLE_ASSERTIONS) dash::internal::logging::disable_log(); @@ -28,7 +29,8 @@ TEST_F(CartesianTest, DefaultConstructor) { // 4-dimensional: dash::CartesianIndexSpace<4> cartesian4d; EXPECT_EQ(cartesian4d.size(), 0); - EXPECT_EQ(cartesian4d.rank(), 4); + EXPECT_EQ(decltype(cartesian4d)::ndim::value, 4); + EXPECT_EQ(cartesian4d.rank(), 0); EXPECT_EQ(cartesian4d.extent(0), 0); EXPECT_EQ(cartesian4d.extent(1), 0); EXPECT_EQ(cartesian4d.extent(2), 0); @@ -137,8 +139,8 @@ TEST_F(CartesianTest, Conversion10Dim) { cartesianR(extents); dash::CartesianIndexSpace cartesianC(extents); - EXPECT_EQ(cartesianR.rank(), Dimensions); - EXPECT_EQ(cartesianC.rank(), Dimensions); + EXPECT_EQ(cartesianR.rank(), 8); + EXPECT_EQ(cartesianC.rank(), 8); EXPECT_EQ(cartesianR.size(), size); EXPECT_EQ(cartesianC.size(), size); for (int d = 0; d < Dimensions; ++d) { diff --git a/dash/test/view/MatrixViewTest.cc b/dash/test/view/MatrixViewTest.cc new file mode 100644 index 000000000..c8b83241e --- /dev/null +++ b/dash/test/view/MatrixViewTest.cc @@ -0,0 +1,152 @@ + +#include "MatrixViewTest.h" +#include "ViewTestBase.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include + + +using dash::test::range_str; +using dash::test::print_nview; +using dash::test::region_values; + +TEST_F(MatrixViewTest, GlobalSubLocalBlocks) +{ + using namespace dash; + + typedef dash::SeqTilePattern<2> pattern_t; + typedef typename pattern_t::index_type index_t; + typedef float value_t; + + auto myid = dash::Team::All().myid(); + auto nunits = dash::size(); + + const size_t block_size_x = 2; + const size_t block_size_y = 2; + const size_t block_size = block_size_x * block_size_y; + size_t extent_x = block_size_x * (nunits + 1); + size_t extent_y = block_size_y * (nunits + 1); + + dash::TeamSpec<2> teamspec(dash::Team::All()); + teamspec.balance_extents(); + + pattern_t pattern( + dash::SizeSpec<2>( + extent_y, + extent_x), + dash::DistributionSpec<2>( + dash::TILE(block_size_y), + dash::TILE(block_size_x)), + teamspec + ); + + dash::Matrix + matrix(pattern); + + int li = 0; + std::generate(matrix.lbegin(), + matrix.lend(), + [&]() { + return dash::myid() + 0.01 * li++; + }); + + dash::barrier(); + + // -------------------------------------------------------------------- + // matrix | sub + // + auto matrix_sub = matrix | sub<0>(3, extent_y-1) + | sub<1>(1, extent_x-1); + + EXPECT_EQ_U(matrix.extent(0) - 4, matrix_sub.extent(0)); + EXPECT_EQ_U(matrix.extent(1) - 2, matrix_sub.extent(1)); + + // -------------------------------------------------------------------- + // matrix | sub | blocks + // + { + auto m_s_blocks = matrix_sub | blocks(); + auto m_s_blocks_idx = m_s_blocks | index(); + std::vector m_s_b_values; + std::vector m_s_values; + + int b_idx = 0; + for (const auto & blk : m_s_blocks) { + auto blk_gidx = m_s_blocks_idx[b_idx]; + auto blk_glob_viewspec = matrix.pattern().block(blk_gidx); + bool blk_is_local_expected = matrix.pattern().unit_at( + blk_glob_viewspec.offsets() + ) == myid; + bool blk_is_local_actual = blk.is_local_at(myid); + bool blk_is_strid_expected = blk.extent(1) < block_size_x && + blk.extent(0) > 1; + bool blk_is_strid_actual = blk.is_strided(); + + DASH_LOG_DEBUG("MatrixViewTest.GlobalSubLocalBlocks", + "block view idx:", b_idx, "-> block gidx:", blk_gidx, + ":", range_str(blk)); + + if (!blk || !(blk | index())) { + EXPECT_EQ_U(blk.size(), 0); + EXPECT_EQ_U((blk | index()).size(), 0); + } else { + EXPECT_EQ_U(blk_is_local_expected, blk.is_local_at(myid)); + EXPECT_EQ_U(blk_is_strid_expected, blk.is_strided()); + + std::copy(blk.begin(), blk.end(), + std::back_inserter(m_s_b_values)); + } + ++b_idx; + } + + // Block-wise element order differs from element order in sub-matrix + // which is canonical. Copy, sort and intersect both ranges to test + // equality: + + std::copy(matrix_sub.begin(), matrix_sub.end(), + std::back_inserter(m_s_values)); + + DASH_LOG_DEBUG("MatrixViewTest.GlobalSubLocalBlocks", + "matrix_sub:", (m_s_values)); + DASH_LOG_DEBUG("MatrixViewTest.GlobalSubLocalBlocks", + "copied from blocks:", (m_s_b_values)); + + std::sort(m_s_values.begin(), m_s_values.end()); + std::sort(m_s_b_values.begin(), m_s_b_values.end()); + + std::vector m_s_isect; + std::set_difference(m_s_values.begin(), m_s_values.end(), + m_s_b_values.begin(), m_s_b_values.end(), + std::back_inserter(m_s_isect)); + DASH_LOG_DEBUG("MatrixViewTest.GlobalSubLocalBlocks", + "intersection:", (m_s_isect)); + EXPECT_EQ_U(0, m_s_isect.size()); + } + + // -------------------------------------------------------------------- + // matrix | sub | local | blocks + // + return; + { + auto m_s_l_blocks = matrix_sub | local() | blocks(); + auto m_s_l_blocks_idx = m_s_l_blocks | index(); + int b_idx = 0; + for (const auto & blk : m_s_l_blocks) { + auto blk_gidx = m_s_l_blocks_idx[b_idx]; + auto blk_glob_viewspec = matrix.pattern().block(blk_gidx); + bool blk_is_local_expected = true; + bool blk_is_strid_expected = !test::is_contiguous_ix(blk | index()); + + ++b_idx; + } + } +} + diff --git a/dash/test/view/MatrixViewTest.h b/dash/test/view/MatrixViewTest.h new file mode 100644 index 000000000..ffba02f11 --- /dev/null +++ b/dash/test/view/MatrixViewTest.h @@ -0,0 +1,22 @@ +#ifndef DASH__TEST__MATRIX_VIEW_TEST_H__INCLUDED +#define DASH__TEST__MATRIX_VIEW_TEST_H__INCLUDED + +#include "ViewTestBase.h" + +/** + * Test fixture for the DASH View concept + */ +class MatrixViewTest : public dash::test::ViewTestBase { +protected: + + MatrixViewTest() { + LOG_MESSAGE(">>> Test suite: MatrixViewTest"); + } + + virtual ~MatrixViewTest() { + LOG_MESSAGE("<<< Closing test suite: MatrixViewTest"); + } + +}; + +#endif // DASH__TEST__MATRIX_VIEW_TEST_H__INCLUDED diff --git a/dash/test/view/NViewTest.cc b/dash/test/view/NViewTest.cc index 9e537facb..29d8a7ffb 100644 --- a/dash/test/view/NViewTest.cc +++ b/dash/test/view/NViewTest.cc @@ -1,5 +1,6 @@ #include "NViewTest.h" +#include "ViewTestBase.h" #include @@ -7,75 +8,12 @@ #include #include #include +#include #include #include -#include -#include -namespace dash { -namespace test { - - template - void initialize_matrix(MatrixT & matrix) { - if (dash::myid() == 0) { - for(size_t i = 0; i < matrix.extent(0); ++i) { - for(size_t k = 0; k < matrix.extent(1); ++k) { - matrix[i][k] = (i + 1) * 0.100 + (k + 1) * 0.001; - } - } - } - matrix.barrier(); - - for(size_t i = 0; i < matrix.local_size(); ++i) { - matrix.lbegin()[i] += dash::myid(); - } - matrix.barrier(); - } - - template - void print_nview( - const std::string & name, - const NViewType & nview) { - using value_t = typename NViewType::value_type; - auto view_nrows = nview.extents()[0]; - auto view_ncols = nview.extents()[1]; - auto nindex = dash::index(nview); - for (int r = 0; r < view_nrows; ++r) { - std::ostringstream row_ss; - for (int c = 0; c < view_ncols; ++c) { - int offset = r * view_ncols + c; - row_ss << std::fixed << std::setw(2) - << nindex[offset] - << ":" - << std::fixed << std::setprecision(3) - << static_cast(nview[offset]) - << " "; - } - DASH_LOG_DEBUG("NViewTest.print_nview", - name, "[", r, "]", row_ss.str()); - } - } - - template - std::vector - region_values(const NViewType & view, const dash::ViewSpec<2> & vs) { - auto nvalues = vs.size(); - using value_t = typename NViewType::value_type; - std::vector values; - values.reserve(nvalues); - dash::CartesianIndexSpace<2> cart(view.extents()); - for (int i = 0; i < nvalues; i++) { - auto coords = cart.coords(i, vs); - auto index = cart.at(coords); - values.push_back(static_cast(view.begin()[index])); - } - return values; - } -} -} - using dash::test::range_str; TEST_F(NViewTest, ViewTraits) @@ -257,14 +195,15 @@ TEST_F(NViewTest, MatrixBlocked1DimSingle) dash::test::print_nview("nview_rows_g", nview_rows_g); auto exp_nview_rows_g = dash::test::region_values( - mat, {{ 1,0 }, { 2,mat.extent(1) }} ); + mat, {{ 1,0 }, { 2,mat.extent(1) }} + ); - EXPECT_TRUE_U( + EXPECT_TRUE( dash::test::expect_range_values_equal( exp_nview_rows_g, nview_rows_g)); - EXPECT_EQ_U(2, nview_rows_g.extent<0>()); - EXPECT_EQ_U(mat.extent(1), nview_rows_g.extent<1>()); + EXPECT_EQ(2, nview_rows_g.extent<0>()); + EXPECT_EQ(mat.extent(1), nview_rows_g.extent<1>()); DASH_LOG_DEBUG("NViewTest.MatrixBlocked1DimSingle", "sub<1>(2,7, mat) ->", @@ -523,7 +462,7 @@ TEST_F(NViewTest, MatrixBlocked1DimChained) "extents:", nview_cr_s_g.extents(), "size:", nview_cr_s_g.size()); dash::test::print_nview("nview_cr_s_g", nview_cr_s_g); - + DASH_LOG_DEBUG("NViewTest.MatrixBlocked1DimChained", "sub<0>(1,3, sub<1>(2,7, mat) ->", "offsets:", nview_rc_s_g.offsets(), @@ -548,17 +487,20 @@ TEST_F(NViewTest, MatrixBlocked1DimChained) DASH_LOG_DEBUG("NViewTest.MatrixBlocked1DimChained", "== nview_rows_l"); auto nview_rows_l = dash::local(nview_rows_g); DASH_LOG_DEBUG("NViewTest.MatrixBlocked1DimChained", + "local(sub<0>(1,3, mat)):", + dash::typestr(nview_rows_l), "extents:", nview_rows_l.extents(), "offsets:", nview_rows_l.offsets()); // EXPECT_EQ_U(2, nview_rows_l.extent<0>()); // EXPECT_EQ_U(block_cols, nview_rows_l.extent<1>()); -// + // dash::test::print_nview("nview_rows_l", nview_rows_l); DASH_LOG_DEBUG("NViewTest.MatrixBlocked1DimChained", "== nview_cols_l"); auto nview_cols_l = dash::local(nview_cols_g); DASH_LOG_DEBUG("NViewTest.MatrixBlocked1DimChained", + "local(sub<1>(2,7, mat)):", "extents:", nview_cols_l.extents(), "offsets:", nview_cols_l.offsets()); @@ -601,6 +543,17 @@ TEST_F(NViewTest, MatrixBlocked1DimSub) DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlocked1DimSub", mat.pattern().local_size()); + // Initial plausibility check: equality of iterator on n-dim view and + // matrix view proxy iterator: + auto view_expr_it = dash::sub<0>(1,2, mat) + .begin() + 2; + auto mat_ref_glob_it = (mat.row(1).begin() + 2); + + using globiter_t = decltype(mat.begin()); + + EXPECT_EQ_U(view_expr_it.dart_gptr(), + mat_ref_glob_it.dart_gptr()); + if (dash::myid() == 0) { auto all_sub = dash::sub<0>( 0, mat.extents()[0], @@ -624,7 +577,7 @@ TEST_F(NViewTest, MatrixBlocked1DimSub) // -- Sub-Section ---------------------------------- // - + if (dash::myid() == 0) { DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlocked1DimSub", mat.extents()); @@ -663,7 +616,7 @@ TEST_F(NViewTest, MatrixBlocked1DimSub) // -- Local View ----------------------------------- // - + auto lsub_view = dash::local( dash::sub<0>( 0, mat.extents()[0], @@ -671,7 +624,7 @@ TEST_F(NViewTest, MatrixBlocked1DimSub) EXPECT_EQ_U(2, decltype(lsub_view)::rank::value); EXPECT_EQ_U(2, lsub_view.ndim()); - + int lrows = lsub_view.extent<0>(); int lcols = lsub_view.extent<1>(); @@ -685,14 +638,14 @@ TEST_F(NViewTest, MatrixBlocked1DimSub) DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlocked1DimSub", lsub_view.size()); DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlocked1DimSub", index(lsub_view).size()); - + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlocked1DimSub", lsub_view.begin().pos()); DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlocked1DimSub", lsub_view.end().pos()); DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlocked1DimSub", (lsub_view.end() - lsub_view.begin())); - + EXPECT_EQ_U(mat.local_size(), lrows * lcols); dash::test::print_nview("lsub_view", lsub_view); @@ -776,7 +729,7 @@ TEST_F(NViewTest, MatrixBlockCyclic1DimSub) int bi = 0; for (const auto & block : nview_blocks) { DASH_LOG_DEBUG("NViewTest.MatrixBlockCyclic1DSingle", - "block", bi, ":", "extents:", block.extents(), + "block", bi, ":", "extents:", block.extents(), range_str(block)); bi++; } @@ -819,11 +772,11 @@ TEST_F(NViewTest, MatrixBlockCyclic2DimSub) { auto nunits = dash::size(); - int block_rows = 2; + int block_rows = 3; int block_cols = 2; int nrows = nunits * block_rows; - int ncols = nunits * block_cols * 2; + int ncols = nunits * block_cols * 2 - block_cols; if (nunits % 2 == 0 && nunits > 2) { nrows /= 2; @@ -860,11 +813,24 @@ TEST_F(NViewTest, MatrixBlockCyclic2DimSub) dash::test::initialize_matrix(mat); DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", mat.extents()); - DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", team_spec.extents()); DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", mat.pattern().local_extents()); DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", mat.pattern().local_size()); + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", + mat.pattern().blockspec()); + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", + mat.pattern().blockspec().rank()); + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", + mat.pattern().blocksize(0)); + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", + mat.pattern().blocksize(1)); + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", + mat.pattern().local_blockspec()); + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", + mat.pattern().local_blockspec().rank()); + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", + mat.pattern().teamspec()); if (dash::myid() == 0) { auto all_sub = dash::sub<0>( @@ -879,8 +845,11 @@ TEST_F(NViewTest, MatrixBlockCyclic2DimSub) DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", index(all_sub).size()); - dash::test::print_nview("mat_view", all_sub); + dash::test::print_nview("mat_global", all_sub); + } + mat.barrier(); + if (dash::myid() == 0) { auto nview_rows = dash::sub<0>(1, mat.extent(0) - 1, mat); DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", @@ -905,13 +874,192 @@ TEST_F(NViewTest, MatrixBlockCyclic2DimSub) auto nview_blocks = dash::blocks(mat); + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", + nview_blocks.size()); + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", + nview_blocks.offsets()); + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", + nview_blocks.extents()); + int bi = 0; for (const auto & block : nview_blocks) { - DASH_LOG_DEBUG("NViewTest.MatrixBlockCyclic2DSingle", - "block", bi, ":", "extents:", block.extents(), - range_str(block)); + DASH_LOG_DEBUG("NViewTest.MatrixBlockCyclic2DSub", + "block", bi, ":", + "offsets:", block.offsets(), + "extents:", block.extents()); + + const auto & block_idx = dash::index(block); + const auto & pat_block = mat.pattern().block(bi); + + DASH_LOG_DEBUG("NViewTest.MatrixBlockCyclic2DSub", + "blocks(mat)[b]:"); + DASH_LOG_DEBUG("NViewTest.MatrixBlockCyclic2DSub", + dash::test::nview_str(block)); + DASH_LOG_DEBUG("NViewTest.MatrixBlockCyclic2DSub", + "pattern.block(b):", + pat_block); + + EXPECT_EQ(pat_block.size(), block.size()); + EXPECT_EQ(pat_block.offsets(), block.offsets()); + EXPECT_EQ(pat_block.extents(), block.extents()); + + for (int bphase = 0; bphase < pat_block.size(); ++bphase) { + auto pat_g_index = dash::CartesianIndexSpace<2>( + mat.pattern().extents() + ).at( + // in-block coords + dash::CartesianIndexSpace<2>( + pat_block.extents() + ).coords(bphase), + // block viewspec + pat_block); + EXPECT_EQ(pat_g_index, block_idx[bphase]); + } bi++; } } mat.barrier(); + + // TODO: multi-dimensional strided local views not supported yet, + // for example when using dash::SeqTilePattern in this test. + + auto mat_local = dash::local( + dash::sub<0>( + 0, mat.extents()[0], + mat)); + + typedef typename dash::pattern_traits::mapping + pat_mapping_traits; + bool pat_traits_shifted = pat_mapping_traits::shifted || + pat_mapping_traits::diagonal; + + EXPECT_EQ_U(pat_traits_shifted, index(mat_local).is_shifted()); + + EXPECT_TRUE_U(index(mat_local).is_strided() || dash::size() < 2); + EXPECT_TRUE_U(index(mat_local).is_sub() || dash::size() < 2); + EXPECT_FALSE_U(index(dash::domain(mat_local)).is_sub()); + + EXPECT_EQ_U(mat.pattern().local_size(), mat_local.size()); + EXPECT_EQ_U(mat.pattern().local_extents(), mat_local.extents()); + + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", mat_local.offsets()); + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", mat_local.extents()); + DASH_LOG_DEBUG_VAR("NViewTest.MatrixBlockCyclic2DSub", mat_local.size()); + + dash::test::print_nview("mat_local", mat_local); +} + + +TEST_F(NViewTest, Matrix2DTiledLocalBlocks) +{ + dart_unit_t myid = dash::myid(); + size_t num_units = dash::Team::All().size(); + + dash::TeamSpec<2> teamspec_2d(num_units, 1); + teamspec_2d.balance_extents(); + + //Number of blocks per dimension + size_t size_factor = 3; + size_t tile_size = 3; + size_t rows = tile_size * teamspec_2d.num_units(0) * size_factor; + size_t cols = tile_size * teamspec_2d.num_units(1) * size_factor; + size_t matrix_size = rows * cols; + + if (matrix_size <= 1024 && 0 == myid) { + std::cout << "Matrix size: " << rows + << " x " << cols + << " == " << matrix_size + << std::endl; + } + + dash::Matrix matrix( + dash::SizeSpec<2>( + rows, + cols), + dash::DistributionSpec<2>( + dash::TILE(tile_size), + dash::TILE(tile_size)), + dash::Team::All(), + teamspec_2d); + DASH_ASSERT(matrix_size == matrix.size()); + DASH_ASSERT(rows == matrix.extent(0)); + DASH_ASSERT(cols == matrix.extent(1)); + + std::fill(matrix.lbegin(), matrix.lend(), (double)myid); + + dash::barrier(); + + auto pattern = matrix.pattern(); + using pattern_t = decltype(pattern); + using index_t = pattern_t::index_type; + using viewspec_t = pattern_t::viewspec_type; + + + if (dash::myid() == 0) { + dash::test::print_pattern_mapping( + "matrix.pattern.unit_at", pattern, 3, + [](const pattern_t & _pattern, int _x, int _y) -> dart_unit_t { + return _pattern.unit_at( + std::array {{ _x, _y }}); + }); + dash::test::print_pattern_mapping( + "matrix.pattern.global_index", pattern, 3, + [](const pattern_t & _pattern, int _x, int _y) -> index_t { + return _x * _pattern.extent(1) + _y; + }); + dash::test::print_pattern_mapping( + "matrix.pattern.local_index", pattern, 3, + [](const pattern_t & _pattern, int _x, int _y) -> index_t { + return _pattern.local_index( + std::array {{ _x, _y }}).index; + }); + + + } + + auto nlblocks = pattern.local_blockspec().size(); + + std::vector local_blocks; + + for (auto b = 0; b < nlblocks; ++b) { + auto block = pattern.local_block(b); + local_blocks.push_back(block); + DASH_LOG_DEBUG("NViewTest.Matrix2DTiledLocalBlocks", + "matrix local_blockspec", + "extents:", block.extents(), + "offsets:", block.offsets(), + "size:", block.size()); + } + + auto const last_block = local_blocks[local_blocks.size() - 1]; + auto const gend_row = (last_block.offset(0) + last_block.extent(0) - 1); + auto const gend_col = (last_block.offset(1) + last_block.extent(1)); + + auto const gbegin_row = local_blocks[0].offset(0); + auto const gbegin_col = local_blocks[0].offset(1); + + auto loc = dash::local(matrix); + + DASH_LOG_DEBUG("NViewTest.Matrix2DTiledLocalBlocks", + "first_block gbegin", gbegin_row * cols + gbegin_col); + DASH_LOG_DEBUG("NViewTest.Matrix2DTiledLocalBlocks", + "last_block gend", gend_row * cols + gend_col); + + DASH_LOG_DEBUG("NViewTest.Matrix2DTiledLocalBlocks", + "local block view", + "extents:", loc.extents(), + "offsets:", loc.offsets(), + "size:", loc.size()); + DASH_LOG_DEBUG("NViewTest.Matrix2DTiledLocalBlocks", + "local block view domain extents:", + dash::domain(loc).extents()); + DASH_LOG_DEBUG("NViewTest.Matrix2DTiledLocalBlocks", + "begin.pos:", loc.begin().pos(), + "end.pos:", loc.end().pos(), + "begin.gpos:", loc.begin().gpos(), + "end.gpos:", loc.end().gpos()); + + + DASH_ASSERT(loc.begin().gpos() == gbegin_row * cols + gbegin_col); + DASH_ASSERT(loc.end().gpos() == gend_row * cols + gend_col); } diff --git a/dash/test/view/ViewTest.cc b/dash/test/view/ViewTest.cc index d43aed6d0..71a22b794 100644 --- a/dash/test/view/ViewTest.cc +++ b/dash/test/view/ViewTest.cc @@ -6,6 +6,8 @@ #include #include +#include + #include #include @@ -539,6 +541,205 @@ TEST_F(ViewTest, ArrayBlockCyclicPatternLocalSub) a.barrier(); } +TEST_F(ViewTest, ArrayCyclicPatternLocalSub) +{ + int elem_per_unit = 7; + int elem_additional = 2; + int array_size = dash::size() * elem_per_unit + + std::min(elem_additional, dash::size()); + int num_local_elem = elem_per_unit + + ( dash::myid() < elem_additional + ? 1 + : 0 ); + + dash::Array a(array_size, dash::CYCLIC); + dash::test::initialize_array(a); + + DASH_LOG_DEBUG("ViewTest.ArrayCyclicPatternLocalSub", + "array:", range_str(a)); + DASH_LOG_DEBUG("ViewTest.ArrayCyclicPatternLocalSub", + "local(array):", range_str(dash::local(a))); + + // sub(local(array)) + // + { + auto s_l_view = dash::sub( + 2, a.lsize() - 2, + dash::local( + a)); + DASH_LOG_DEBUG("ViewTest.ArrayCyclicPatternLocalSub", + range_str(s_l_view)); + DASH_ASSERT( + std::equal(a.lbegin() + 2, + a.lbegin() + a.lsize() - 2, + s_l_view.begin())); + } +} + +TEST_F(ViewTest, ArrayCyclicPatternCopyLocalToGlobal) +{ + int elem_per_unit = 7; + int elem_additional = 2; + int array_size = dash::size() * elem_per_unit + + std::min(elem_additional, dash::size()); + int num_local_elem = elem_per_unit + + ( dash::myid() < elem_additional + ? 1 + : 0 ); + + dash::Array a(array_size, dash::CYCLIC); + dash::test::initialize_array(a); + + dash::Array a_pre(array_size, dash::CYCLIC); + dash::test::initialize_array(a_pre); + + auto copy_num_elem = a.size() / 2; + auto copy_dest_begin_idx = a.size() / 4; + auto copy_dest_end_idx = copy_dest_begin_idx + copy_num_elem; + + DASH_LOG_DEBUG("ViewTest.ArrayCyclicPatternCopyLocalToGlobal", + "array:", range_str(a)); + DASH_LOG_DEBUG("ViewTest.ArrayCyclicPatternCopyLocalToGlobal", + "copy", copy_num_elem, + "[", copy_dest_begin_idx, "...", copy_dest_end_idx, "]"); + + std::vector buf(copy_num_elem); + std::iota(buf.begin(), buf.end(), 0.9999); + + if (dash::myid() == 0) { + auto copy_begin_it = a.begin() + copy_dest_begin_idx; + // copy local buffer to global array + auto copy_end_it = dash::copy( + buf.data(), + buf.data() + copy_num_elem, + copy_begin_it); + EXPECT_EQ_U(copy_end_it, copy_begin_it + copy_num_elem); + } + a.barrier(); + + DASH_LOG_DEBUG("ViewTest.ArrayCyclicPatternCopyLocalToGlobal", + "array:", range_str(a)); + + auto eq_pred = + [](float el_a, + float el_b) { + return static_cast(el_a * 1000000) == + static_cast(el_b * 1000000); + }; + + // Elements in front of copied range: + EXPECT_TRUE_U( + std::equal( + a.begin(), + a.begin() + copy_dest_begin_idx, + a_pre.begin(), + eq_pred)); + // Elements in copied range: + EXPECT_TRUE_U( + std::equal( + a.begin() + copy_dest_begin_idx, + a.begin() + copy_dest_end_idx, + buf.begin(), + eq_pred)); + // Elements after copied range: + EXPECT_TRUE_U( + std::equal( + a.begin() + copy_dest_end_idx, + a.end(), + a_pre.begin() + copy_dest_end_idx, + eq_pred)); +} + +TEST_F(ViewTest, ArrayBlockCyclicPatternCopyLocalToGlobal) +{ + int elem_per_unit = 7; + int elem_additional = 2; + int array_size = dash::size() * elem_per_unit + + std::min(elem_additional, dash::size()); + int num_local_elem = elem_per_unit + + ( dash::myid() < elem_additional + ? 1 + : 0 ); + + dash::Array a(array_size, dash::BLOCKCYCLIC(3)); + dash::test::initialize_array(a); + + dash::Array a_pre(array_size, dash::BLOCKCYCLIC(3)); + dash::test::initialize_array(a_pre); + + auto copy_num_elem = a.size() / 2; + auto copy_dest_begin_idx = a.size() / 4; + auto copy_dest_end_idx = copy_dest_begin_idx + copy_num_elem; + + DASH_LOG_DEBUG("ViewTest.ArrayBlockCyclicPatternCopyLocalToGlobal", + "array:", range_str(a)); + DASH_LOG_DEBUG("ViewTest.ArrayBlockCyclicPatternCopyLocalToGlobal", + "copy", copy_num_elem, + "[", copy_dest_begin_idx, "...", copy_dest_end_idx, "]"); + + std::vector buf(copy_num_elem); + std::iota(buf.begin(), buf.end(), 0.9999); + + a.barrier(); + + if (dash::myid() == 0) { + auto copy_begin_it = a.begin() + copy_dest_begin_idx; + auto copy_end_it_exp = copy_begin_it + copy_num_elem; + auto dest_range = dash::make_range(copy_begin_it, + copy_end_it_exp); + + DASH_LOG_DEBUG_VAR("ViewTest.ArrayBlockCyclicPatternCopyLocalToGlobal", + copy_begin_it); + DASH_LOG_DEBUG_VAR("ViewTest.ArrayBlockCyclicPatternCopyLocalToGlobal", + copy_end_it_exp); + auto dest_blocks = dash::blocks(dest_range); + for (const auto & block : dest_blocks) { + DASH_LOG_DEBUG("ViewTest.ArrayBlockCyclicPatternCopyLocalToGlobal", + "copy dest block:", range_str(block)); + } + + // copy local buffer to global array + auto copy_end_it = dash::copy( + buf.data(), + buf.data() + copy_num_elem, + copy_begin_it); + EXPECT_EQ_U(copy_end_it_exp, copy_end_it); + } + a.barrier(); + + DASH_LOG_DEBUG("ViewTest.ArrayBlockCyclicPatternCopyLocalToGlobal", + "array:", range_str(a)); + + auto eq_pred = + [](float el_a, + float el_b) { + return static_cast(el_a * 1000000) == + static_cast(el_b * 1000000); + }; + + // Elements in front of copied range: + EXPECT_TRUE_U( + std::equal( + a.begin(), + a.begin() + copy_dest_begin_idx, + a_pre.begin(), + eq_pred)); + // Elements in copied range: + EXPECT_TRUE_U( + std::equal( + a.begin() + copy_dest_begin_idx, + a.begin() + copy_dest_end_idx, + buf.begin(), + eq_pred)); + // Elements after copied range: + EXPECT_TRUE_U( + std::equal( + a.begin() + copy_dest_end_idx, + a.end(), + a_pre.begin() + copy_dest_end_idx, + eq_pred)); +} + TEST_F(ViewTest, ArrayBlockCyclicPatternLocalBlocks) { int block_size = 5; @@ -565,7 +766,7 @@ TEST_F(ViewTest, ArrayBlockCyclicPatternLocalBlocks) int l_b_idx; int l_idx; - auto blocks_view = dash::blocks(a); + auto blocks_view = dash::blocks(a); if (dash::myid() == 0) { for (auto block : blocks_view) { DASH_LOG_DEBUG("ViewTest.ArrayBlockCyclicPatternLocalBlocks", "----", @@ -1066,7 +1267,6 @@ TEST_F(ViewTest, LocalBlocksView1Dim) std::vector block_indices(block_index.begin(), block_index.end()); DASH_LOG_DEBUG_VAR("ViewTest.LocalBlocksView1Dim", block_indices); - //DASH_LOG_DEBUG_VAR("ViewTest.LocalBlocksView1Dim", block); std::vector block_values(block.begin(), block.end()); DASH_LOG_DEBUG_VAR("ViewTest.LocalBlocksView1Dim", block_values); diff --git a/dash/test/view/ViewTestBase.h b/dash/test/view/ViewTestBase.h new file mode 100644 index 000000000..837c272cb --- /dev/null +++ b/dash/test/view/ViewTestBase.h @@ -0,0 +1,105 @@ +#ifndef DASH__TEST__VIEW__VIEW_TEST_BASE_H__INCLUDED +#define DASH__TEST__VIEW__VIEW_TEST_BASE_H__INCLUDED + +#include "../TestBase.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace dash { +namespace test { + +template +void initialize_matrix(MatrixT & matrix) { + if (dash::myid() == 0) { + for(size_t i = 0; i < matrix.extent(0); ++i) { + for(size_t k = 0; k < matrix.extent(1); ++k) { + matrix[i][k] = (i + 1) * 0.100 + (k + 1) * 0.001; + } + } + } + matrix.barrier(); + + for(size_t i = 0; i < matrix.local_size(); ++i) { + matrix.lbegin()[i] += dash::myid(); + } + matrix.barrier(); +} + +template +void print_nview( + const std::string & name, + const NViewType & nview) { + using value_t = typename NViewType::value_type; + auto view_nrows = nview.extents()[0]; + auto view_ncols = nview.extents()[1]; + auto nindex = dash::index(nview); + for (int r = 0; r < view_nrows; ++r) { + std::ostringstream row_ss; + for (int c = 0; c < view_ncols; ++c) { + int offset = r * view_ncols + c; + row_ss << std::fixed << std::setw(2) + << nindex[offset] + << ":" + << std::fixed << std::setprecision(3) + << static_cast(nview[offset]) + << " "; + } + DASH_LOG_DEBUG("NViewTest.print_nview", + name, "[", r, "]", row_ss.str()); + } +} + +template +std::vector +region_values(const NViewType & view, const dash::ViewSpec<2> & vs) { + auto nvalues = vs.size(); + using value_t = typename NViewType::value_type; + std::vector values; + values.reserve(nvalues); + dash::CartesianIndexSpace<2> cart(view.extents()); + for (int i = 0; i < nvalues; i++) { + auto coords = cart.coords(i, vs); + auto index = cart.at(coords); + values.push_back(static_cast(view.begin()[index])); + } + return values; +} + +template +bool is_contiguous_ix(const RangeT & rng) { + if (!rng || rng.size() == 1) { return true; } + auto ix_prev = rng.first(); + for (const auto & ix : rng) { + if ((ix != ix_prev+1) && + !(ix == ix_prev && ix == rng.first())) { return false; } + ix_prev = ix; + } + return true; +} + +using dash::sub; +using dash::block; +using dash::blocks; +using dash::local; +using dash::index; +using dash::expand; +using dash::shift; + +class ViewTestBase : public dash::test::TestBase { +protected: +}; + +} // namespace test +} // namespace dash + +#endif // DASH__TEST__VIEW__VIEW_TEST_BASE_H__INCLUDED diff --git a/doc/Views/ViewConcepts.md b/doc/Views/ViewConcepts.md new file mode 100644 index 000000000..0f471fed1 --- /dev/null +++ b/doc/Views/ViewConcepts.md @@ -0,0 +1,51 @@ + +# Range- and View Expressions + +## Cartesian Set Operations + +### `index` + +Maps elements in a view to their index in the view's origin domain. + + +### `sub(ob,oe)` + +Subsection in dimension `D` in offset range `(ob,oe]` with default +dimension `D = 0`. + +In a two-dimensional matrix, for example, `sub(1,3)` selects the second +and third row. + + +### `section(ib,ie)` + +Subsection delimited by n-dimensional indices `(ib,ie]`. + + +### `intersect(r)` + + + + + +## Operations based on Memory Space + +### `local` + + +### `global` + + +### `blocks` + +Group range into domain decomposition blocks. +Elements in single block are not necessarily contiguous. + + +### `chunks` + +Group range into chunks of sequential elements. +Elements in a chunk are contiguous in memory. + + + diff --git a/doc/config/Doxyfile.codedocs b/doc/config/Doxyfile.codedocs index 8b59bd8bf..ab40ddb86 100644 --- a/doc/config/Doxyfile.codedocs +++ b/doc/config/Doxyfile.codedocs @@ -50,7 +50,7 @@ MARKDOWN_SUPPORT = YES DISTRIBUTE_GROUP_DOC = YES SUBGROUPING = YES SOURCE_BROWSER = YES -INLINE_SOURCES = YES +INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES @@ -148,3 +148,4 @@ UML_LOOK = NO TEMPLATE_RELATIONS = NO INTERACTIVE_SVG = NO +USE_MATHJAX = YES diff --git a/doc/config/Doxyfile.in b/doc/config/Doxyfile.in index 589d83817..4d42e34d5 100644 --- a/doc/config/Doxyfile.in +++ b/doc/config/Doxyfile.in @@ -41,7 +41,7 @@ MARKDOWN_SUPPORT = YES DISTRIBUTE_GROUP_DOC = YES SUBGROUPING = YES SOURCE_BROWSER = YES -INLINE_SOURCES = YES +INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES @@ -155,3 +155,4 @@ LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain +USE_MATHJAX = YES