diff --git a/CMakeLists.txt b/CMakeLists.txt index 27d00d528f0..7773c849caa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules/") # Ginkgo configuration options option(GINKGO_DEVEL_TOOLS "Add development tools to the build system" OFF) option(GINKGO_BUILD_TESTS "Generate build files for unit tests" ON) +option(GINKGO_BUILD_EXTENSIONS "Build Ginkgo's extension" ON) option(GINKGO_BUILD_EXAMPLES "Build Ginkgo's examples" ON) option(GINKGO_BUILD_BENCHMARKS "Build Ginkgo's benchmarks" ON) option(GINKGO_BUILD_REFERENCE "Compile reference CPU kernels" ON) @@ -278,6 +279,9 @@ if(GINKGO_BUILD_BENCHMARKS) find_package(gflags 2.2.2 QUIET) find_package(RapidJSON 1.1.0 QUIET) endif() +if(GINKGO_BUILD_EXTENSIONS) + find_package(nlohmann_json 3.11.2 QUIET) +endif() if(GINKGO_BUILD_HWLOC) find_package(HWLOC 2.1) # No need for QUIET as we ship FindHWLOC endif() @@ -335,6 +339,10 @@ if(GINKGO_BUILD_BENCHMARKS) add_subdirectory(benchmark) endif() +if(GINKGO_BUILD_EXTENSIONS) + add_subdirectory(extensions) +endif() + if(GINKGO_DEVEL_TOOLS) add_custom_target(add_license COMMAND ${Ginkgo_SOURCE_DIR}/dev_tools/scripts/add_license.sh diff --git a/dev_tools/scripts/format_header.sh b/dev_tools/scripts/format_header.sh index 2437a03d623..7227e5da0f2 100755 --- a/dev_tools/scripts/format_header.sh +++ b/dev_tools/scripts/format_header.sh @@ -13,6 +13,8 @@ convert_header () { else echo "#include \"${header_file}\"" fi + elif [ -f "extensions/file_config/include/${header_file}" ]; then + echo "#include \"${header_file}\"" elif [ "${header_file}" = "matrices/config.hpp" ]; then echo "#include \"${header_file}\"" elif [[ "${header_file}" =~ ${jacobi_regex} ]]; then @@ -28,8 +30,8 @@ convert_header () { get_header_def () { local regex="\.(hpp|cuh)" if [[ $@ =~ $regex ]]; then - local def=$(echo "$@" | sed -E "s~include/ginkgo/~PUBLIC_~g;s~/|\.~_~g") - # Used to get rid of \r in Windows + local def=$(echo "$@" | sed -E "s~include/ginkgo/~PUBLIC_~g;s~extensions/[^/]*/include/~PUBLIC_EXT_~g;s~/|\.~_~g") + # Used to get rid of \r in Windows def=$(echo "GKO_${def^^}_") echo "$def" else diff --git a/dev_tools/scripts/regroup b/dev_tools/scripts/regroup index 85eade99289..79bf6bd5019 100644 --- a/dev_tools/scripts/regroup +++ b/dev_tools/scripts/regroup @@ -1,6 +1,6 @@ IncludeBlocks: Regroup IncludeCategories: - - Regex: '^<(rapidjson|gflags|gtest|papi).*' + - Regex: '^<(rapidjson|gflags|gtest|papi|nlohmann).*' Priority: 3 - Regex: '^<(omp|cu|hip|thrust|CL/|cooperative|oneapi|mpi|nvToolsExt).*' Priority: 2 diff --git a/extensions/CMakeLists.txt b/extensions/CMakeLists.txt new file mode 100644 index 00000000000..475bf122aae --- /dev/null +++ b/extensions/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(file_config) diff --git a/extensions/file_config/CMakeLists.txt b/extensions/file_config/CMakeLists.txt new file mode 100644 index 00000000000..027af8c24e7 --- /dev/null +++ b/extensions/file_config/CMakeLists.txt @@ -0,0 +1,84 @@ +add_library(file_config "") +add_library(file_config_custom "") + +target_sources(file_config_custom + PRIVATE + "base/executor.cpp" + "matrix/csr.cpp" + "preconditioner/isai.cpp" + "stop/iteration.cpp" + "log/convergence.cpp" + ) + + +target_link_libraries(file_config_custom PUBLIC nlohmann_json::nlohmann_json Ginkgo::ginkgo) +target_include_directories(file_config_custom PUBLIC + $ + $ + ) +target_sources(file_config + PRIVATE + "base/selection.cpp" + ) +target_link_libraries(file_config PUBLIC file_config_custom) + +ginkgo_compile_features(file_config_custom) +ginkgo_compile_features(file_config) + + +function(ginkgo_ext_install_library name export_target) + if (WIN32 OR CYGWIN) + # dll is considered as runtime + install(TARGETS "${name}" + EXPORT "${export_target}" + LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" + ) + else () + # install .so and .a files + install(TARGETS "${name}" + EXPORT "${export_target}" + LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" + ) + endif () +endfunction() + +ginkgo_ext_install_library(file_config_custom GkoFileConfig) +ginkgo_ext_install_library(file_config GkoFileConfig) + +install(DIRECTORY "${Ginkgo_SOURCE_DIR}/extensions/file_config/include/" + DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/extensions/file_config" + FILES_MATCHING PATTERN "*.hpp" + ) +# export targets +export(EXPORT GkoFileConfig + NAMESPACE Ginkgo:: + FILE "${Ginkgo_BINARY_DIR}/extensions/file_config/GkoFileConfigTargets.cmake" + ) + +# export configuration file for importing +write_basic_package_version_file( + "${Ginkgo_BINARY_DIR}/extensions/file_config/GkoFileConfigConfigVersion.cmake" + VERSION "${PROJECT_VERSION}" + COMPATIBILITY SameMajorVersion + ) +configure_package_config_file( + "${Ginkgo_SOURCE_DIR}/extensions/file_config/GkoFileConfigConfig.cmake.in" + "${Ginkgo_BINARY_DIR}/extensions/file_config/GkoFileConfigConfig.cmake" + INSTALL_DESTINATION "${GINKGO_INSTALL_CONFIG_DIR}" + PATH_VARS CMAKE_INSTALL_FULL_INCLUDEDIR CMAKE_INSTALL_FULL_LIBDIR CMAKE_INSTALL_PREFIX GINKGO_INSTALL_MODULE_DIR + ) +install(FILES + "${Ginkgo_BINARY_DIR}/extensions/file_config/GkoFileConfigConfig.cmake" + "${Ginkgo_BINARY_DIR}/extensions/file_config/GkoFileConfigConfigVersion.cmake" + DESTINATION "${GINKGO_INSTALL_CONFIG_DIR}" + ) +install(EXPORT Ginkgo + NAMESPACE Ginkgo:: + FILE GkoFileConfigTargets.cmake + DESTINATION "${GINKGO_INSTALL_CONFIG_DIR}") +if(GINKGO_BUILD_TESTS) + add_subdirectory(test) +endif() diff --git a/extensions/file_config/GkoFileConfigConfig.cmake.in b/extensions/file_config/GkoFileConfigConfig.cmake.in new file mode 100644 index 00000000000..c1d7f98f1f6 --- /dev/null +++ b/extensions/file_config/GkoFileConfigConfig.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +find_package(nlohmann_json 3.11.2 REQUIRED) + +include(${CMAKE_CURRENT_LIST_DIR}/GkoFileConfig.cmake) diff --git a/extensions/file_config/base/executor.cpp b/extensions/file_config/base/executor.cpp new file mode 100644 index 00000000000..408011a89af --- /dev/null +++ b/extensions/file_config/base/executor.cpp @@ -0,0 +1,157 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#include + + +#include +#include + + +#include + + +#include "file_config/base/generic_constructor.hpp" +#include "file_config/base/helper.hpp" +#include "file_config/base/json_helper.hpp" +#include "file_config/base/macro_helper.hpp" +#include "file_config/base/types.hpp" + +namespace gko { +namespace extensions { +namespace file_config { + + +template <> +struct Generic { + using type = std::shared_ptr; + static type build(const nlohmann::json& item, + std::shared_ptr exec, + std::shared_ptr linop, + ResourceManager* manager) + { + std::cout << "Cuda" << std::endl; + auto device_id = get_value_with_default(item, "device_id", 0); + auto ptr = CudaExecutor::create(device_id, ReferenceExecutor::create()); + add_logger(ptr, item, exec, linop, manager); + return std::move(ptr); + } +}; + + +IMPLEMENT_BRIDGE(RM_Executor, CudaExecutor, CudaExecutor); + + +template <> +struct Generic { + using type = std::shared_ptr; + static type build(const nlohmann::json& item, + std::shared_ptr exec, + std::shared_ptr linop, + ResourceManager* manager) + { + std::cout << "Hip" << std::endl; + auto device_id = get_value_with_default(item, "device_id", 0); + auto ptr = HipExecutor::create(device_id, ReferenceExecutor::create()); + add_logger(ptr, item, exec, linop, manager); + return std::move(ptr); + } +}; + + +IMPLEMENT_BRIDGE(RM_Executor, HipExecutor, HipExecutor); + + +template <> +struct Generic { + using type = std::shared_ptr; + static type build(const nlohmann::json& item, + std::shared_ptr exec, + std::shared_ptr linop, + ResourceManager* manager) + { + std::cout << "Dpcpp" << std::endl; + auto device_id = get_value_with_default(item, "device_id", 0); + auto device_type = + get_value_with_default(item, "device_type", std::string("all")); + auto ptr = DpcppExecutor::create(device_id, ReferenceExecutor::create(), + device_type); + add_logger(ptr, item, exec, linop, manager); + return std::move(ptr); + } +}; + + +IMPLEMENT_BRIDGE(RM_Executor, DpcppExecutor, DpcppExecutor); + + +template <> +struct Generic { + using type = std::shared_ptr; + static type build(const nlohmann::json& item, + std::shared_ptr exec, + std::shared_ptr linop, + ResourceManager* manager) + { + std::cout << "Reference" << std::endl; + auto ptr = ReferenceExecutor::create(); + add_logger(ptr, item, exec, linop, manager); + return std::move(ptr); + } +}; + + +IMPLEMENT_BRIDGE(RM_Executor, ReferenceExecutor, ReferenceExecutor); + + +template <> +struct Generic { + using type = std::shared_ptr; + static type build(const nlohmann::json& item, + std::shared_ptr exec, + std::shared_ptr linop, + ResourceManager* manager) + { + std::cout << "Omp" << std::endl; + auto ptr = OmpExecutor::create(); + add_logger(ptr, item, exec, linop, manager); + return std::move(ptr); + } +}; + + +IMPLEMENT_BRIDGE(RM_Executor, OmpExecutor, OmpExecutor); + + +} // namespace file_config +} // namespace extensions +} // namespace gko diff --git a/extensions/file_config/base/selection.cpp b/extensions/file_config/base/selection.cpp new file mode 100644 index 00000000000..a0f78b8f91d --- /dev/null +++ b/extensions/file_config/base/selection.cpp @@ -0,0 +1,34 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +// compile the implementation in the library +#include "file_config/file_config_custom.hpp" diff --git a/extensions/file_config/include/file_config/base/generic_constructor.hpp b/extensions/file_config/include/file_config/base/generic_constructor.hpp new file mode 100644 index 00000000000..4bd544872b2 --- /dev/null +++ b/extensions/file_config/include/file_config/base/generic_constructor.hpp @@ -0,0 +1,260 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#ifndef GKO_PUBLIC_EXT_FILE_CONFIG_BASE_GENERIC_CONSTRUCTOR_HPP_ +#define GKO_PUBLIC_EXT_FILE_CONFIG_BASE_GENERIC_CONSTRUCTOR_HPP_ + + +#include + + +#include + + +#include "file_config/base/macro_helper.hpp" +#include "file_config/base/template_helper.hpp" +#include "file_config/base/types.hpp" + + +namespace gko { +namespace extensions { +namespace file_config { + + +class ResourceManager; + + +/** + * create_from_config is a function to use the base string to select the next + * function. + * + * @tparam T the type + * + * @param item the const nlohmann::json + * @param base the string from the base + * @param exec the Executor from outside + * @param linop the LinOp from outside + * @param manager the ResourceManager pointer + */ +template +std::shared_ptr create_from_config(const nlohmann::json& item, + std::string base, + std::shared_ptr exec, + std::shared_ptr linop, + ResourceManager* manager); + +/** + * DECLARE_SELECTION is to declare a specialization on create_from_config such + * that call the overloading selection function on base type. + * + * @param _base_type the base type + */ +#define DECLARE_SELECTION(_base_type) \ + template <> \ + std::shared_ptr<_base_type> create_from_config<_base_type>( \ + const nlohmann::json& item, std::string base, \ + std::shared_ptr exec, \ + std::shared_ptr linop, ResourceManager* manager) + + +DECLARE_SELECTION(Executor); +DECLARE_SELECTION(LinOp); +DECLARE_SELECTION(LinOpFactory); +DECLARE_SELECTION(CriterionFactory); +DECLARE_SELECTION(Logger); + + +/** + * Generic struct to implement the actual object creation. + * + * @tparam T the type + * @tparam U the helper type. + * + * @note U is T by default, when T is derived from LinOpFactory or + * CriterionFactory (not included the base type), U is the outer type of + * Factory. This can help the template deduction and reduce huge amount of + * manual macro usage for building each template case. + */ +template +struct Generic { + using type = std::shared_ptr; + + /** + * build is the implementation to create the object from the input. + * + * @param item the const nlohmann::json + * @param exec the Executor from outside + * @param linop the LinOp from outside + * @param manager the ResourceManager pointer + */ + static type build(const nlohmann::json& item, + std::shared_ptr exec, + std::shared_ptr linop, + ResourceManager* manager); +}; + +/** + * GENERIC_BASE_IMPL is a implementaion of Generic for base type + * + * @param _base_type the base type + */ +#define GENERIC_BASE_IMPL(_base_type) \ + template <> \ + struct Generic<_base_type> { \ + using type = std::shared_ptr<_base_type>; \ + static type build(const nlohmann::json& item, \ + std::shared_ptr exec, \ + std::shared_ptr linop, \ + ResourceManager* manager) \ + { \ + assert(item.contains("base")); \ + std::cout << "build base" << item.at("base").get() \ + << " " \ + << get_base_class(item.at("base").get()) \ + << std::endl; \ + return create_from_config<_base_type>( \ + item, get_base_class(item.at("base").get()), \ + exec, linop, manager); \ + } \ + } + +GENERIC_BASE_IMPL(Executor); +GENERIC_BASE_IMPL(LinOp); +GENERIC_BASE_IMPL(LinOpFactory); +GENERIC_BASE_IMPL(CriterionFactory); +GENERIC_BASE_IMPL(Logger); + +/** + * GenericHelper is the helper to call Generic build with correct template + * parameters. The default case uses `Generic` + * + * @tparam T the type + */ +template +struct GenericHelper { + using type = std::shared_ptr; + static type build(const nlohmann::json& item, + std::shared_ptr exec, + std::shared_ptr linop, + ResourceManager* manager) + { + return Generic::build(item, exec, linop, manager); + } +}; + +/** + * GenericHelper is the helper to call Generic build with correct template + * parameters. This is the specialization cases for Factory Type (except for + * base type), which uses `Generic` and `T::base_type::Factory` + * must be `T`. + * + * @tparam T the type is derived from LinOpFactory or CriterionFactory but not + * LinOpFactory or CriterionFactory + */ +template +struct GenericHelper< + T, typename std::enable_if::value || + is_on_criterionfactory::value>::type> { + using type = std::shared_ptr; + static type build(const nlohmann::json& item, + std::shared_ptr exec, + std::shared_ptr linop, + ResourceManager* manager) + { + return Generic::build(item, exec, linop, + manager); + } +}; + + +/** + * create_from_config is a free function to build object from input. + * + * @param item the const nlohmann::json + * @param exec the Executor from outside + * @param linop the LinOp from outside + * @param manager the ResourceManager pointer + */ +template +std::shared_ptr create_from_config( + const nlohmann::json& item, std::shared_ptr exec = nullptr, + std::shared_ptr linop = nullptr, + ResourceManager* manager = nullptr) +{ + std::cout << "create_from_config directly to type" << std::endl; + return GenericHelper::build(item, exec, linop, manager); +} + + +/** + * create_from_config is another overloading to implement the function after + * selection on enum map. This is the major implementation to select different + * template type from base class. + * + * @tparam T the enum type + * @tparam base the enum item + * @tparam U the corresponding base type of the enum type + */ +template ::type> +std::shared_ptr create_from_config(const nlohmann::json& item, + std::shared_ptr exec, + std::shared_ptr linop, + ResourceManager* manager); + +// If the template does not contain definition, we do not need to declare +// everything but the "file_config/file_config.hpp" needs to be after user +// implementation ENUM_BRIDGE(ENUM_EXECUTER, DECLARE_BRIDGE_EXECUTOR); +// ENUM_BRIDGE(ENUM_LINOP, DECLARE_BRIDGE_LINOP); + + +#define IMPLEMENT_EMPTY_BRIDGE(_enum_type, _enum_item) \ + template <> \ + inline std::shared_ptr::type> \ + create_from_config<_enum_type, _enum_type::_enum_item, \ + typename gkobase<_enum_type>::type>( \ + const nlohmann::json& item, std::shared_ptr exec, \ + std::shared_ptr linop, ResourceManager* manager) \ + { \ + std::cout << "enter empty" << std::endl; \ + return nullptr; \ + } \ + static_assert(true, \ + "This assert is used to counter the false positive extra " \ + "semi-colon warnings") + + +} // namespace file_config +} // namespace extensions +} // namespace gko + + +#endif // GKO_PUBLIC_EXT_FILE_CONFIG_BASE_GENERIC_CONSTRUCTOR_HPP_ diff --git a/extensions/file_config/include/file_config/base/helper.hpp b/extensions/file_config/include/file_config/base/helper.hpp new file mode 100644 index 00000000000..16e77d85c88 --- /dev/null +++ b/extensions/file_config/include/file_config/base/helper.hpp @@ -0,0 +1,108 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#ifndef GKO_PUBLIC_EXT_FILE_CONFIG_BASE_HELPER_HPP_ +#define GKO_PUBLIC_EXT_FILE_CONFIG_BASE_HELPER_HPP_ + + +#include +#include + + +#include + + +#include "file_config/base/generic_constructor.hpp" +#include "file_config/base/resource_manager.hpp" +#include "file_config/base/types.hpp" + + +namespace gko { +namespace extensions { +namespace file_config { + + +/** + * call is a helper function to decide to use the ResourceManager function or + * the free function depends on the manager is existed or not. + * + * @tparam T the type + * + * @param item the RapidJson::Value + * @param exec the Executor from outside + * @param linop the LinOp from outside + * @param manager the ResourceManager pointer + * + * @note the `build_item` from `ResourceManager` also calls `GenericHelper` free + * function in practice, but `build_item` can store the data if it + * contains name. + */ +template +inline typename std::enable_if::value && + !is_on_criterionfactory::value, + std::shared_ptr>::type +call(const nlohmann::json& item, std::shared_ptr exec, + std::shared_ptr linop, ResourceManager* manager) +{ + if (manager == nullptr) { + return Generic::build(item, exec, linop, manager); + } else { + std::cout << exec.get() << std::endl; + return manager->build_item(item, exec, linop); + } +} + +// In dpcpp, GenericHelper static function does not instantiate the +// corresponding Generic function. We use inline function to instantiate all +// possible template +template +inline typename std::enable_if::value || + is_on_criterionfactory::value, + std::shared_ptr>::type +call(const nlohmann::json& item, std::shared_ptr exec, + std::shared_ptr linop, ResourceManager* manager) +{ + if (manager == nullptr) { + return Generic::build(item, exec, linop, + manager); + } else { + std::cout << exec.get() << std::endl; + return manager->build_item(item, exec, linop); + } +} + + +} // namespace file_config +} // namespace extensions +} // namespace gko + +#endif // GKO_PUBLIC_EXT_FILE_CONFIG_BASE_HELPER_HPP_ diff --git a/extensions/file_config/include/file_config/base/json_helper.hpp b/extensions/file_config/include/file_config/base/json_helper.hpp new file mode 100644 index 00000000000..c25a3184a9a --- /dev/null +++ b/extensions/file_config/include/file_config/base/json_helper.hpp @@ -0,0 +1,416 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#ifndef GKO_PUBLIC_EXT_FILE_CONFIG_BASE_JSON_HELPER_HPP_ +#define GKO_PUBLIC_EXT_FILE_CONFIG_BASE_JSON_HELPER_HPP_ + + +#include +#include + + +#include + + +#include "file_config/base/generic_constructor.hpp" +#include "file_config/base/macro_helper.hpp" +#include "file_config/base/resource_manager.hpp" + + +namespace gko { +namespace extensions { +namespace file_config { + + +template +inline T get_value(const nlohmann::json& item, const char* key) +{ + return item.at(key).get(); +} + +template <> +inline dim<2> get_value>(const nlohmann::json& item, const char* key) +{ + if (item.at(key).is_array()) { + auto array = item.at(key); + if (array.size() == 2) { + return dim<2>(array[0].get(), + array[1].get()); + } else if (array.size() == 1) { + return dim<2>(array[0].get(), + array[0].get()); + } else { + assert(false); + // avoid the warning about return type + return dim<2>(); + } + } else if (item.at(key).is_number()) { + return dim<2>(item.at(key).get(), + item.at(key).get()); + } else { + assert(false); + // avoid the warning about return type + return dim<2>(); + } +} + + +template +inline T get_value_with_default(const nlohmann::json& item, const char* key, + T default_value) +{ + if (item.contains(key)) { + return get_value(item, key); + } else { + return default_value; + } +} + + +template +T get_required_value(const nlohmann::json& item, const char* key) +{ + if (!item.contains(key)) { + std::cerr << "the value of key " << key << " must not be empty" + << std::endl; + assert(false); + return T{}; + } else { + return get_value(item, key); + } +} + + +// It can not use the overload get_value because mask_type is uint. +inline gko::log::Logger::mask_type get_mask_value_with_default( + const nlohmann::json& item, std::string key, + gko::log::Logger::mask_type default_val) +{ + // clang-format off +#define GKORM_LOGGER_EVENT(_event_mask) \ + {#_event_mask, gko::log::Logger::_event_mask} + // clang-format on + + // Note: before using the following command, clang ColumnLimit should use + // 160 or large enough value. Otherwise, some like criterion_check_completed + // will not be caught, so need to manually add them. + // clang-format off + // For single: + // grep -E 'GKO_LOGGER_REGISTER_EVENT\([0-9]+, [^,]*,' include/ginkgo/core/log/logger.hpp | sed -E 's/.*GKO_LOGGER_REGISTER_EVENT\([0-9]+, ([^,]*),.*/GKORM_LOGGER_EVENT(\1_mask),/g' + // For combine: + // grep -E 'mask_type +[^ ]*_mask +=' include/ginkgo/core/log/logger.hpp | sed -E 's/.*mask_type +([^ ]*_mask).*/GKORM_LOGGER_EVENT(\1),/g' + // clang-format on + static std::unordered_map + mask_type_map{ + GKORM_LOGGER_EVENT(allocation_started_mask), + GKORM_LOGGER_EVENT(allocation_completed_mask), + GKORM_LOGGER_EVENT(free_started_mask), + GKORM_LOGGER_EVENT(free_completed_mask), + GKORM_LOGGER_EVENT(copy_started_mask), + GKORM_LOGGER_EVENT(copy_completed_mask), + GKORM_LOGGER_EVENT(operation_launched_mask), + GKORM_LOGGER_EVENT(operation_completed_mask), + GKORM_LOGGER_EVENT(polymorphic_object_create_started_mask), + GKORM_LOGGER_EVENT(polymorphic_object_create_completed_mask), + GKORM_LOGGER_EVENT(polymorphic_object_copy_started_mask), + GKORM_LOGGER_EVENT(polymorphic_object_copy_completed_mask), + GKORM_LOGGER_EVENT(polymorphic_object_deleted_mask), + GKORM_LOGGER_EVENT(linop_apply_started_mask), + GKORM_LOGGER_EVENT(linop_apply_completed_mask), + GKORM_LOGGER_EVENT(linop_advanced_apply_started_mask), + GKORM_LOGGER_EVENT(linop_advanced_apply_completed_mask), + GKORM_LOGGER_EVENT(linop_factory_generate_started_mask), + GKORM_LOGGER_EVENT(linop_factory_generate_completed_mask), + GKORM_LOGGER_EVENT(criterion_check_started_mask), + GKORM_LOGGER_EVENT(criterion_check_completed_mask), + GKORM_LOGGER_EVENT(iteration_complete_mask), + GKORM_LOGGER_EVENT(polymorphic_object_move_started_mask), + GKORM_LOGGER_EVENT(polymorphic_object_move_completed_mask), + GKORM_LOGGER_EVENT(all_events_mask), + GKORM_LOGGER_EVENT(executor_events_mask), + GKORM_LOGGER_EVENT(operation_events_mask), + GKORM_LOGGER_EVENT(polymorphic_object_events_mask), + GKORM_LOGGER_EVENT(linop_events_mask), + GKORM_LOGGER_EVENT(linop_factory_events_mask), + GKORM_LOGGER_EVENT(criterion_events_mask)}; + + + gko::log::Logger::mask_type mask_value = 0; + if (item.contains(key)) { + auto& mask_item = item.at(key); + if (mask_item.is_string()) { + mask_value |= mask_type_map.at(mask_item.get()); + } else if (mask_item.is_array()) { + for (auto& it : mask_item) { + mask_value |= mask_type_map.at(it.get()); + } + } else { + assert(false); + } + } else { + mask_value = default_val; + } + + return mask_value; +} + + +/** + * get_pointer gives the shared_ptr from inputs. + * + * @tparam T the type + * + * @param item the RapidJson::Value + * @param exec the Executor from outside + * @param linop the LinOp from outside + * @param manager the ResourceManager pointer + * + * @return std::shared_ptr + */ +template +inline std::shared_ptr get_pointer(const nlohmann::json& item, + std::shared_ptr exec, + std::shared_ptr linop, + ResourceManager* manager) +{ + std::shared_ptr ptr; + using T_non_const = std::remove_const_t; + if (manager == nullptr) { + if (item.is_object()) { + ptr = GenericHelper::build(item, exec, linop, manager); + } else { + assert(false); + } + } else { + if (item.is_string()) { + std::cout << "search item" << std::endl; + std::string opt = item.get(); + ptr = manager->search_data(opt); + std::cout << "get ptr " << ptr.get() << std::endl; + } else if (item.is_object()) { + ptr = manager->build_item(item, exec, linop); + } else { + assert(false); + } + } + assert(ptr.get() != nullptr); + return std::move(ptr); +} + +template <> +inline std::shared_ptr get_pointer( + const nlohmann::json& item, std::shared_ptr exec, + std::shared_ptr linop, ResourceManager* manager) +{ + std::shared_ptr ptr; + if (manager == nullptr) { + if (item.is_object()) { + ptr = GenericHelper::build(item, exec, linop, manager); + } else if (item.is_string() && + item.get() == std::string("inherit")) { + ptr = exec; + } else { + assert(false); + } + } else { + // assert(false); + // TODO: manager + if (item.is_string()) { + std::string opt = item.get(); + if (opt == std::string("inherit")) { + ptr = exec; + } else { + ptr = manager->search_data(opt); + } + } else if (item.is_object()) { + ptr = manager->build_item(item); + } else { + assert(false); + } + } + assert(ptr.get() != nullptr); + return std::move(ptr); +} + +template <> +inline std::shared_ptr get_pointer( + const nlohmann::json& item, std::shared_ptr exec, + std::shared_ptr linop, ResourceManager* manager) +{ + std::shared_ptr ptr; + if (manager == nullptr) { + if (item.is_object()) { + ptr = GenericHelper::build(item, exec, linop, manager); + } else if (item.is_string() && + item.get() == std::string("given")) { + ptr = linop; + } else { + assert(false); + } + } else { + if (item.is_string()) { + std::string opt = item.get(); + if (opt == std::string("given")) { + ptr = linop; + } else { + ptr = manager->search_data(opt); + } + } else if (item.is_object()) { + ptr = manager->build_item(item); + } else { + assert(false); + } + } + assert(ptr.get() != nullptr); + return std::move(ptr); +} + + +/** + * get_pointer_check considers existence of the key to decide the behavior. + * + * @tparam T the type + * + * @param item the RapidJson::Value + * @param key the key string + * @param exec the Executor from outside + * @param linop the LinOp from outside + * @param manager the ResourceManager pointer + * + * @return std::shared_ptr + */ +template +inline std::shared_ptr get_pointer_check( + const nlohmann::json& item, std::string key, + std::shared_ptr exec, + std::shared_ptr linop, ResourceManager* manager) +{ + assert(item.contains(key)); + return get_pointer(item.at(key), exec, linop, manager); +} + +template <> +inline std::shared_ptr get_pointer_check( + const nlohmann::json& item, std::string key, + std::shared_ptr exec, + std::shared_ptr linop, ResourceManager* manager) +{ + if (item.contains(key)) { + return get_pointer(item.at(key), exec, linop, manager); + } else if (exec != nullptr) { + return exec; + } else { + assert(false); + return nullptr; + } +} + + +template +inline void add_logger(Type& obj, const nlohmann::json& item, + std::shared_ptr exec, + std::shared_ptr linop, + ResourceManager* manager) +{ + if (item.contains("add_loggers")) { + auto& logger = item.at("add_loggers"); + if (logger.is_array()) { + for (auto& it : logger) { + obj->add_logger(get_pointer(it, exec, linop, manager)); + } + } else { + obj->add_logger(get_pointer(logger, exec, linop, manager)); + } + } +} + + +template +inline std::shared_ptr get_csr_strategy( + const std::string& strategy, std::shared_ptr exec_ptr) +{ + std::shared_ptr strategy_ptr; + if (strategy == std::string("sparselib") || + strategy == std::string("cusparse")) { + strategy_ptr = std::make_shared(); + } else if (strategy == std::string("automatical")) { + if (auto explicit_exec = + std::dynamic_pointer_cast(exec_ptr)) { + strategy_ptr = + std::make_shared(explicit_exec); + } else if (auto explicit_exec = + std::dynamic_pointer_cast( + exec_ptr)) { + strategy_ptr = + std::make_shared(explicit_exec); + } else if (auto explicit_exec = + std::dynamic_pointer_cast( + exec_ptr)) { + strategy_ptr = + std::make_shared(explicit_exec); + } else { + // fallback to classical + strategy_ptr = std::make_shared(); + } + } else if (strategy == std::string("load_balance")) { + if (auto explicit_exec = + std::dynamic_pointer_cast(exec_ptr)) { + strategy_ptr = + std::make_shared(explicit_exec); + } else if (auto explicit_exec = + std::dynamic_pointer_cast( + exec_ptr)) { + strategy_ptr = + std::make_shared(explicit_exec); + } else if (auto explicit_exec = + std::dynamic_pointer_cast( + exec_ptr)) { + strategy_ptr = + std::make_shared(explicit_exec); + } else { + // fallback to classical + strategy_ptr = std::make_shared(); + } + + } else if (strategy == std::string("merge_path")) { + strategy_ptr = std::make_shared(); + } else if (strategy == std::string("classical")) { + strategy_ptr = std::make_shared(); + } + return std::move(strategy_ptr); +} + + +} // namespace file_config +} // namespace extensions +} // namespace gko +#endif // GKO_PUBLIC_EXT_FILE_CONFIG_BASE_JSON_HELPER_HPP_ diff --git a/extensions/file_config/include/file_config/base/macro_helper.hpp b/extensions/file_config/include/file_config/base/macro_helper.hpp new file mode 100644 index 00000000000..fe4bf170b17 --- /dev/null +++ b/extensions/file_config/include/file_config/base/macro_helper.hpp @@ -0,0 +1,248 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#ifndef GKO_PUBLIC_EXT_FILE_CONFIG_BASE_MACRO_HELPER_HPP_ +#define GKO_PUBLIC_EXT_FILE_CONFIG_BASE_MACRO_HELPER_HPP_ + + +// MSVC tends to use __VA_ARGS__ as one item +// To expand __VA_ARGS__ as other compilers, another workaround is to use the +// `/Zc:preprocessor` or `/experimental:preprocessor` +#define UNPACK_VA_ARGS(_x) _x + +/** + * MACRO_OVERLOAD_ is a macro helper to overload two possible macros. + */ +#define MACRO_OVERLOAD_(_1, _2, _NAME, ...) _NAME + +/** + * ENUM_VALUE_ is a macro for enum to define the name only + * + * @param _name the name of enum item + */ +#define ENUM_VALUE_(_name) _name + +/** + * ENUM_VALUE_ASSIGN_ is a macro for enum to define the name and the assigned + * value + * + * @param _name the name of enum item + * @param _assign the assigned value of enum item + */ +#define ENUM_VALUE_ASSIGN_(_name, _assign) _name = _assign + +/** + * ENUM_VALUE is a macro for enum with overloading. It can be used as + * ENUM_VALUE(name) or ENUM_VALUE(name, assign). + * + * @param _name the name of enum item + * @param _assign (optional) the assigned value of enum item + */ +#define ENUM_VALUE(...) \ + UNPACK_VA_ARGS(MACRO_OVERLOAD_(__VA_ARGS__, ENUM_VALUE_ASSIGN_, \ + ENUM_VALUE_, UNUSED)(__VA_ARGS__)) + +// Avoid , to be preprocessed first +#define COMMA_() , +#define EMPTY() +#define POSTPONE(_sep) _sep EMPTY() +#define COMMA POSTPONE(COMMA_)() +/** + * ENUM_CLASS is a macro to generate the actual enum class. + * + * @param _enum_type the name of enum class type + * @param _type the base type of enum + * @param _list the list of enum items, which is built by ENUM_VALUE. + */ +#define ENUM_CLASS(_enum_type, _type, _list) \ + enum class _enum_type : _type { _list(ENUM_VALUE, COMMA) } + + +/** + * ENUM_LAMBDA_ is a macro to generate the item of enum map, which + * calls the predefined function create_from_config + * + * @param _name the name of enum item + */ +// clang-format off +#define ENUM_LAMBDA_(_name) \ + { \ + #_name, \ + [&](const nlohmann::json&item, std::shared_ptr exec, \ + std::shared_ptr linop, \ + ResourceManager *manager) { \ + std::cout << #_name << std::endl; \ + return create_from_config( \ + item, exec, linop, manager); \ + } \ + } +// clang-format on + +/** + * ENUM_LAMBDA_ASSIGN_ is a macro to accept the enum item with assigned value. + * It will forward the name to ENUM_LAMBDA_. + * + * @param _name the name of enum item + * @param _assign (not used) the assigned value of enum item + */ +#define ENUM_LAMBDA_ASSIGN_(_name, _assign) ENUM_LAMBDA_(_name) + +/** + * ENUM_LAMBDA is a macro to generate the item of enum map with overloading. It + * can be used as ENUM_LAMBDA(name) or ENUM_LAMBDA(name, assign). + * + * @param _name the name of enum item + * @param _assign (optional, not used) the assigned value of enum item + */ +#define ENUM_LAMBDA(...) \ + UNPACK_VA_ARGS(MACRO_OVERLOAD_(__VA_ARGS__, ENUM_LAMBDA_ASSIGN_, \ + ENUM_LAMBDA_, UNUSED)(__VA_ARGS__)) + +/** + * ENUM_MAP is a macro to generate the actual enum map, which uses ENUM_LAMBDA + * to build each item. + * + * @param _name the name of map + * @param _enum_type the name of enum class type + * @param _return_type the return type of functions in the map + * @param _list the list of enum items, which is built by ENUM_VALUE + * @param _keyword the keyword before map declaration + * + * @note it uses enum_type_alias to make ENUM_LAMBDA use correct enum_type. + */ +#define ENUM_MAP(_name, _enum_type, _return_type, _list, _keyword) \ + using enum_type_alias = _enum_type; \ + _keyword \ + std::map, \ + std::shared_ptr, ResourceManager*)>> \ + _name \ + { \ + _list(ENUM_LAMBDA, COMMA) \ + } + +/** + * IMPLEMENT_SELECTION is a macro helper to implement selection from + * DECLARE_SELECTION. If find a match, use the matched function call, or return + * nullptr. + * + * @param _base_type the base type + * @param _enum_type the corresponding enum type + * @param _list the list of enum items, which is built by ENUM_VALUE + */ +#define IMPLEMENT_SELECTION(_base_type, _enum_type, _list) \ + template <> \ + std::shared_ptr<_base_type> create_from_config<_base_type>( \ + const nlohmann::json& item, std::string base, \ + std::shared_ptr exec, \ + std::shared_ptr linop, ResourceManager* manager) \ + { \ + std::cout << "search on enum " << base << std::endl; \ + ENUM_MAP(_base_type##Select, _enum_type, std::shared_ptr<_base_type>, \ + _list, static); \ + auto it = _base_type##Select.find(base); \ + if (it == _base_type##Select.end()) { \ + std::cout << "Not Found" << std::endl; \ + return nullptr; \ + } else { \ + std::cout << "Found!" << std::endl; \ + return it->second(item, exec, linop, manager); \ + } \ + } \ + static_assert(true, \ + "This assert is used to counter the false positive extra " \ + "semi-colon warnings") + +/** + * IMPLEMENT_BRIDGE is a macro helper to implement bridge between + * `create_from_config<_enum_type, _enum_item>` to `call<_impl_type>`. It can be + * used when the `_impl_type` does not need furthermore selection such as + * ValueType or something else. + * + * @param _enum_type the enum type + * @param _enum_item the enum item of `_enum_type` + * @param _impl_type the implementation type, which is used in + * `call<_impl_type>(...)` + */ +#define IMPLEMENT_BRIDGE(_enum_type, _enum_item, _impl_type) \ + template <> \ + std::shared_ptr::type> \ + create_from_config<_enum_type, _enum_type::_enum_item, \ + typename gkobase<_enum_type>::type>( \ + const nlohmann::json& item, std::shared_ptr exec, \ + std::shared_ptr linop, ResourceManager* manager) \ + { \ + std::cout << "enter bridge" << std::endl; \ + return call<_impl_type>(item, exec, linop, manager); \ + } \ + static_assert(true, \ + "This assert is used to counter the false positive extra " \ + "semi-colon warnings") + + +#define DECLARE_BRIDGE_EXECUTOR_(_enum_item) \ + template <> \ + std::shared_ptr::type> \ + create_from_config::type>( \ + const nlohmann::json& item, std::shared_ptr exec, \ + std::shared_ptr linop, ResourceManager* manager) + +#define DECLARE_BRIDGE_EXECUTOR_ASSIGN_(_name, _assign) \ + DECLARE_BRIDGE_EXECUTOR_(_name) + +/** + * ENUM_LAMBDA is a macro to generate the item of enum map with overloading. It + * can be used as ENUM_LAMBDA(name) or ENUM_LAMBDA(name, assign). + * + * @param _name the name of enum item + * @param _assign (optional, not used) the assigned value of enum item + */ +#define DECLARE_BRIDGE_EXECUTOR(...) \ + UNPACK_VA_ARGS( \ + MACRO_OVERLOAD_(__VA_ARGS__, DECLARE_BRIDGE_EXECUTOR_ASSIGN_, \ + DECLARE_BRIDGE_EXECUTOR_, UNUSED)(__VA_ARGS__)) + +#define DECLARE_BRIDGE_LINOP(_enum_item) \ + template <> \ + std::shared_ptr::type> create_from_config< \ + RM_LinOp, RM_LinOp::_enum_item, typename gkobase::type>( \ + const nlohmann::json& item, std::shared_ptr exec, \ + std::shared_ptr linop, ResourceManager* manager) + + +#define ENUM_BRIDGE(_list, _declare) _list(_declare, ;) + + +#endif // GKO_PUBLIC_EXT_FILE_CONFIG_BASE_MACRO_HELPER_HPP_ diff --git a/extensions/file_config/include/file_config/base/macro_impl_helper.hpp b/extensions/file_config/include/file_config/base/macro_impl_helper.hpp new file mode 100644 index 00000000000..fe495796f7b --- /dev/null +++ b/extensions/file_config/include/file_config/base/macro_impl_helper.hpp @@ -0,0 +1,288 @@ +/************************************************************* +Copyright (c) 2017-2023, the Ginkgo authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*************************************************************/ + +#ifndef GKO_PUBLIC_EXT_FILE_CONFIG_BASE_MACRO_IMPL_HELPER_HPP_ +#define GKO_PUBLIC_EXT_FILE_CONFIG_BASE_MACRO_IMPL_HELPER_HPP_ + + +/** + * PACK is to pack several args for one parameter + */ +#define PACK(...) __VA_ARGS__ + + +/** + * BUILD_FACTORY is to implement the beginning of setting factory. It sets the + * several alias to following usage and get the executor, which can be used the + * subitem. + * + * @param _type the outer type of factory + * @param _manager the outside parameter name of ResourceManager + * @param _item the outside parameter name of RapidJson Value& + * @param _linop the outside parameter name of LinOp + * @param _exec the outside parameter name of Executor + * + * @note This should be in a lambda function. It generates `factory_alias_` from + * `_type` factory, `exec_alias` from `_exec` and `_item` and alias name + * `*_alias_` from `_manager`, `_item`, `_linop`. + */ +#define BUILD_FACTORY(_type, _manager, _item, _exec, _linop) \ + auto factory_alias_ = _type::build(); \ + auto& manager_alias_ = _manager; \ + auto& item_alias_ = _item; \ + auto& linop_alias_ = _linop; \ + auto exec_alias_ = get_pointer_check(_item, "exec", _exec, \ + _linop, _manager) + +/** + * SET_POINTER is to set one pointer for the factory. It is for the + * `std::shared_ptr GKO_FACTORY_PARAMETER_SCALAR(name, initial)`. It only + * sets the pointer when the RapidJson contain the value. The corresponding call + * should be `SET_POINTER(type, name);` + * + * @note This should be used in the of a lambda function. + */ +#define SET_POINTER(_param_type, _param_name) \ + if (item_alias_.contains(#_param_name)) { \ + factory_alias_.with_##_param_name( \ + get_pointer<_param_type>(item_alias_[#_param_name], exec_alias_, \ + linop_alias_, manager_alias_)); \ + } \ + static_assert(true, \ + "This assert is used to counter the false positive extra " \ + "semi-colon warnings") + + +/** + * SET_POINTER_VECTOR is to set pointer array for the factory. It is for the + * `std::vector> GKO_FACTORY_PARAMETER_VECTOR(name, + * initial)`. It only sets the pointer array when the RapidJson contain the + * value. The corresponding call should be `SET_POINTER_VECTOR(type, name);` + * + * @note This should be used in the of a lambda function. + */ +#define SET_POINTER_VECTOR(_param_type, _param_name) \ + if (item_alias_.contains(#_param_name)) { \ + std::cout << "pointer_vector executor " << exec_alias_.get() \ + << std::endl; \ + factory_alias_.with_##_param_name(get_pointer_vector<_param_type>( \ + item_alias_[#_param_name], exec_alias_, linop_alias_, \ + manager_alias_)); \ + } \ + static_assert(true, \ + "This assert is used to counter the false positive extra " \ + "semi-colon warnings") + + +/** + * SET_VALUE is to set one value for the factory. It is for the + * `type GKO_FACTORY_PARAMETER_SCALAR(name, initial)`. It only + * sets the value when the RapidJson contain the value. The corresponding call + * should be `SET_VALUE(type, name);` + * + * @note This should be used in the of a lambda function. + */ +#define SET_VALUE(_param_type, _param_name) \ + if (item_alias_.contains(#_param_name)) { \ + std::string name{#_param_name}; \ + factory_alias_.with_##_param_name( \ + get_value<_param_type>(item_alias_, #_param_name)); \ + } \ + static_assert(true, \ + "This assert is used to counter the false positive extra " \ + "semi-colon warnings") + +#define SET_ARRAY(_param_type, _param_name) \ + if (item_alias_.contains(#_param_name)) { \ + std::string name{#_param_name}; \ + factory_alias_.with_##_param_name( \ + get_array<_param_type>(item_alias_, #_param_name, exec_alias_)); \ + } \ + static_assert(true, \ + "This assert is used to counter the false positive extra " \ + "semi-colon warnings") + + +#define SET_FUNCTION(_param_type, _param_name) \ + if (item_alias_.contains(#_param_name)) { \ + std::string name{#_param_name}; \ + factory_alias_.with_##_param_name( \ + _param_name##_map[get_value(item_alias_, \ + #_param_name)]); \ + } \ + static_assert(true, \ + "This assert is used to counter the false positive extra " \ + "semi-colon warnings") + +#define SET_CSR_STRATEGY(_param_type, _param_name) \ + if (item_alias_.contains(#_param_name)) { \ + std::string name{#_param_name}; \ + factory_alias_.with_##_param_name(get_csr_strategy<_param_type>( \ + get_value(item_alias_, #_param_name), exec_alias_)); \ + } \ + static_assert(true, \ + "This assert is used to counter the false positive extra " \ + "semi-colon warnings") + + +/** + * SET_EXECUTOR is to set the executor of factory and return the factory type + * from this operation. + * + * @note This should be used in the end of a lambda function. + */ +#define SET_EXECUTOR return factory_alias_.on(exec_alias_) + +/** + * SIMPLE_LINOP_FACTORY_IMPL is a implementation for those LinOp, taking the + * factory and generating the LinOp with matrix. + * + * @param _base the LinOp type base without the template parameter + * @param _template the template parameter for LinOp type base + * @param _type the template type usage from `_template` + * + * @note Use PACK to pack more than one args for `_template` and `_type`. + */ +#define SIMPLE_LINOP_WITH_FACTORY_IMPL(_base, _template, _type) \ + template <_template> \ + struct Generic<_base<_type>> { \ + using type = std::shared_ptr<_base<_type>>; \ + static type build(const nlohmann::json& item, \ + std::shared_ptr exec, \ + std::shared_ptr linop, \ + ResourceManager* manager) \ + { \ + std::cout << #_base << exec.get() << std::endl; \ + auto factory = get_pointer::Factory>( \ + item["factory"], exec, linop, manager); \ + auto mtx = get_pointer(item["generate"], exec, linop, \ + manager); \ + auto ptr = factory->generate(mtx); \ + add_logger(ptr, item, exec, linop, manager); \ + return std::move(ptr); \ + } \ + } + +#define SIMPLE_LINOP_WITH_FACTORY_IMPL_BASE(_base) \ + template <> \ + struct Generic<_base> { \ + using type = std::shared_ptr<_base>; \ + static type build(const nlohmann::json& item, \ + std::shared_ptr exec, \ + std::shared_ptr linop, \ + ResourceManager* manager) \ + { \ + std::cout << #_base << exec.get() << std::endl; \ + auto factory = get_pointer( \ + item["factory"], exec, linop, manager); \ + auto mtx = get_pointer(item["generate"], exec, linop, \ + manager); \ + auto ptr = factory->generate(mtx); \ + return std::move(ptr); \ + } \ + } + + +/** + * ENABLE_SELECTION is to build a template selection on the given tt_list. It + * will take each item (single type or type_list) of tt_list and the + * corresponding identifier string. If the string is accepted by the Predicate, + * it will launch the function with the accepted type. + * + * @param _name the selection function name + * @param _callable the function to launch + * @param _return the return type of the function (pointer) + * @param _get_type the method to get the type (get_actual_type or + * get_actual_factory_type) + */ +#define ENABLE_SELECTION(_name, _callable, _return, _get_type) \ + template